Typescript 联合类型 - 字段类型覆盖

问题描述 投票:0回答:1

我有以下示例代码,但我不清楚其行为。

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)
}

ababc作业上存在打字稿错误,这让我感到惊讶。我希望以下类型是相似的 AORB = AORBField = BaseTypes 至少在我们可以分配给它们的上下文中。显然只有 AORB 才能正确推断“If else”语句的类型。

我未能在 TS 文档中找到解释,有人可以在这里启发我吗?

typescript typescript-typings union-types
1个回答
0
投票

这不是对象类型联合的工作方式,并且在大多数情况下,这也不是您“希望”它们工作的方式(尽管您的特定情况可能是例外)。您的 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

游乐场

© www.soinside.com 2019 - 2024. All rights reserved.