TypeScript中的“构造函数”,“静态”和常规接口之间有什么区别?

时间:2019-04-28 12:01:29

标签: typescript constructor interface static

TypeScript具有两个名为StringStringConstructor的字符串接口。

此外,TypeScript language specification在第1章第1.3节中提供了此代码示例:

interface JQuery {
  text(content: string);
}

interface JQueryStatic {
  get(url: string, callback: (data: string) => any);
  (query: string): JQuery;
}

JQuery / JQueryStaticString / StringConstructor接口有什么区别,并且StaticConstructor接口有关系吗? / p>

编辑:是的,我知道链接的书已经 3岁过时了。

1 个答案:

答案 0 :(得分:1)

我要从String切换到RegExp,因为String出现了皱纹,我稍后会提到 *


实例接口(例如RegExpJQuery)通常表示一种对象类型,其中可以存在多个不同的实例。关联的静态接口(例如RegExpConstructorJQueryStatic)通常表示创建返回这些实例的对象的类型。通常,这些静态对象中只有一个存在。因此,只有一个RegExpConstructor对象可以构成许多RegExp个对象,只有一个JQueryStatic对象可以构成许多JQuery个对象。

在实践中,一个常见的混淆来源是name collision between values and types。单个静态对象的名称(例如RegExpjQuery)往往与实例接口的名称相同。但是该静态对象的类型不是实例接口的类型。因此,在运行时名为RegExp value 具有类型RegExpConstructor,而不是RegExp。并且在运行时名为jQuery value 具有类型JQueryStatic,而不是JQuery。这很令人困惑,但可能是最好的,因为它使您可以在运行时说x instanceof Y之类的东西,而在编译时x的类型是Y

无论如何,如果存在行为取决于特定实例的属性或方法,则通常位于实例接口上。如果某些属性或方法的行为不依赖于特定实例,则通常位于静态接口上。


构造函数接口是一个静态接口,专门允许您在其上使用new operator来创建新实例。在TypeScript中,它的表示类似于函数调用签名,但其名称为new,如下所示:

type F = (x: string) => number[];
type C = new(x: string) => number[]; 

类型F代表一个函数,该函数采用一个string参数并产生一个number s数组,而类型C代表一个构造函数函数,该函数带有一个string参数,并产生一个number s数组:

declare const f: F;
declare const c: C;
const arr1 = f("hey"); // number[]
const oops1 = new f("hey"); // error, f is not newable
const arr2 = new c("hey"); // number[]
const oops2 = c("hey"); // error, c is not callable

拥有同时也是构造函数接口的静态接口是很常见的;所有class静态接口都是构造函数接口。但是,并非每个静态接口都是构造函数接口。 JQueryStatic接口只是一个示例。要从JQuery对象中获取JQueryStatic实例,可以像调用函数一样调用它(这就是(query: string): JQuery;签名的含义)。

这就是JQueryStatic / JQuery对和RegExpConstructor / RegExp对之间的主要区别,也是该问题的主要答案的结尾。

>

* 回到String皱纹。名为String的类型专门引用通过在new构造函数上调用String运算符构造的 object 。还有一个名为string的类型(带有小写的s),它引用primitive数据类型。实际上,您处理的所有字符串都是string类型的原语,而String是相对不常见的wrapper object,它拥有一个string值。 stringString通常可以互换:

const stringPrimitive = "hello"; // type is string
const stringObject = new String("hello"); // type is String
console.log(stringPrimitive+"!"); // "hello!"
console.log(stringObject+"!"); // "hello!"
console.log(stringPrimitive.charAt(4)); // "o"
console.log(stringObject.charAt(4)); // "o"

除非它们不可互换:

console.log(typeof stringPrimitive); // "string"
console.log(typeof stringObject); // "object"
console.log(stringPrimitive instanceof String); // false
console.log(stringObject instanceof String); // true

当您意识到StringConstructor也可以像函数一样调用并产生 primitive string时,情况就更加混乱了:

console.log(typeof "hey"); // "string"
console.log(typeof new String("hey")); // "object"
console.log(typeof String("hey")); // "string"

所以很混乱。这里的规则几乎是always use string; never use String。这就是为什么我将代码示例从String更改为始终对象RegExp的原因,对于该对象,没有原始数据类型(typeof /foo/ === "object")会造成麻烦。 / p>


好的,希望能有所帮助。祝你好运!