TypeScript中的动态类型

时间:2018-12-28 17:53:58

标签: typescript

如何根据类型变量的属性为通用类动态分配类型?例如

interface EntityErrors<T> {
    [p in keyof T]?: string; // How can I make "string" dynamic?  It needs to be a string for primitives (id, name), and an array of strings for the `teachers` array.

    // I've tried the following, but it appears `teachers` is still resolving to `SimpleError` instead of `ArrayOfErrors`.
    [p in keyof T]?: p extends [] ? ArrayOfErrors<p> : SimpleErrors;
    // I've also tried `instanceof` and `typeof`, but I receive syntax errors.
    [p in keyof T]?: p instanceof [] ? ArrayOfErrors<p>: SimpleErrors;
}

interface School {
    id: string;
    name: string;
    teachers: Teacher[];
}

interface Teacher {
    id: string;
    name: string;
}

因为School错误对象看起来像:

{
  "id": "The input is invalid",
  "name": "The input is invalid",
  "teachers": [
    {
      "id": "The input is invalid",
      "name": "The input is invalid"
    },
    {
      "id": "The input is invalid",
      "name": "The input is invalid"
    }
  ]
}

2 个答案:

答案 0 :(得分:2)

p是带有属性名称的字符串类型。

您需要检查类中属性的类型:

    [p in keyof T]?: T[p] extends [] ? ArrayOfErrors<T[p]>: SimpleErrors;

答案 1 :(得分:1)

根据您的要求,事情会变得更加复杂,因为错误类型需要递归。如果遇到原始数组或原始属性,则结果类型中的属性将为字符串。如果我们有一个实体或一个实体数组,我们需要递归地应用类型以获得适当的结果。

为此,我们需要使用映射类型。属性的类型为T[P],其中P为属性名称

type EntityErrors = {

    [P in keyof T]?:ErrorProperty<T[P]>
}
type Primitive = number| string| Date | boolean
type ErrorProperty<T> =
    T extends Primitive ? string :
    T extends Array<Primitive> ? string[] :
    T extends Array<infer U> ? Array<EntityErrors<U>> :
    EntityErrors<T>;


interface School {
    id: string;
    name: string;
    teachers: Teacher[];
}

interface Teacher {
    id: string;
    name: string;
}

let e:EntityErrors<School> = {
"id": "The input is invalid",
"name": "The input is invalid",
"teachers": [
    {
    "id": "The input is invalid",
    "name": "The input is invalid"
    },
    {
    "id": "The input is invalid",
    "name": "The input is invalid"
    }
]
}