如何在TypeScript中正确进行递归类型定义?

时间:2018-12-04 10:02:49

标签: typescript recursion types

我有一个由嵌套数组和对象组成的任意结构,ValidationError对象为叶子。要输入此内容,我需要一个Typescript guidelines中所示的递归类型。

虽然赋值(const x = ...)通过了类型检查,但是访问结构(x.errors.a)却出现了TypeScript错误,我无法理解:

  

错误:TS2339:类型'ValidationResultElement'上不存在属性'a'。

     

类型'ValidationResultObject'上不存在属性'a'。

see code on TypeScript Playground

export interface ValidationResult {
  errors: ValidationResultElement;
}

type ValidationResultElement =
  ValidationResultObject | ValidationResultArray | ValidationError;

interface ValidationResultArray extends Array<ValidationResultElement> {
}

interface ValidationResultObject {
  [key: string]: ValidationResultElement;
}

interface ValidationError {
  details: string;
}

// This works:
const x: ValidationResult = {
    errors: { a: { b: [{ c: { details: 'foo' } }] } }
};

// This produces a type error:
console.log(x.errors.a);

1 个答案:

答案 0 :(得分:1)

您需要缩小类型。这是一个例子,但我有警告!

function isValidationResultObject(obj: any): obj is ValidationResultObject {
  return (obj && (!obj.type) && (!obj.length));
}

if (isValidationResultObject(x.errors)) {
  console.log(x.errors.a);
}

我已经定制了一个自定义类型防护以消除其他类型,但这可能是错误的,它只是演示了这个概念。您需要编写一个有效的类型防护。

您可能会发现,有区别的联合类型使研究大量属性变得更加容易。

您可以使用断言来强制缩小类型,但是类型保护更为诚实,可以确保您确实在处理所需的类型。