【问题标题】:Typescript error when default clause of switch for an unkown union type未知联合类型的 switch 的默认子句时打字稿错误
【发布时间】:2019-10-29 10:55:47
【问题描述】:

我正在从一个文件中读取数据,其中的数据可能比我的代码关心的要多。对于要处理的每种对象类型,我都有一个打字稿类型。但是对于某些不受支持的对象类型,我想对那个对象做点什么。

问题是打字稿认为我已经用尽了所有的可能性,我的默认子句是不可能的。

// Untyped example data source.
function loadFromSomeFile(): any {
  return [{ objType: "A", a: 1 }, { objType: "B", b: 2 }] as any
}

// Union type of supported data from data source.
type A = { objType: "A", a: number }
type B = { objType: "B", b: number }
type ObjTypes = A | B

// Load the data.
const arr: ObjTypes[] = loadFromSomeFile()

// Switch on the type of each object. 
for (const obj of arr) {
  switch (obj.objType) {
    case "A":
      console.log('A', obj.a)
      break
    case "B":
      console.log('B', obj.b)
      break
    default:
      // Fall though case for unsupported objType
      console.log('unkown objType: ' + obj.objType)
      // ^ TS Error: objType does not exist on type 'never'
  }
}

Error on Typescript Playground

我想过尝试向联合中添加第三个选项,例如:

type X = { objType: string } // unknown
type ObjTypes = A | B | X

但是现在当obj.objType === 'A' typescript 无法判断它是A 还是X,因为它对两者都是有效的类型。

我如何告诉 typescript 可能还有未知和未处理的值,并且我的列表并不详尽?

【问题讨论】:

  • type Other = { objType: any } type ObjTypes = A |乙|其他
  • @DanielA.White 好吧,这消除了这个错误,但似乎 TS 实际上并没有推断出正确的类型,因为如果我尝试访问已知类型的属性,现在就会出错。我已经更新了问题中的代码以涵盖这种情况。
  • 我能想到的最好的方法是type ObjTypes = A | B | {objType?: never},但它需要strictNullChecks,并且它在默认子句中推断undefined 类型为obj.objType - 不知道如何声明类型所以它将在string 那里而不影响其他分支,缺少类型断言。

标签: typescript


【解决方案1】:

在纠结了一段时间后,我决定给未知类型一个具有固定值的具体类型,这是不正确的。

type A = { objType: "A", a: number }
type B = { objType: "B", b: number }
type Unknown = { objType: '___unknown-obj-type___' }
type ObjTypes = A | B | Unknown

这会导致 switch 的默认子句落入此类型。而且我仍然可以在运行时访问对象属性以获取实际值。

感觉有点像 hack,但到目前为止,这对代码可读性的妥协最少,恕我直言。

Typescript Playground

【讨论】:

    【解决方案2】:

    由于您不仅可以从文件中获取 A 或 B,因此不要将类型声明为 A | B.

    Playground

    【讨论】:

      【解决方案3】:

      使用:

      return [
          { objType: "A", a: 1 }, 
          { objType: "B", b: 2 },
          { objType: "C" }
          { foo: "bar" }
      ] as any
      

      作为数据,并将类型设置为:

      type ObjTypes = A | B | any
      

      然后,在每个 case 块内,将对象转换为预期的类型,AB 等。

      case "A":
        let a = <A>obj;
        console.log('A', a.a)
        //console.log('A', a.x) // TS error! 
        break
      

      登录到控制台:

      A 1
      B 2
      unknown objType: C
      unknown objType: undefined
      

      查看更新的Typescript Playground

      【讨论】:

      • any 的联合允许访问任何类型对象的任何属性,而无需在编译时进行任何检查
      • 好吧,在case "A": 块内,您可以将对象转换为A 类型。将更新答案以包含此内容。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-06
      • 1970-01-01
      • 2017-08-04
      相关资源
      最近更新 更多