为什么typescript会扩大属性';即使在显式设置的情况下,是否仍为s类型?
考虑一下这段简单的代码,它为为什么typescript会扩大属性';即使在显式设置的情况下,是否仍为s类型?,typescript,Typescript,考虑一下这段简单的代码,它为人定义了一个接口,然后创建了该类型的对象: 接口人{ 名称:字符串|编号 } 警察约翰:人={ 姓名:“约翰” } 现在我希望john.name是一个字符串。然而,令我惊讶的是,即使在分配了字符串之后,该属性的类型仍然是: function greet(name: string) { console.log(`Hello ${name}`) } greet(john.name) // Argument of type 'string | number' i
人定义了一个接口,然后创建了该类型的对象:
接口人{
名称:字符串|编号
}
警察约翰:人={
姓名:“约翰”
}
现在我希望john.name
是一个字符串
。然而,令我惊讶的是,即使在分配了字符串之后,该属性的类型仍然是:
function greet(name: string) {
console.log(`Hello ${name}`)
}
greet(john.name) // Argument of type 'string | number' is not assignable to parameter of type 'string'.
// Type 'number' is not assignable to type 'string'.(2345)
我甚至试图通过强制name
的类型为string
来迫使编译器看清真相,但没有成功:
const john: Person = {
name: "John" as string
}
greet(john.name) // Argument of type 'string | number' is not assignable to parameter of type 'string'.
// Type 'number' is not assignable to type 'string'.(2345)
有人能解释一下这种行为吗?TypeScript扩展了类型,给出了此代码的错误:
interface Person {
name: string | number
}
const john: Person = {
name: "John"
}
john.name = 0
function greet(name: string) {
console.log(`Hello ${name}`)
}
greet(john.name)
john
的类型仅被检查为Person
您可能想知道您的示例失败的原因:
const john: Person = {
name: "John"
}
greet(john.name) // error!
// -> ~~~~~~~~~ "(string | number) is not assignable to string"
而以下工作:
const name: string | number = "John";
greet(name); // okay
或者这个:
john.name = "Still John";
greet(john.name); // okay
是TypeScript的一项功能,通过该功能,类型检查器可以推断某个较宽类型的变量可以暂时视为某个较窄类型的变量。因此,如果我有一个变量name
声明为typestring | number
,我可以将任何string
或number
分配给它:
name = Math.random() < 0.5 ? 0.007 : "James Millibond";
在代码的name.toUpperCase()
部分,编译器将name
的类型缩小为string
,在name.toExponential(0)
部分,编译器将name
的类型缩小为number
。这是正在进行的控制流分析
当您将string
或number
类型的值分配给string | number
类型的变量时,编译器会将该变量的类型缩小为string
或number
,直到您将新值分配给该变量。这也是由于控制流分析
TypeScript控制流分析的一个重要限制是:只有联合类型被缩小如果变量不是联合类型,它将不会缩小。而string | number
是联合类型,而Person
不是。是的,Person
的name
属性属于联合类型,但这并不使Person
成为联合类型
因此,分配john
本身不会缩小范围,但分配john.name
会缩小范围
为什么编译器不缩小非并集类型?我能找到的最接近标准答案是控制流分析算法的实现者:
缩小赋值上的非并集类型的问题是我们仍在思考的问题。它变得有些复杂,因为。。。当涉及可选属性时,分配的类型实际上可能比声明的类型具有更少的成员
有人建议控制流分析也应用于非联合类型。如果你对此有强烈的感觉,你可能想给这个问题一个参数问题
我认为您的错误来自此函数:
function greet(name: string) {
console.log(`Hello ${name}`)
}
对于参数,您仅定义为string
,但您的类型是string | number
执行以下操作将修复错误:
function greet(name: string | number) { // add number here =)
console.log(`Hello ${name}`)
}
它是如何运行的
当您运行其中一个时,它将工作:
const john: Person = {
name: "John"
};
const sam: Person = {
name: 1
};
输出:
greet(john.name); // Hello John
greet(sam.name); // Hello 1
问题是为什么您希望它在这里缩小类型,通过编写:string | number
您告诉TS这个属性可以是string或number。TS进行静态类型检查,因此每当它找到Person.name
时就会应用这个规则。这确实是我想知道的。谢谢你的详细回答。
greet(john.name); // Hello John
greet(sam.name); // Hello 1