我有以下示例代码,但我不清楚其行为。
type A = {
field: string
}
type B = {
field: number
}
//I expect A | B is equivalent to field: A["field"] | B["field"]
type AORB = A | B
type AORBField = {
field: A["field"] | B["field"]
}
type BaseTypes = {
field: number | string
}
//Toggle between AORB and AORBField
type AB = AORB;
//type AB = AORBField;
//type AB = BaseTypes
const isA = (t: AB): t is A => {
return typeof t.field === "string"
}
const isB = (t: AB): t is B => {
return typeof t.field === "number"
}
const test = (x: AB) => {}
const testA = (x: A) => {}
const testB = (x: B) => {}
const testString = (x: string) => {}
const testNumber = (x: number) => {}
const getField = () => {
const val = Math.random();
return Math.random() % 2 ? val.toString(): val
}
const getDummyObject = () => {
const val = Math.random();
return { field: Math.random() % 2 ? val.toString(): val }
}
//Why error?
const ab: AB = {
//field: 1 //This will pass for AORB
//field: "string" //This will pass for AORB
field: getField() //This will pass for AORBFields
}
//Why error?
const abc: AB = getDummyObject();
if (isA(ab)){
const a: A = ab;
testString(a.field)
testNumber(a.field) //Expected err
testA(a)
test(ab)
}
else
{
const b: B = ab; //This will fail for AORBField and BaseTypes, but that is expected since else statement cannot figure out main type
testString(b.field) //Expected err
testNumber(b.field)
testB(b)
test(ab)
}
ab和abc作业上存在打字稿错误,这让我感到惊讶。我希望以下类型是相似的 AORB = AORBField = BaseTypes 至少在我们可以分配给它们的上下文中。显然只有 AORB 才能正确推断“If else”语句的类型。
我未能在 TS 文档中找到解释,有人可以在这里启发我吗?
这不是对象类型联合的工作方式,并且在大多数情况下,这也不是您“希望”它们工作的方式(尽管您的特定情况可能是例外)。您的 getDummyObject
的返回类型是
{ field: string | number }
并且您不能将其分配给 A
或
B
,因此您也不能将其分配给联合 A | B
:它不能满足任一类型的并集。这两种类型并不像您希望的那样“混合”。type A = {
field: number
}
type B = {
field: string
}
type AB = A | B
// return type of getDummyObject
type Neither = {
field: string | number
}
type Test1 = Neither extends A ? A : never // never
type Test2 = Neither extends B ? B : never // never
type Test3 = Neither extends AB ? AB : never // never
如果你仔细想想,这是有道理的,既不是
A
也不是
B
的东西怎么可能被分配给 A
或 B
的东西呢?如果将getDummyObject
中的代码更改为
const getDummyObject = () => {
const val = Math.random();
return Math.random() % 2 ?
{ field: val.toString() } :
{ field: val };
}
然后就可以正常工作了
const foo: AB = getDummyObject(); // no error