我理解ts中的联合类型可以允许变量有多种类型。
type Test1 = never | any;
// Any is the top-level type
// Test1 = any
type Test2 = "123" | string;
// String is the collection of all strings
// Test2 = string
类型T=A | B
,当A和B结合时当A(“广义类型”)包含B(“具体类型”)时,则得出A(“广义类型”)。
然后,当我应用“对象联合”的结论时,我对父子类型有疑问。
interface A1 {
name: string
}
interface A2 extends A1 {
age: number
}
type Test3 = A2 | A1;
// According to the conclusion, A2 is broader than A1, Test3 = A2
// Not equal to A2
/* Here I explain that when the value corresponding to Test3 is {name: "??"},
the mandatory item age attribute type in A2 type is unsafe
/
// According to the above explanation, I try to add options to A2. Will the result be different?
type Test4 = A1 | Partial<A2>;
// but, Not equal to A2 ?
type TypeKeys = keyof Test3;
// Why do I get such a result when I try to get the key
// TypeKeys = "name"
应用程序函数返回时也有问题
const record: Test3 = {
name: 'name',
age: 20
}
const record2: Test3 = {
name: 'name'
}
// Finally, I use Test3 type for function return
const fn = (): Test3 => record;
const da = fn();
da.name
da.age // The type shown here is unsafe
// Property 'age' does not exist on type 'Test3'.
// Property 'age' does not exist on type 'A1'
2条答案
按热度按时间ecfdbz9o1#
Test2
和Test3
之间存在概念上的差异:"123"
已经存在于string
集合中,即"123"
**是string
集合的子集。因此,该并集可以有效地折叠到string
集合中A1
不是A2
的子集,反之亦然,尽管乍一看这似乎违反直觉:A1
是具有单一属性name: string
的对象A2
是具有两个属性name: string
和age: number
的对象A1 | A2
时,编译器最多只能解析为A1
或A2
,但肯定不能同时满足这两种定义。discriminated unions
之类的东西定义
record
和record2
时,将执行以下操作:record
和record2
注解为Test3
,其等效于A1 | A2
。A2
形式的对象传递给record
,编译器对此非常满意,因为这是一个有效的A1 | A2
。重要的是,并不是record
在幕后变成了A2
,它仍然是A1 | A2
A1
形状的对象传递给record2
,编译器对此非常满意,因为这是一个有效的A1 | A2
。let
而不是const
会更容易形象化;只要变量在其生命周期内被赋值为A1
或A2
形式的内容,编译器就会保持满意(即使它开始时是A2
,将来也可能是A1
等)当所有的都说了和做了之后,尽管
record
和record2
中的对象的内容对我们来说显然分别是A2
和A1
,由于注解Test3
,编译器不可能推断出底层对象是A1
还是A2
。关于Test3
,它所能推断的是,不管当前值是多少,它都将具有name: string
属性,它不知道age: number
属性是存在还是缺失,因为这将取决于关于对象是A1
还是A2
的知识。此问题的常见解决方案是使用
type guard
"解包"类型,例如:这显式地通知编译器正在使用运行时构造的基础类型的形状,因此即使变量的值要更改,它仍然能够保证类型安全。
现在应该可以理解为什么编译器不接受从
fn
定义中Test3
类型的变量访问名为age
的属性了。以下备选方案均有效
一个二个一个一个
https://tsplay.dev/w1AeGw
zlhcx6iw2#
当您使用Test3的keyof时,TypeScript尝试获取Test3类型的键,即A2,因此它返回A2接口中的键,即仅“name”。
你可以通过使用类型保护来解决这个问题,检查返回的对象是否有age属性,