TypeScript从其他类型动态派生的字段

时间:2019-06-11 07:37:45

标签: typescript

export type Foo = {
  a: boolean
  b: number
}

我想基于Foo创建另一种类型,但是在其字段名称中添加前缀:

export type Foo2 = {
  bar_a: boolean
  bar_b: number
}

有可能吗?

1 个答案:

答案 0 :(得分:2)

从TypeScript 3.5开始,您不能以编程方式执行此操作。有open issue in GitHub表示可以扩展映射类型中的键。如果您对此很在意,则可能会想去那里给它一个?或描述您的用例,如果您认为它比这里的内容更具吸引力。


同时,您唯一可以做的就是自己手动维护这样的映射。有很多可能的方法来实现映射类型来转换键,并且对此有很多警告。映射类型旨在转换属性 values 而不是 keys ,因此TypeScript提供给我们的工具并不完全适合该任务。不过,这是一种实现方法:

// MapKeys<T, M> takes an object type T and a key map M  and produces 
// a new type whose keys are mapped from M (or left alone if they are not in  M)
//
// Thus MapKeys<{a: 0, b: 1}, {a: "A", z: "Z"}> becomes {A: 0, b: 1}
//
// The following is one of many possible implementations. 
// It does not properly deal well with optional properties, e.g., {a?: number}
// and types with index-signature properties, e.g., {[k: string]: number}
// (these can be worked around with even more complexity)
type MapKeys<T extends object, M extends Record<keyof M, keyof any>> = {
  [K in keyof T]-?: (a: { [P in K extends keyof M ? M[K] : K]: T[K] }) => void
}[keyof T] extends (a: infer U) => void
  ? { [K in keyof U]: U[K] }
  : never;

让我们看看它是否适用于您的类型:

export type Foo = {
  a: boolean;
  b: number;
};

type KeyMap = {
  a: "bar_a";
  b: "bar_b";
  c: "bar_c";
  d: "bad_d";
  // etc
};

export type Foo2 = MapKeys<Foo, KeyMap>;
// type Foo2 = {
//    bar_a: boolean;
//    bar_b: number;
// }

看起来不错。好的,希望对您有所帮助。祝你好运!

Link to code