想象一下下面的场景.您有一个类A,它有一个方法可以创建类B的实例.您不能编辑A或B的代码(就像在外部库中一样).

在这种情况下,如果您想要扩展B的功能,例如,您可以创建一个扩展B的新类C,并在C中实现新的功能.然而,返回B的A的方法仍将返回B,而不是具有您想要添加到B的新功能的类.如果您希望该方法返回C,您可以做的是创建一个新的类D来扩展A并覆盖返回B的方法以返回C.这可能会失控,例如,如果类E-Z还实现了返回B的实例的方法,那么您希望用C实现新的方法.

在Rust中,您可以使用extension traits通过向 struct 添加新方法来扩展 struct 的功能,并且新方法将可用于该 struct 的所有实例.因此,在前面的示例中,我们可以为B实现一个新的特征Bext,而由A的方法返回的B的实例将具有在Bext中实现的方法.有没有可能在Typescript 中做类似的事情?或者换句话说,是否有可能在不修改类的原始实现的情况下将方法添加到类的所有实例中?或者,您是否可以扩展类的功能,并让返回类实例的所有方法返回具有扩展功能的对象?

示例:

//lib.ts
class B {}

class A {
 static getB(): B { return new B(); }
//index.ts
import {A, B} from "lib.ts"


//Add a new method to B in some way, for instance:
addMethod(B, "helloWorld", () => console.log("Hello World"));

A.getB().helloWorld() // ok;

请注意,此处的addMethod函数仅用于示例目的,它实际上不一定是一个函数,而只是将新方法添加到B中的一种方式.

推荐答案

在JavaScript中获得您所讨论的行为的方法是将方法添加到the prototype个现有类构造函数中.就像这样:

import { A, B } from "./lib";

B.prototype.helloWorld = function () {
  console.log("Hello World");
};

A.getB().helloWorld(); // "Hello World"

这在运行时可以工作,但是类型脚本编译器会抱怨,因为它认为B没有helloWorld()方法.您需要在将新方法签名添加到与类对应的接口之前让编译器知道这一点.由于您是从模块导入的,因此您将使用module augmentation来执行此操作:

declare module "./lib" {
  interface B {
    helloWorld(): void;
  }
}

现在,这也将正确地编译.


请注意,修改现有的原型不一定是recommended%.现有类中或其他地方的任何代码如果没有预料到这样的更改,都可能崩溃.或者,当其他人做出与您的修改冲突的更改时,您的修改可能会中断.一般说来,最好不要以这种方式修修补补,尽管在某些情况下,这可能是有根据的.

Codesandbox link to code

Typescript相关问答推荐

从接口创建类型安全的嵌套 struct

TypeScript类型不匹配:在返回类型中处理已经声明的Promise Wrapper

TypeScript Page Routing在单击时不呈现子页面(React Router v6)

有没有办法解决这个问题,类型和IntrinsicAttributes类型没有相同的属性?

为什么T[数字]不也返回UNDEFINED?

缩小并集子键后重新构造类型

是否可以针对联合类型验证类型属性名称?

尽管对象的类型已声明,但未解析的变量<;变量

如何获取受类型脚本泛型约束的有效输入参数

打字错误推断

如何连接属性名称和值?

当数组类型被扩展并提供标准数组时,TypeScrip不会抱怨

打印脚本中正则函数和函数表达式的不同类型缩小行为

扩展对象的此内容(&Q;)

完全在类型系统中构建的东西意味着什么?

如何处理可能为空的变量...我知道这不是Null?

在类型{}上找不到带有string类型参数的索引签名 - TypeScript

如何将 MUI 主题对象的自定义属性与情感样式组件中的自定义props 一起使用?

为什么我的 Typescript 函数中缺少 void 隐式返回类型?

在 TypeScript 中实现类型级别深度优先搜索