Skip to content

从 TypeScript 到 Targo

欢迎 TypeScript 开发者!本指南帮助你快速理解 Targo 与 TypeScript 的异同。

核心理念

Targo 使用 TypeScript 语法,但具有 Go 语义。可以理解为:

Targo = TypeScript 语法 + Go 类型系统 + Go 运行时

这意味着:

  • ✅ 你熟悉的语法:letconst、箭头函数、解构等
  • ⚠️ 不同的类型系统:明确的数值类型、值/引用语义
  • ❌ 没有 JavaScript 运行时:没有 Promiseasync/await、DOM API

快速对比

特性TypeScriptTargo
数值类型numberint, float64, int32
数组Array<T>T[]slice<T>
对象{}classinterface
异步Promise, async/awaitchan, go()
错误处理try/catch多返回值 [result, error]
类继承extends组合(Embedding)
Nullnullundefined只有 null

类型系统差异

1. 数值类型

TypeScript 只有一个 number 类型,Targo 需要明确指定:

typescript
// ❌ TypeScript(在 Targo 中不工作)
let count: number = 42;
let price: number = 19.99;

// ✅ Targo(必须明确类型)
let count: int = 42;
let price: float64 = 19.99;
let age: int8 = 25;
let port: uint16 = 8080;

常用数值类型

  • 整数:int, int8, int16, int32, int64
  • 无符号:uint, uint8, uint16, uint32, uint64
  • 浮点:float32, float64
  • 大整数:bigint

选择建议

  • 默认使用 intfloat64
  • 需要节省内存时使用 int8int16
  • 处理二进制数据时使用 uint8byte

2. 数组和集合

TypeScript 的 Array 变成 Targo 的 slice

typescript
// ❌ TypeScript
let items: Array<string> = ["a", "b", "c"];
let nums: number[] = [1, 2, 3];

// ✅ Targo
let items: slice<string> = ["a", "b", "c"];
let nums: slice<int> = [1, 2, 3];

// 如果需要 JS 风格的方法(push, map, filter)
let arr: Array<int> = [1, 2, 3];
arr.push(4);
let doubled = arr.map(x => x * 2);

集合类型对比

TypeScriptTargo说明
Array<T>slice<T>动态数组
Map<K,V>map<K,V>键值映射
Set<T>使用 map<T, bool> 代替
-chan<T>通道(并发通信)
-Fixed<T, N>固定大小数组

3. Null 和 Undefined

Targo 只有 null(映射到 Go 的 nil):

typescript
// ❌ TypeScript
let x: string | undefined = undefined;
let y: string | null = null;

// ✅ Targo(只有 null)
let x: string | null = null;

// 可选字段使用 ?
class Config {
    host: string;
    port?: int;  // 等价于 port: int | null
}

4. 布尔条件

Targo 没有 truthy/falsy 值,条件必须是 bool 类型:

typescript
// ❌ TypeScript(在 Targo 中不工作)
if (x) { }              // x 必须是 bool
if (arr.length) { }     // length 是 int,不是 bool
if (str) { }            // str 是 string,不是 bool

// ✅ Targo(显式比较)
if (x != null) { }
if (arr.length > 0) { }
if (str != "") { }

异步编程

Promise → Channel

TypeScript 使用 Promiseasync/await,Targo 使用 chango()

typescript
// ❌ TypeScript
async function fetchData(url: string): Promise<string> {
    const response = await fetch(url);
    return response.text();
}

// 使用
const data = await fetchData("https://api.example.com");

// ✅ Targo
import { Get } from "net/http";
import { ReadAll } from "io";

function fetchData(url: string): chan<string> {
    let ch = chan.make<string>();
    
    go(() => {
        let [resp, err] = Get(url);
        if (err != null) {
            ch.close();
            return;
        }
        
        let [body, err2] = ReadAll(resp.Body);
        resp.Body.Close();
        
        if (err2 != null) {
            ch.close();
            return;
        }
        
        ch.send(string(body));
        ch.close();
    });
    
    return ch;
}

// 使用
let ch = fetchData("https://api.example.com");
let data = ch.receive();

并发模式对比

typescript
// TypeScript - Promise.all
const [user, posts, comments] = await Promise.all([
    fetchUser(id),
    fetchPosts(id),
    fetchComments(id)
]);

