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

Mat*_*fek 11 typescript

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

export interface LatLng {
  constructor(lat: number, lng: number): void;
  lat(): number;
  lng(): number;
}
Run Code Online (Sandbox Code Playgroud)

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

export class LatLngImpl implements LatLng {
  constructor(private _lat: number, private _lng: number) {  }
Run Code Online (Sandbox Code Playgroud)

无法编译:

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

我读过有关打字稿中的构造函数接口的信息,但我认为它不适用于此处。

编辑:

我不需要理解的是constructor()接口中的此声明。具有构造函数签名的接口使用new ()语法。

ser*_*0ne 9

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

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

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

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

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

    }

    lat(): number {
        return 0;
    }

    lng(): number {
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

declare var LatLng: LatLngConstructor;
Run Code Online (Sandbox Code Playgroud)

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

  • 重要的是,“接口”是为了确保创建“什么”,而不是“创建什么”。根据我的经验,强迫构造函数以某种方式操作只会导致更多的痛苦,而没有任何实际的好处。即,无论使用“LatLngImpl”,只关心“lat”和“lng”属性,而构造函数的详细信息应该是无关的。任何更严格的规定_可能_都是糟糕代码的标志。 (3认同)

jca*_*alz 9

这个图书馆是哪里来的?无论是谁写的,都应该严肃地与他交谈。这是一个错误(在这种情况下,他们从未进行过测试),或者是有意的,但eeeeevil:使用不完全保留的单词 constructor作为实例方法的标识符只是在自找麻烦。

编辑2019-04-25:麻烦比“这是一个坏主意”还要糟糕;实际上,一旦JavaScript原生支持类字段,拥有一个名为属性的类将是一个错误"constructor"。TypeScript将进行更改以在版本3.5+中反映出来,因此下面的实现将停止工作。有关更多信息,请参见最近打开的GitHub问题Microsoft / TypeScript#31020。在TS3.5之后,似乎将无法拥有一个实例constructor属性而不是实际构造函数本身的类。

要么库作者想引用一个真正的构造函数,然后调用new@ Series0ne的建议作者真的想使用实例方法来初始化对象,在这种情况下,他们应该帮大家一个忙,并使用更传统的方法名称,例如init()

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

让我们实现它:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

诀窍是使用字符串文字"constructor"而不是裸字constructor。根据TypeScript规范

字符串文字可能会用于提供无效标识符的属性名称

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

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

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

,我们不应该胆子大。

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

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