在 TypeScript 中,this 的正确类型化对于支持方法链模式至关重要,该模式允许方法返回 this 以进行连续调用。如果不明确指定返回值的类型,TypeScript 默认将返回的对象视为当前类的实例,这在继承时是不正确的。
为了解决这个问题,可以使用 多态 this 类型(polymorphic this types) 通过返回 this:
class Builder { value: number = 0; setValue(v: number): this { this.value = v; return this; } } class AdvancedBuilder extends Builder { multiply(factor: number): this { this.value *= factor; return this; } } const b = new AdvancedBuilder().setValue(5).multiply(2); // multiply 正确可见
返回类型 this 确保了即使是继承类,方法链也得到了正确的类型化,而不仅仅是基类。
是否可以仅在返回类型中指定类名(例如,返回 Builder)而不使用 this?这将如何影响继承者中的方法链?
回复:
如果你返回 Builder 而不是 this:
class Builder { setValue(v: number): Builder { //... return this; } } class AdvancedBuilder extends Builder { multiply(factor: number): this { // ... return this; } } const a = new AdvancedBuilder().setValue(2).multiply(2); // multiply 不可见!
在 setValue 之后,multiply 将不可用,因为 setValue 将返回 Builder,而不是 AdvancedBuilder。只有在方法签名中使用 this 才能在方法链中保持正确的类型化。
故事
在开发团队中创建了一个流畅的 API 用于构建配置。在方法中返回基类类型,认为这是良好的实践。在出现继承者后,流畅的 API 中所有附加方法在标准调用链后变得不可见。结果:不得不将 API 重构为 this,以便客户能使用扩展功能。
故事
在内部装饰器库中,明确返回特定类型的类。用户在使用继承者时失去了对新方法的访问,收到 “object has no method ...”。这个错误只在与新服务的集成时出现。
故事
开发者在将方法从旧的 C# API 复制时,将方法链重写为 TypeScript,返回类名。在构建阶段一切看起来正常,但在用户的继承中丧失了新方法。只有严格的 tsconfig 检查帮助快速发现这个问题——并修复为返回 this。