
通过继承而非手动代理,可让子类天然获得父类所有方法,既保持类型安全又避免重复代码;若需组合而非继承,可结合 Proxy 与泛型约束实现类型感知的自动方法转发。
通过继承而非手动代理,可让子类天然获得父类所有方法,既保持类型安全又避免重复代码;若需组合而非继承,可结合 `proxy` 与泛型约束实现类型感知的自动方法转发。
在面向对象设计中,当需要将一个类(如 Bar)的行为“委托”给另一个类实例(如 Foo)时,常见的错误思路是为每个方法手动编写转发逻辑(如 greet() { return this.foo.greet(); })。这不仅冗余、易出错,更严重的是破坏了类型安全性——TypeScript 无法静态推导出 Bar 实例具备 Foo 的全部方法签名。
最简洁且完全类型安全的解决方案是使用 extends 实现继承:
class Foo {
greet() {
return "hello";
}
sayGoodbye() {
return "bye";
}
}
class Bar extends Foo {} // 直接继承,无需任何额外代码
const bar = new Bar();
console.log(bar.greet()); // ✅ 类型安全:string
console.log(bar.sayGoodbye()); // ✅ 类型安全:string
此时 Bar 是 Foo 的子类,其原型链天然包含 Foo.prototype 上的所有方法,TypeScript 编译器能精确推导出 Bar 实例的完整方法签名,零运行时开销,零类型断言。
完整的Galileo AI平台 TypeScript/JS SDK 参考,用于评估、观察和保护 GenAI 应用。适用于构建 Node.js 或 TypeScript 项目。
⚠️ 注意:继承适用于“is-a”关系(Bar 是一种 Foo)。若业务语义要求“has-a”(Bar 持有一个 Foo 实例,且需独立构造 Foo),则继承不适用。此时可采用 类型安全的 Proxy + 泛型委托模式:
class Foo {
greet() { return "hello"; }
sayGoodbye() { return "bye"; }
}
class Bar {
private foo: Foo;
constructor(foo?: Foo) {
this.foo = foo ?? new Foo();
}
// 自动转发所有 Foo 方法(类型安全)
public static readonly forwardedMethods = [
'greet',
'sayGoodbye',
] as const;
private static readonly forwardedMethodSet = new Set(Bar.forwardedMethods);
// 重写 get,仅对已知方法做类型安全转发
[key: string]: unknown;
get(key: string): unknown {
if (Bar.forwardedMethodSet.has(key as any)) {
return (...args: unknown[]) => (this.foo as any)[key](...args);
}
throw new Error(`Method '${key}' is not forwarded`);
}
}
// 更推荐的类型增强版(利用映射类型确保编译期检查):
type ForwardedMethods<t> = {
[K in keyof T as K extends string ? K : never]: T[K] extends (...args: any[]) => any
? (...args: Parameters<t>) => ReturnType<t>
: never;
};
class BarTyped<fooinstance extends foo> {
private foo: FooInstance;
constructor(foo: FooInstance) {
this.foo = foo;
}
// 通过索引签名 + 显式泛型约束,实现类型安全代理
public greet = (...args: Parameters<foo>) => this.foo.greet(...args);
public sayGoodbye = (...args: Parameters<foo>) => this.foo.sayGoodbye(...args);
// ✅ 添加新方法时,TS 会强制你显式声明,兼顾安全与可控性
}</foo></foo></fooinstance></t></t></t>
总结:优先使用 extends 继承——它是最符合 TypeScript 类型系统原生能力、零配置、零妥协的方案;仅当组合语义不可替代时,再考虑基于泛型和映射类型的显式委托,避免使用无类型 Proxy 或 any,以守住类型安全底线。










