Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/docker/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么typescript会扩大属性';即使在显式设置的情况下,是否仍为s类型?_Typescript - Fatal编程技术网

为什么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
声明为type
string | 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