为什么将联合类型赋予变量和将相同类型赋予参数如此不同?
Why are giving a union type to a variable and giving the same type to a parameter so different?
使用 tsc --strict
命令我得到以下错误:
error TS2339: Property 'foo' does not exist on type 'T'. Property
'foo' does not exist on type 'Bar'. 16 console.log(obj.foo)
我不明白的是为什么我可以将对象文字分配给 obj
但在函数内部使用相同的 属性 会出错。谢谢!
type Foo = {
foo: string
xyz: string
}
type Bar = {
bar: string
xyz: string
}
type T = Foo | Bar
let obj: T = { foo: "foo", xyz: "xyz" }
const sayHello = (obj: T) => {
console.log(obj.foo)
}
当您分配给联合时,您可以分配联合中的任何一种构成类型。这就是赋值成功的原因
当您尝试访问联合类型的 parameter/variable 时,您实际上 不知道 哪个联合组成类型实际上包含在其中。它们可能会枯萎,因此 typescript 认为仅安全访问联合所有成员共有的属性。在您的示例中,访问 xyz
是安全的,因为它存在于两个联合成分中
您需要使用 type guard 才能使编译器将参数类型缩小为一种或另一种构成类型:
const sayHello = (obj: T) => {
console.log(obj.xyz) // ok common
if ('bar' in obj) {
obj.bar // ok
} else {
obj.foo //ok
}
}
类型 Foo
比类型 Foo | Bar
更具体。如果你有一个可以放入 Foo | Bar
的盒子,那么你可以将 Foo
放入那个盒子,没问题。变量 obj
和同样命名为 obj
的参数在这方面是相同的;您可以将 Foo
或 Bar
分配给变量,并且可以使用 Foo
或 Bar
作为参数调用函数。
不同之处在于当您尝试从类型为 Foo | Bar
的 obj
获取 obj.foo
时。 .foo
属性 仅在 Foo
类型的事物上定义;但是参数 obj
不一定是 Foo
,它可能是 Bar
,所以它不一定有 .foo
属性。这就是您收到错误的原因。
但是,如果您尝试在函数外部使用类型为 T
的变量执行 console.log(obj.foo);
,您将得到相同的错误。与是否为参数无关
在您的特定代码中,您没有看到此错误,因为即使您声明 obj
的类型为 T
,Typescript 也知道您已将 Foo
分配给它,因此由于控制流类型缩小,变量在分配后实际上是 Foo
类型,并且在重新分配变量之前将保持原样。如果您更改声明以避免使用 as T
类型断言缩小,则错误将按预期出现:
let obj: T = { foo: "foo", xyz: "xyz" } as T
console.log(obj.foo); // type error
使用 tsc --strict
命令我得到以下错误:
error TS2339: Property 'foo' does not exist on type 'T'. Property 'foo' does not exist on type 'Bar'. 16 console.log(obj.foo)
我不明白的是为什么我可以将对象文字分配给 obj
但在函数内部使用相同的 属性 会出错。谢谢!
type Foo = {
foo: string
xyz: string
}
type Bar = {
bar: string
xyz: string
}
type T = Foo | Bar
let obj: T = { foo: "foo", xyz: "xyz" }
const sayHello = (obj: T) => {
console.log(obj.foo)
}
当您分配给联合时,您可以分配联合中的任何一种构成类型。这就是赋值成功的原因
当您尝试访问联合类型的 parameter/variable 时,您实际上 不知道 哪个联合组成类型实际上包含在其中。它们可能会枯萎,因此 typescript 认为仅安全访问联合所有成员共有的属性。在您的示例中,访问 xyz
是安全的,因为它存在于两个联合成分中
您需要使用 type guard 才能使编译器将参数类型缩小为一种或另一种构成类型:
const sayHello = (obj: T) => {
console.log(obj.xyz) // ok common
if ('bar' in obj) {
obj.bar // ok
} else {
obj.foo //ok
}
}
类型 Foo
比类型 Foo | Bar
更具体。如果你有一个可以放入 Foo | Bar
的盒子,那么你可以将 Foo
放入那个盒子,没问题。变量 obj
和同样命名为 obj
的参数在这方面是相同的;您可以将 Foo
或 Bar
分配给变量,并且可以使用 Foo
或 Bar
作为参数调用函数。
不同之处在于当您尝试从类型为 Foo | Bar
的 obj
获取 obj.foo
时。 .foo
属性 仅在 Foo
类型的事物上定义;但是参数 obj
不一定是 Foo
,它可能是 Bar
,所以它不一定有 .foo
属性。这就是您收到错误的原因。
但是,如果您尝试在函数外部使用类型为 T
的变量执行 console.log(obj.foo);
,您将得到相同的错误。与是否为参数无关
在您的特定代码中,您没有看到此错误,因为即使您声明 obj
的类型为 T
,Typescript 也知道您已将 Foo
分配给它,因此由于控制流类型缩小,变量在分配后实际上是 Foo
类型,并且在重新分配变量之前将保持原样。如果您更改声明以避免使用 as T
类型断言缩小,则错误将按预期出现:
let obj: T = { foo: "foo", xyz: "xyz" } as T
console.log(obj.foo); // type error