结构体与组合
Targo 支持 class,但语义是 Go-first。把它理解为"带方法和引用语义的 struct",而不是"完整的 JavaScript class 运行时"。
核心规则
class映射到 Go struct,引用语义(Go 中为*T)。constructor支持——编译为NewT()工厂函数。- 不支持经典继承。
- 优先使用组合、接口、
Embedding<{ ... }>()、DefinedType<...>(),而不是试图重现extends。 - 私有字段使用
#field。不要使用 TypeScript 的private或protected。
字段可见性与大小写
Go 使用首字母大小写控制可见性。Targo 自动映射:
| Targo 语法 | Go 输出 | 可见性 |
|---|---|---|
name: string | Name string | 公开(默认——首字母大写) |
#secret: string | secret string | 私有(包内部) |
_internal: int | _Internal int | 公开(_ 保留,下一个字母大写) |
typescript
class User {
name: string = ""; // → Name string(公开)
#password: string = ""; // → password string(私有)
}#field 只能在类内部访问。外部访问需要 getter/setter 方法。
构造函数
当类有 constructor 时,new T(...) 编译为 NewT(...):
typescript
class User {
Name: string;
constructor(name: string) {
this.Name = name;
}
}
let u = new User("Alice"); // Go: NewUser("Alice")当类没有 constructor 时,new T() 编译为 new(T)(Go 零值分配):
typescript
class Point { X: float64 = 0; Y: float64 = 0; }
let p = new Point(); // Go: new(Point)Struct 字面量初始化绕过构造函数:
typescript
let u: User = { Name: "Bob" }; // Go: &User{Name: "Bob"}构造函数约束:
- 只能有一个构造函数(Go 没有函数重载)
- 没有
super()(没有继承) DefinedType类不能有构造函数——使用as或工厂函数代替
方法与接收者
方法默认使用指针接收者(匹配约 83% 的 Go 标准库方法):
typescript
class Counter {
Value: int = 0;
Increment(): void { // Go: func (c *Counter) Increment()
this.Value++;
}
}需要值接收者时,使用显式 this: Val<T>:
typescript
class Point {
X: float64 = 0;
Y: float64 = 0;
Distance(this: Val<Point>): float64 { // Go: func (p Point) Distance() float64
return Math.sqrt(this.X * this.X + this.Y * this.Y);
}
}方法可见性遵循与字段相同的大小写规则——所有方法在 Go 输出中都是公开的(首字母大写)。
可选字段
使用 ? 标记可选字段。编译为存在感知的持有者,而非简单的 *T:
typescript
class Config {
Host: string = "localhost";
Port?: int; // Go: Port targo.Optional[int]
}读取语义:
config.Port !== undefined→ 存在性检查config.Port ?? 8080→ 缺失时回退
这与 Map.get() 和 Array.find() 使用的 comma-ok 模式([T, bool])不同。
DefinedType
DefinedType 创建一个独立的 Go defined type——Targo 实现类型安全最重要的模式之一。
原始类型 DefinedType
typescript
class UserId extends DefinedType<int64>() {}
class Temperature extends DefinedType<float64>() {}
let id: UserId = 42 as UserId; // Go: UserId(42)
let raw: int64 = id.underlying(); // Go: int64(id)两个底层类型相同的 DefinedType 类不可互换。
基于 Struct 的 DefinedType
继承底层 struct 的字段但不继承方法:
typescript
class Point {
X: int = 0; Y: int = 0;
Distance(): float64 { return Math.sqrt(this.X * this.X + this.Y * this.Y); }
}
class Location extends DefinedType<Point>() {
ToString(): string { return `(${this.X}, ${this.Y})`; }
}
let loc = new Location();
loc.X = 10; // ✅ 字段继承
loc.ToString(); // ✅ 自有方法
// loc.Distance(); // ❌ 方法不继承DefinedType 与集合
typescript
class UserList extends DefinedType<slice<User>>() {}
class Config extends DefinedType<map<string, string>>() {}DefinedType 规则
- 创建的是 Go 名义类型,不是 TypeScript 类型别名
- 使用
as进行转换:42 as UserId,反向使用id.underlying() - 不能有
constructor——使用as或工厂函数 - 支持嵌套 DefinedType:
class OInt extends DefinedType<MyInt>() {} Underlying<T>约束匹配所有底层类型为T的类型
Embedding
Embedding 提供 Go 风格的结构体嵌入。被嵌入类型的字段和方法会提升到外层 struct。
基本用法
typescript
class Animal {
Name: string = "";
}
class Dog extends Embedding<{ Animal: Animal }>() {
Bark(): string {
return `${this.Name} says woof`; // Name 从 Animal 提升
}
}多重嵌入
typescript
class ReadWriter extends Embedding<{ Reader: Reader; Writer: Writer }>() {}Embedding 规则
- 键名必须匹配类型名:
{ Reader: Reader }✅,{ Foo: Reader }❌ - 只有 struct 和 interface 可以被嵌入(不能嵌入 slice、map、chan 或原始类型)
- 提升字段:直接访问
this.Name或显式访问this.Animal.Name - 命名冲突:如果两个嵌入类型有同名成员,该成员不会被提升——需要显式限定访问
- 嵌入是组合,不是继承——没有多态分发
Struct Tags
使用 JSDoc 注释在 class 字段上添加 Go struct tag。
@json 简写用于简单 JSON tag:
typescript
class User {
/** @json "user_name" */
Name: string = "";
/** @json "email,omitempty" */
Email: string = "";
/** @json "-" */
#password: string = "";
}@tag 完整语法用于多个 tag(反引号包裹):
typescript
class Product {
/** @tag `json:"id" db:"product_id"` */
Id: string = "";
/** @tag `json:"name" xml:"Name" db:"product_name"` */
Name: string = "";
}接口
- 接口是 Go 风格的行为契约
- 涉及真实 Go interface 的代码使用
GoInterface标记 - 完整规则见
interfaces.md,包括 GoInterface、class 兼容性和方法形状要求
组合模式
| 需求 | 使用 |
|---|---|
| 复用数据布局 | 组合(另一个类型的字段) |
| 从另一个 struct 提升字段/方法 | Embedding<{ T: T }>() |
| 具有类型安全的独立名义类型 | DefinedType<T>() |
| 行为契约 / 可替换性 | interface(+ Go 边界使用 GoInterface) |
常见错误
- 以为支持 constructor 就意味着推荐 JavaScript OOP 模式——以 Go-first 思维
- 试图用
extends风格的层次设计代替组合 - 使用 TypeScript
private/protected而不是#field - 把两个底层类型相同的
DefinedType当作可互换的 - 给
DefinedType类添加constructor(不允许) - 忘记
Embedding会提升字段,可能导致命名冲突 - 期望方法通过
DefinedType<Struct>()继承——只有字段会继承 - 当
User已经是指针时使用Ptr<User>(class 实例默认就是*T)