如何在单独的定义文件中扩展 TypeScript 类定义?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23217334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I extend a TypeScript class definition in a separate definition file?
提问by
I have a JS library called leaflet which has an existing TypeScript definition file.
我有一个名为 Leaflet 的 JS 库,它有一个现有的 TypeScript 定义文件。
I wish to use a plugin which extends some of the objects in leaflet with an extra function.
我希望使用一个插件来扩展传单中的一些对象,并具有额外的功能。
In the existing TypeScript definition file the objects are defined as classes rather than interfaces.
在现有的 TypeScript 定义文件中,对象被定义为类而不是接口。
e.g.
例如
declare module L {
function circleMarker(latlng: LatLng, options?: PathOptions): CircleMarker;
export class CircleMarker extends Circle {
constructor(latlng: LatLng, options?: PathOptions);
setLatLng(latlng: LatLng): CircleMarker;
setRadius(radius: number): CircleMarker;
toGeoJSON(): any;
}
}
If I try and define it a second time in a separate file then I get an error about "Duplicate Identifier 'CircleMarker'.".
如果我尝试在单独的文件中再次定义它,则会收到有关“重复标识符‘CircleMarker’。”的错误消息。
declare module L {
export class CircleMarker {
bindLabel(name: string, options: any): CircleMarker;
}
}
This makes sense as it's a class and not an interface, but that being the case is there a way to extend this class definition without changing the original definition file?
这是有道理的,因为它是一个类而不是接口,但在这种情况下,有没有办法扩展这个类定义而不更改原始定义文件?
The base definition file is pulled in from DefinitelyTyped via nuget so I have a very strong desire not to make any changes to it as it'll make updating much more awkward/prone to failure.
基本定义文件是通过 nuget 从绝对类型中提取的,因此我非常希望不要对其进行任何更改,因为它会使更新变得更加笨拙/容易失败。
采纳答案by WiredPrairie
If you don't control the original definition file, and can't make adjustments to it, then unfortunately, what you're trying to do isn't supported currently in TypeScript. An interface
in TypeScript is the only construct that allows reasonable extensions as it is only a compile-time/syntax check and not a run-time operation.
如果您不控制原始定义文件,并且无法对其进行调整,那么不幸的是,TypeScript 目前不支持您尝试执行的操作。一个interface
在打字稿是唯一的构造,允许合理的扩展,因为它只是一个编译时/语法检查,而不是运行时操作。
You cannot extend a class
in TypeScript with new functionality using only TypeScript (and expecting code-completion/Intellisense to work as expected). You could of course add the functions to the prototype
for the CircleMarker
class, but they would be unavailable to Intellisense and would fail to compile unless you use a type assertion.
您不能class
仅使用 TypeScript 使用新功能扩展TypeScript 中的 a(并期望代码完成/智能感知按预期工作)。你当然可以添加功能,到prototype
了CircleMarker
类,但他们将无法使用智能感知,并会出错,除非你使用一个类型断言。
Instead of using any
, you should be able to use an interface
with the type assertion:
any
您应该能够将 aninterface
与类型断言一起使用,而不是使用:
declare module L {
export interface CircleMarkerEx {
bindLabel(name: string, options: any): CircleMarker;
}
}
Then:
然后:
var cm = <L.CircleMakerEx> circle.bindLabel("name", {});
Thankfully, it doesn't add any run-time overhead, just a bit of extra typing (pun intended!).
值得庆幸的是,它没有增加任何运行时开销,只是一些额外的输入(双关语!)。
There have been suggestions for things like "mix-ins"on CodePlex, but they have not been implemented. Even the mix-in suggestions would not be entirely straightforward to use, and wouldn't work well for libraries that weren't entirely written in TypeScript (as it would be too easy to have JavaScript code that simply could not be safely constructed for example with a mix-in).
在 CodePlex 上有人提出了诸如“混入”之类的建议,但尚未实施。即使是混合建议也不是完全直接使用,并且对于不是完全用 TypeScript 编写的库也不能很好地工作(因为 JavaScript 代码太容易无法安全构建,例如混入)。
回答by basarat
You can't do that with the class
keyword. There is a feature request you can vote on here : https://typescript.codeplex.com/workitem/917
你不能用class
关键字来做到这一点。您可以在此处投票的功能请求:https: //typescript.codeplex.com/workitem/917
You can however mimic classes using interfaces
as shown in the workaround (https://typescript.codeplex.com/workitem/917) for the issue. In your case
但是,您可以使用该问题interfaces
的解决方法 ( https://typescript.codeplex.com/workitem/917) 中所示来模拟类。在你的情况下
declare module L {
function circleMarker(latlng: LatLng, options?: PathOptions): CircleMarker;
declare var CircleMarker: CircleMarkerStatic;
export interface CircleMarkerStatic{
new (latlng: LatLng, options?: PathOptions): CircleMarker;
}
export interface CircleMarker {
setLatLng(latlng: LatLng): CircleMarker;
setRadius(radius: number): CircleMarker;
toGeoJSON(): any;
}
}
and extend it
并扩展它
declare module L {
export interface CircleMarker {
bindLabel(name: string, options: any): CircleMarker;
}
}
回答by Roy Yin
This is what I tried and it feels relatively comfortable for me
这是我尝试过的,对我来说感觉比较舒服
declare module L {
export class CircleMarkerEx {
constructor(source: CircleMarker);
public bindLabel(name: string, options: any): CircleMarker;
}
export function ex(cm: CircleMarker): CircleMarkerEx;
}
where CircleMarkerEx
and ex
can be defined as
其中CircleMarkerEx
和ex
可以定义为
class CircleMarkerExtender extends CircleMarker {
public b() {
return `${this.a()} extended`;
}
}
CircleMarker.prototype = Object.create(CircleMarkerExtender.prototype);
CircleMarker.prototype.constructor = CircleMarker;
export function ex(cm: CircleMarker) {
return cm as CircleMarkerExtender;
}
then
然后
let cm = ex(circle).bindLabel("name", {});
but it is still a little strange
但还是有点奇怪
回答by Rune Jeppesen
Is this possible?
这可能吗?
declare module L {
export class MyCircleMarker extends CircleMarker{
bindLabel(name: string, options: any): CircleMarker;
}
}
And then define your CircleMarker instances as MyCircleMarker
然后将您的 CircleMarker 实例定义为 MyCircleMarker
回答by tanguy_k
Edit: this answer is off topic. It talks about interfaces and not classes like asked
编辑:这个答案是题外话。它谈论接口而不是像被问到的类
I didn't have any problem extending a TypeScript (v3.6) external type definition.
我在扩展 TypeScript (v3.6) 外部类型定义时没有任何问题。
Example with google.maps.Marker type definition:
google.maps.Marker 类型定义示例:
// File types/googlemaps-marker-hello.d.ts or
// whatever file name you like, it doesn't matter
declare namespace google.maps {
interface Marker {
hello: string;
}
}
// Later on inside src/MyCode.ts
const marker = new google.maps.Marker();
marker.hello = 'Hello, World!';
You don't have to modify your tsconfig.json: it just works.
您不必修改您的 tsconfig.json:它只是有效。
It's the way DefinitelyTyped works
这是绝对类型的工作方式
declare module 'webpack' {
interface Configuration {
devServer?: WebpackDevServer.Configuration;
}
}
webpack-dev-server type definition extends webpack type definition. If you use @types/webpack and not @types/webpack-dev-server you won't have the devServer
property.
webpack-dev-server 类型定义扩展了 webpack 类型定义。如果您使用 @types/webpack 而不是 @types/webpack-dev-server 您将没有该devServer
属性。
Another example:
另一个例子:
declare namespace NodeJS {
interface Global {
hello: string;
}
}
global.hello = 'Hello, World!';