是否可以在打字稿中扩展类型的道具?

时间:2020-02-23 21:17:40

标签: typescript

考虑下一个示例:

enum Keys {
  A = 'a',
  B = 'b',
  C = 'c',
}
//imagine a lot more possible keys

type ExtendKeysPropsByKey = {
  [Keys.A]: {
    a: string
  }
  [Keys.B]: {
    b: string
  }
}
//Keys.C doesn't require extended props

type KeysPropsByKey = {
  [key in keyof Keys]: {
    key: key
  } & ExtendKeysPropsByKey[key]
  //errors: Type 'key' cannot be used to index type 'ExtendKeysPropsByKey'.
  //also tried:
  //ExtendKeysPropsByKey[key] ? ExtendKeysPropsByKey[key] : {}
  //ExtendKeysPropsByKey[key] || {}
  //key in keyof ExtendKeysPropsByKey ? ExtendKeysPropsByKey[key] : {}
  //neither works
}

因此,假设有50种可能的Keys,我们想创建一个类型,该类型最初包含一个key实际值的Keys道具,并且希望能够(可选)扩展道具,因此上述示例的预期类型为:

{
  [Keys.A]: {
    key: Keys.A
    a: string
  }
  [Keys.B]: {
    key: Keys.B
    b: string
  }
  [Keys.C]: {
    key: Keys.C
  }
}

任何可能的情况?

1 个答案:

答案 0 :(得分:2)

希望我能满足您的要求:)。因此,我制作了一个带有两个参数的类型构造函数-Keys-它定义了我们将拥有的键,KeyProps-类型代表了给定键应具有的道具。

enum Keys {
  A = 'a',
  B = 'b',
  C = 'c',
}

type ExtendKeysPropsByKey = {
  [Keys.A]: {
    a: string
  }
  [Keys.B]: {
    b: string,
    c: number;
  }
}

type MakeT<Keys extends string, KeyProps extends Partial<Record<Keys, any>>> = {
  [K in Keys]: {key: K} & (K extends keyof KeyProps ? KeyProps[K] : {})
}

type Result = MakeT<Keys, ExtendKeysPropsByKey>
/**
type Result = {
    a: {
        key: Keys.A;
    } & {
        a: string;
    };
    b: {
        key: Keys.B;
    } & {
        b: string;
        c: number;
    };
    c: {
        key: Keys.C;
    };
}
*/

说明:

  • KeyProps extends Partial<Record<Keys, any>>我们将第二个参数定义为具有所需键的记录,但由于不是我们需要的所有键,它也是局部的。
  • {key: K} & (K extends keyof KeyProps ? KeyProps[K] : {})我们说给定键的值将具有key等于键的属性,并且将其与KeyProps对象中给出的道具相交