typescript 打字稿界面中的“构造函数”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46969551/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:49:20  来源:igfitidea点击:

"constructor" in typescript interface

typescript

提问by Mateusz Stefek

I received the following interface from a library that I'm using:

我从我正在使用的库中收到以下界面:

export interface LatLng {
  constructor(lat: number, lng: number): void;
  lat(): number;
  lng(): number;
}

How do I create an implementation of this class? (I need a testing mock) A natural-looking implementation with constructor defined as:

如何创建此类的实现?(我需要一个测试模拟)一个看起来很自然的实现,构造函数定义为:

export class LatLngImpl implements LatLng {
  constructor(private _lat: number, private _lng: number) {  }

doesn't compile:

不编译:

Class 'LatLngImpl' incorrectly implements interface 'LatLng'. Types of property 'constructor' are incompatible. Type 'Function' is not assignable to type '(lat: number, lng: number) => >void'. Type 'Function' provides no match for the signature '(lat: number, lng: >number): void'

类“LatLngImpl”错误地实现了接口“LatLng”。属性“构造函数”的类型不兼容。类型“函数”不可分配给类型“(纬度:数字, lng:数字)=> >void”。类型“函数”不提供与签名“(lat: number, lng: >number): void”的匹配项

I read about contructor-interfaces in typescript, but I don't think it's applicable here.

我在打字稿中阅读了构造函数接口,但我认为它不适用于这里。

Edit:

编辑:

What I don't undertand is this constructor()declaration in the interface. The interfaces with constructor signatures use new ()syntax.

我不明白的是constructor()接口中的这个声明。带有构造函数签名的接口使用new ()语法。

采纳答案by jcalz

Where is this library from? Whoever wrote it deserves a stern talking-to. Either it's a mistake (in which case they never tested it) or it's intentional but eeeeevil: using the not-quite-reserved wordconstructoras an identifier for an instance method is just asking for trouble.

这个图书馆是哪里来的?写它的人应该得到严厉的谈话。要么是错误(在这种情况下,他们从未测试过),要么是故意的,但令人毛骨悚然:使用不太保留的词constructor作为实例方法的标识符只是自找麻烦。

EDIT 2019-04-25:The trouble is worse than just "this is a bad idea"; it actually looks like once JavaScript natively supports class fields, it is going to be an error to have a class with a property named "constructor". TypeScript will change to reflect this in version 3.5+, so the implementation below will stop working then. See recently opened GitHub issue Microsoft/TypeScript#31020for more information. After TS3.5 it looks like there will be no way to have a class with an instance constructorproperty that is not the actual constructor function itself.

编辑 2019-04-25:麻烦不仅仅是“这是一个坏主意”;实际上,一旦 JavaScript 原生支持类字段,那么如果类具有名为"constructor". TypeScript 将在 3.5+ 版本中更改以反映这一点,因此下面的实现将停止工作。有关更多信息,请参阅最近打开的 GitHub 问题Microsoft/TypeScript#31020。在 TS3.5 之后,似乎没有办法让类的实例constructor属性不是实际的构造函数本身。

Either the library author intended to refer to a real constructor that you call with new, in which case they should do something like @Series0ne's suggestion; orthe author really wants to use an instance method to initialize the object, in which case they should do everyone a favor and use a more conventional method name like init().

库作者打算引用您调用的真实构造函数new,在这种情况下,他们应该执行类似@Series0ne 的建议或者作者真的想使用实例方法来初始化对象,在这种情况下,他们应该帮大家一个忙,使用更常规的方法名称,如init()

In either case nobody should accept the interface you've been given, and certainly nobody should implement it.

在任何一种情况下,没有人应该接受你得到的接口,当然也没有人应该实现它。

Let's implement it:

让我们实现它:

export class LatLngImpl implements LatLng {
  private _lat: number;
  private _lng: number;
  lat() {
    return this._lat;
  }
  lng() {
    return this._lng;
  }
  // here's the important part, but see Microsoft/TypeScript#31020
  "constructor"(lat: number, lng: number) { 
    this._lat = lat;
    this._lng = lng;
  }
}

The trick is to use the string literal "constructor"instead of the bare word constructor. From the TypeScript spec:

诀窍是使用字符串文字"constructor"而不是裸词constructor。从打字稿规范

String literals may be used to give properties names that are not valid identifiers

字符串文字可用于给出不是有效标识符的属性名称

By using the string literal, we were able to declare it as an instance method, and not the static class constructor method that is invoked when you call new, and it compiles happily.

通过使用字符串字面量,我们能够将其声明为实例方法,而不是调用时调用的静态类构造函数方法new,并且编译愉快。

Now we can use it, if we dare:

现在我们可以使用它,如果我们敢:

const latLng = new LatLngImpl();
latLng.constructor(47.6391132, -122.1284311); //  Why not init()?
console.log("Latitude: " + latLng.lat() + ", Longitude: " + latLng.lng());

Yuck, we shouldn't have dared.

哎呀,我们不应该敢。

EDIT AGAIN 2019-04-25The above quoted-string implementation will not workstarting in TypeScript 3.5, and the correct answer to this will be "you can't do this" and "use a real constructor instead".

再次编辑 2019-04-25从 TypeScript 3.5 开始,上面的引用字符串实现将不起作用,正确答案是“你不能这样做”和“使用真正的构造函数”。

Hope that helps; good luck!

希望有所帮助;祝你好运!

回答by Matthew Layton

A constructor is technically a special, static function call that returns an instance of itself, so it doesn't really make sense for it to be part of an interface, because interface members are instance bound.

从技术上讲,构造函数是一个特殊的静态函数调用,它返回自身的一个实例,因此将其作为接口的一部分实际上没有意义,因为接口成员是实例绑定的。

Typescript has a bit of a compiler trick to make them statically bound, and uses this for ambient declarations.

Typescript 有一些编译器技巧可以使它们静态绑定,并将其用于环境声明。

In your case, to provide an implementation, you need to remove the constructor from the interface:

在您的情况下,要提供实现,您需要从接口中删除构造函数:

interface LatLng {
    lat(): number;
    lng(): number;
}

class LatLngImpl implements LatLng {
    constructor(lat: number, lng: number) {

    }

    lat(): number {
        return 0;
    }

    lng(): number {
        return 0;
    }
}

If LatLngis implemented elsewhere, you simply need to provide an ambient declaration:

如果LatLng在其他地方实现,您只需要提供一个环境声明:

interface LatLng {
    lat(): number;
    lng(): number;
}

interface LatLngConstructor {
    new(lat: number, lng: number): LatLng;
}

declare var LatLng: LatLngConstructor;

Notice that LatLngConstructordefines a new(...): LatLng, which is what describes the constructor signature.

请注意,LatLngConstructor定义了一个new(...): LatLng,它描述了构造函数签名。

回答by Sourav Bhattacharya

I believe you cannot put constructor inside an interface.

我相信你不能将构造函数放在接口中。

interface IPerson 
{
    firstName: string;
    lastName: string;
}

class Person implements IPerson 
{
    constructor (public firstName: string, public lastName: string) 
    {
        //TODO
    }
}

var personA: IPerson = new Person('Jane', 'Smith');
var personB: IPerson = { firstName: 'Jo', lastName: 'Smith' };