TypeScript类型扩展与方法

huangapple go评论66阅读模式
英文:

TypeScript type extension with methods

问题

假设我有一个外部定义的类(之前没有具体说明)
```ts
export class A {
    a: string
    b: number

    public foo() { }
}

我想要在类 A 中全局添加一个方法 bar,在TypeScript中应该如何实现?在JavaScript中,我知道你可以简单地这样做:A.prototype.bar = function() { ... } 但在TypeScript中,这会导致多个问题,因为它在类 A 的定义和所有用法中都无法识别为属性。所以我想知道如何在TypeScript中实现这一点,只需运行objectOfTypeA.bar()


<details>
<summary>英文:</summary>

Suppose I have an externally defined class (sorry for not specifying earlier)
```ts
export class A {
    a: string
    b: number

    public foo() { }
}

And I want to add a method bar to class A globally, how would I do that in TypeScript? In JavaScript I know you can simply do A.prototype.bar = function() { ... } but in TypeScript that causes multiple issues with it not being a recognized property of class A in both definition and all usages. So I'm wondering how do I do this in TypeScript just being able to run objectOfTypeA.bar()?

答案1

得分: 1

要将 bar() 方法添加到全局的 class A 中,你可以按照以下方式在 TypeScript 中实现:

假设 class A 是你自己的类,那么只需添加 bar() 方法即可,因为任何能够操作 A.prototype.ts.js 文件都将不得不导入它:

export class A {
    a: string;
    b: number;

    foo() { }
    bar() { }

}

但如果 class A 不是一个导出的类型,而是一个全局范围内的旧式构造函数或类,那么你仍然需要使用 A.prototype 进行操作(可能需要在 TypeScript 中使用 any),但你可以使用 declare 声明来规范化你的更改。

在(现代)TypeScript 中,你可能只会在查看 @types 库中的 .d.ts 文件或 TypeScript 安装文件夹中的 lib.dom.d.ts 时遇到 declare,但它也用于允许 TypeScript 与不合作的库一起使用。

你还可以为完全相同的类型拥有多个 declare 声明,因为 TypeScript 将它们合并在一起。

模块扩展:
如果要对外部模块代码进行修补,这被称为“模块扩展”:

Uncooperative.js:

export class A {
    foo() { }
}

You.ts:

// 首先,导入它:
import { A } from "./uncooperative";

// 其次:使用声明扩展`class A`的接口:
// 是的,你可以使用`interface`类型扩展`class`类型。
declare module "./uncooperative" {
    
    interface A {
        bar(): void;
    }
}

// 然后:进行实际的补丁,使用`any`类型来避免我们在这里不关心的TS错误:
( A as any ).prototype.bar = function() {
    window.location = 'https://leekspin.com/';
};

全局扩展:
如果你正在使用不使用模块的.js文件,就像在1996年一样,它们是全局范围的文件,那么你需要使用declare global语句:

Uncooperative.js:

function MacGuffin() {
    this.fieldA = 'a';
}
MacGuffin.prototype.runTurboEncabulator = function( arg1 ) {
    
};

You.ts:

// 无需导入任何内容,只需进行声明:

declare global {
    interface MacGuffin {
        doSomethingElse(): void;
    }
}

// 然后进行补丁:

MacGuffin.prototype.doSomethingElse = function() {
    window.location = 'https://www.youtube.com/watch?v=uKfKtXYLG78';
}
英文:

> And I want to add a method bar() to class A globally, how would I do that in TypeScript?

Assuming class A is yours, then just add bar() - there's no point to doing anything else because any .ts or .js file that could manipulate the A.prototype will already have to import it anyway.

export class A {
    a: string;
    b: number;

    foo() { }
    bar() { }

}

Whereas if class A is not an exported type, but is an old-school "global"-scoped class or Constructor-function, then you will still need to use A.prototype manipulation (probably using any in TypeScript) but you can still codify your changes with a declare declaration:

In (modern) TypeScript you'll probably only encounter declare if you peer inside .d.ts files from @types libraries, or the lib.dom.d.ts in your TypeScript install folder - but it's also used to allow TypeScript to work with uncooperative libraries...

You can also have multiple declare statements for the exact same type: that works because TypeScript will merge them together for you.

Module Augmentation:

Also, doing this for patching external module code is known as "module augmentation":

Uncooperative.js:

export class A {
    foo() { }
}

You.ts:

// First, import it:
import { A } from &quot;./uncooperative&quot;;

// Second: extend the interface of `class A` with a declaration:
// Yes, you use an `interface` type to extend a `class` type.
declare module &quot;./uncooperative&quot; {
    
    interface A {
        bar(): void;
    }
}

// Third: you do the actual monkey-patching, with the `any` type to avoid TS errors that we don&#39;t care about here:
( A as any ).prototype.bar = function() {
    window.location = &#39;https://leekspin.com/&#39;;
};

Global Augmentation:

If you're working with a .js file that doesn't use Modules: good ol' fashioned global-scoped files, just like they were back in 1996, then you need to use the declare global statement:

Uncooperative.js:

function MacGuffin() {
    this.fieldA = &#39;a&#39;;
}
MacGuffin.prototype.runTurboEncabulator = function( arg1 ) {
    
};

You.ts:

// Nothing to import, just make your declarations:

declare global {
    interface MacGuffin {
        doSomethingElse(): void;
    }
}

// Then monkey-patch it:

MacGuffin.prototype.doSomethingElse = function() {
    window.location = &#39;https://www.youtube.com/watch?v=uKfKtXYLG78&#39;;
}

huangapple
  • 本文由 发表于 2023年7月17日 18:48:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76703713.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定