// Targo - 使用 goroutine 和 channel
let userCh = chan.make<User>();
let postsCh = chan.make<slice<Post>>();
let commentsCh = chan.make<slice<Comment>>();

go(() => { userCh.send(fetchUser(id)); });
go(() => { postsCh.send(fetchPosts(id)); });
go(() => { commentsCh.send(fetchComments(id)); });

let user = userCh.receive();
let posts = postsCh.receive();
let comments = commentsCh.receive();

类和接口

Class 是结构体

Targo 的 class 编译为 Go 结构体,不是 JavaScript 类:

typescript
// Targo
class Person {
    name: string;
    age: int;
    
    greet(): string {
        return `Hello, ${this.name}`;
    }
}

// 创建实例(使用工厂函数)
function NewPerson(name: string, age: int): Person {
    return { name, age } as Person;
}

let p = NewPerson("Alice", 30);
console.log(p.greet());

关键差异

  • ❌ 没有 constructor,使用工厂函数
  • ❌ 没有 extends(继承),使用组合
  • ❌ 没有 private/protected 关键字
  • ✅ 使用 #field 表示私有字段

组合代替继承

typescript
// ❌ TypeScript 继承
class Animal {
    name: string;
    speak(): void {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Animal {
    bark(): void {
        console.log("Woof!");
    }
}

// ✅ Targo 组合
class Animal {
    name: string;
    
    speak(): void {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Embedding({ animal: {} as Animal }) {
    bark(): void {
        console.log("Woof!");
    }
}

// 使用
let dog = new Dog();
dog.animal.name = "Buddy";
dog.animal.speak();  // 访问嵌入字段的方法
dog.bark();

接口

接口工作方式类似,但具有 Go 的隐式实现:

typescript
// 定义接口
interface Writer {
    write(data: slice<byte>): [int, error | null];
}

// 隐式实现(不需要 implements 关键字)
class FileWriter {
    write(data: slice<byte>): [int, error | null] {
        // 实现
        return [data.len(), null];
    }
}

// FileWriter 自动实现 Writer 接口
let w: Writer = new FileWriter();

错误处理

Try/Catch → 多返回值

Targo 没有异常,使用多返回值处理错误:

typescript
// ❌ TypeScript
try {
    const result = riskyOperation();
    console.log(result);
} catch (error) {
    console.error("Error:", error);
}

// ✅ Targo
import { New } from "errors";

function riskyOperation(): [int, error | null] {
    // 模拟可能失败的操作
    if (Math.random() > 0.5) {
        return [0, New("operation failed")];
    }
    return [42, null];
}

// 使用
let [result, err] = riskyOperation();
if (err != null) {
    console.error("Error:", err);
    return;
}
console.log(result);

错误处理模式

typescript
// 模式 1:立即返回错误
function processFile(path: string): error | null {
    let [data, err] = readFile(path);
    if (err != null) {
        return err;  // 传播错误
    }
    
    let [result, err2] = parseData(data);
    if (err2 != null) {
        return err2;
    }
    
    return null;
}

// 模式 2:包装错误
import { Errorf } from "fmt";

function loadConfig(path: string): [Config, error | null] {
    let [data, err] = readFile(path);
    if (err != null) {
        return [zero<Config>(), Errorf("failed to load config: %w", err)];
    }
    
    // ...
    return [config, null];
}

模块系统

导入 Go 包

typescript
// TypeScript
import { readFile } from 'fs/promises';
import express from 'express';

// Targo - 导入 Go 标准库
import { Println, Printf } from "fmt";
import { ReadFile } from "os";
import { Get } from "net/http";

// Targo - 导入第三方 Go 包
import { NewRouter } from "github.com/gorilla/mux";

包管理

typescript
// TypeScript - package.json
{
  "dependencies": {
    "express": "^4.18.0"
  }
}

// Targo - go.mod
module myapp

go 1.22

require (
    github.com/gorilla/mux v1.8.0
)

不支持的特性

JavaScript 运行时

特性状态Targo 替代
Promisechan<T>
async/awaitgo() + channel
setTimeouttime.Sleep()
setIntervaltime.Ticker
fetchnet/http
JSON.parseencoding/json
console.log映射到 fmt.Println

TypeScript 高级特性

特性状态
keyof
typeof(类型操作符)
条件类型
映射类型
模板字面量类型
装饰器🧪(仅 @tag

Class 特性

特性状态Targo 替代
constructor工厂函数
extends组合(Embedding)
private/protected#field
abstract class接口
static包级函数

迁移检查清单

从 TypeScript 项目迁移到 Targo 时,按以下步骤检查:

类型相关

  • [ ] 将 number 替换为具体类型(intfloat64 等)
  • [ ] 将 Array<T>T[] 替换为 slice<T>
  • [ ] 将 undefined 统一为 null
  • [ ] 移除 Set<T>,使用 map<T, bool> 代替

异步相关

  • [ ] 将 Promise<T> 替换为 chan<T>
  • [ ] 移除 async/await,使用 go() 和 channel
  • [ ] 将 Promise.all() 改为并发 goroutine

错误处理

  • [ ] 将 try/catch 替换为多返回值
  • [ ] 添加错误检查:if (err != null) { return err; }
  • [ ] 使用 error | null 类型

条件和循环

  • [ ] 使布尔条件显式化:if (x)if (x != null)
  • [ ] 检查数组长度:if (arr.length)if (arr.length > 0)

类和对象

  • [ ] 将类继承改为组合(Embedding)
  • [ ] 移除 constructor,创建工厂函数
  • [ ] 使用 #field 表示私有字段
  • [ ] 移除 static 方法,改为包级函数

导入和模块

  • [ ] 更新导入语句为 Go 包路径
  • [ ] 创建 go.mod 文件
  • [ ] 使用 targo bind 生成 Go 包的类型声明

实战示例

HTTP 服务器

typescript
// TypeScript + Express
import express from 'express';

const app = express();

app.get('/hello', (req, res) => {
    res.json({ message: 'Hello, World!' });
});

app.listen(3000, () => {
    console.log('Server running on port 3000');
});

// Targo + net/http
import { HandleFunc, ListenAndServe } from "net/http";
import { Fprintf } from "fmt";

function helloHandler(w: ResponseWriter, r: Request): void {
    Fprintf(w, `{"message": "Hello, World!"}`);
}

function main(): void {
    HandleFunc("/hello", helloHandler);
    console.log("Server running on port 3000");
    ListenAndServe(":3000", null);
}

数据处理

typescript
// TypeScript
interface User {
    id: number;
    name: string;
    email: string;
}

async function getUsers(): Promise<User[]> {
    const response = await fetch('/api/users');
    return response.json();
}

const users = await getUsers();
const names = users.map(u => u.name);
const adults = users.filter(u => u.age >= 18);

// Targo
class User {
    id: int;
    name: string;
    email: string;
}

function getUsers(): chan<slice<User>> {
    let ch = chan.make<slice<User>>();
    
    go(() => {
        // 模拟 API 调用
        let users = slice.of<User>(
            { id: 1, name: "Alice", email: "alice@example.com" } as User,
            { id: 2, name: "Bob", email: "bob@example.com" } as User
        );
        ch.send(users);
        ch.close();
    });
    
    return ch;
}

let usersCh = getUsers();
let users = usersCh.receive();

// 使用 Array 获取 map/filter 方法
let usersArr = users as Array<User>;
let names = usersArr.map(u => u.name);
let adults = usersArr.filter(u => u.age >= 18);

常见问题

Q: 为什么没有 number 类型?

A: Go 有多种数值类型(int, float64 等),每种都有不同的大小和精度。明确类型可以:

  • 避免隐式转换导致的精度损失
  • 更好的性能(使用合适的类型)
  • 与 Go 生态系统兼容

Q: 为什么不支持 async/await

A: Go 使用 goroutine 和 channel 实现并发,这是一种不同但更强大的模型:

  • Goroutine 比 Promise 更轻量
  • Channel 提供类型安全的通信
  • 可以使用 select 实现复杂的并发模式

Q: 如何处理 JSON?

A: 使用 Go 的 encoding/json 包:

typescript
import { Marshal, Unmarshal } from "encoding/json";

class User {
    name: string;
    age: int;
}

// 序列化
let user = { name: "Alice", age: 30 } as User;
let [jsonData, err] = Marshal(user);

// 反序列化
let user2 = zero<User>();
let err2 = Unmarshal(jsonData, ref(user2));

Q: 可以使用 npm 包吗?

A: 不可以。Targo 编译为 Go 代码,只能使用 Go 包。但 Go 生态系统非常丰富,大多数需求都有对应的 Go 包。

下一步

参考资源