英文:
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 export
ed 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 "./uncooperative";
// Second: extend the interface of `class A` with a declaration:
// Yes, you use an `interface` type to extend a `class` type.
declare module "./uncooperative" {
interface A {
bar(): void;
}
}
// Third: you do the actual monkey-patching, with the `any` type to avoid TS errors that we don't care about here:
( A as any ).prototype.bar = function() {
window.location = 'https://leekspin.com/';
};
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 = 'a';
}
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 = 'https://www.youtube.com/watch?v=uKfKtXYLG78';
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论