为什么TypeScript允许我将字符串原语分配给类型为String
的变量(对象类型)?例如,为什么这不会导致错误:
var str : String = '2333';
请注意,另一种方式不起作用:
var str : string = new String('2333'); // Error: Type 'String' is not assignable to type 'string'. 'string' is a primitive, but 'String' is a wrapper object. Prefer using 'string' when possible.
代码如下:
const str: string = '2333'
console.log(`typeof str === "string" is ${typeof str === "string"}`)
const str2: String = new String('2333')
console.log(`str2 instanceof String is ${str2 instanceof String}`)
console.log(`typeof str2 === "string" is ${typeof str2 === "string"}`)
const str3: String = '2333'
console.log(`str3 instanceof String is ${str3 instanceof String}`)
console.log(`typeof str3 === "string" is ${typeof str3 === "string"}`)
它表示:
typeof str === "string" is true
str2 instanceof String is true
typeof str2 === "string" is false
str3 instanceof String is false
typeof str3 === "string" is true
来自str
和str2
的我们可以知道string
是来自String
的不同类型。为什么str3
允许滥用两种类型?
答案 0 :(得分:1)
简短版本:TypeScript专门允许将string
分配给String
。
长版本:TypeScript允许将字符串,数字或布尔基元分配给其关联对象类型的变量。这在规范的§3.11.4和§3.11.1部分中定义。
§3.11.4说:
S可分配给类型T,如果S没有相对于T(3.11.5)的多余属性并且以下之一为真,则可从S分配T:
- S是对象类型,交集类型,枚举类型或Number,Boolean或String基元类型,T是对象类型,对于T中的每个成员M,以下之一为真:
- M是属性,S具有表观属性N
- M和N具有相同的名称,
- N的类型可分配给M,
- 如果M是必需属性,则N也是必需属性,
- M和N都是公共的,M和N都是私有的,并且起源于同一个声明,M和N都受到保护并且起源于同一个声明,或者M受到保护,N被声明在派生自声明M的类。
- M是可选属性,S没有与M同名的明显属性。
- M是一个非专用的调用或构造签名,S有一个明显的调用或构造签名N,当M和N使用类型Any实例化为M和N声明的所有类型参数的类型参数时(如果有的话) )
- 签名属于同一类型(调用或构造),
- M有一个rest参数或N中非可选参数的数量小于或等于M中的参数总数,
- 对于两个签名中都存在的参数位置,N中的每个参数类型都可以分配给M中的相应参数类型,或者
- M的结果类型为Void,或者N的结果类型可分配给M的结果类型。
- M是U类型的字符串索引签名,U是Any类型,或者S具有可分配给U的类型的明显字符串索引签名。
- M是U类型的数字索引签名,U是Any类型,或者S具有可分配给U的类型的明显字符串或数字索引签名。
然后§3.11.1说:
基本类型String的明显成员和所有字符串文字类型是全局接口类型“String”的明显成员。
拉出相关部分:
S (在我们的情况下为
string
)可分配给类型T (在我们的例子中为String
) ...如果S有没有多余的属性相对于T,...... S是...数字,布尔或字符串基元类型,T是对象类型...并且对于T中的每个成员M ... M是属性和S具有明显的属性N,其中...... M和N具有相同的名称; N的类型可赋予M的类型;如果M是必需的财产,N也是必需的财产;而且M和N都是公开的......
...因为string
的明显成员是String
明显的成员。