TypeScript具有两个名为String
和StringConstructor
的字符串接口。
此外,TypeScript language specification在第1章第1.3节中提供了此代码示例:
interface JQuery {
text(content: string);
}
interface JQueryStatic {
get(url: string, callback: (data: string) => any);
(query: string): JQuery;
}
JQuery
/ JQueryStatic
和String
/ StringConstructor
接口有什么区别,并且Static
和Constructor
接口有关系吗? / p>
编辑:是的,我知道链接的书已经 3岁过时了。
答案 0 :(得分:1)
我要从String
切换到RegExp
,因为String
出现了皱纹,我稍后会提到 * 。
实例接口(例如RegExp
和JQuery
)通常表示一种对象类型,其中可以存在多个不同的实例。关联的静态接口(例如RegExpConstructor
和JQueryStatic
)通常表示创建或返回这些实例的对象的类型。通常,这些静态对象中只有一个存在。因此,只有一个RegExpConstructor
对象可以构成许多RegExp
个对象,只有一个JQueryStatic
对象可以构成许多JQuery
个对象。
在实践中,一个常见的混淆来源是name collision between values and types。单个静态对象的名称(例如RegExp
或jQuery
)往往与实例接口的名称相同。但是该静态对象的类型不是实例接口的类型。因此,在运行时名为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
值。 string
和String
通常可以互换:
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>
好的,希望能有所帮助。祝你好运!