通过值的匹配属性将对象投射到另一个对象

时间:2019-05-22 02:00:20

标签: typescript types casting typescript-typings

我需要根据一些规则将一个对象转换为另一个对象。

  • Types枚举;
  • 有两个接口ColorNumber;
  • 存在ValuesByType接口,其中Types枚举映射到接口ColorNumber
  • 三个是source对象(字典/记录),具有type枚举的Types属性。

我需要为convert函数编写类型,该函数返回一个具有与source对象相同键的新对象,但值应引用到映射到ValuesByType的接口。

示例:

interface Color {}
interface Number {}

enum Types {
  Color,
  Number,
}

interface ValuesByType {
  [Types.Color]: Color,
  [Types.Number]: Number,
}

interface SourceValue<T extends Types = Types> {
  type: T;
}


// Need to define types for this function
function convert(source: SourceValue) {
  ...
}

const source: SourceValue = {
  foo: {
    type: Types.Color,
  },
  bar: {
    type: Types.Number,
  },
};

const result = convert(source);

// The type of "result" veriable should be:
// {
//     foo: Color,
//     bar: Number
// }

我尝试过这种方法,但是它不起作用:

export type Convert = <
  T extends Types,
  S extends Record<keyof S, SourceValue<T>>
>(
  source: S,
) => Record<keyof S, ValuesByType[T]>;


1 个答案:

答案 0 :(得分:1)

解决此问题时要解决的一个问题是输入_sources对象的类型。在您的TS Playground链接上,当前键入为:

const _source: { 
  foo: { type: Types; }; 
  bar: { type: Types; };
};

注意如何将type参数设置为Types而不是具体的Types.ColorTypes.Number

在Typescript 3.4上,您可以通过在定义之后添加as const来解决此问题:

const _source = {
  foo: { type: Types.Color },
  bar: { type: Types.Number },
} as const;

或者,在3.4之前,您可以使用Types.Color as Types.Color来获取打字稿,将其视为文字值。

清除后,“映射类型”将获取您需要的返回值。我将其编写为通用帮助程序类型。

type ConvertedSources<T extends Record<string, SourceValue<any>>> = {
  [key in keyof T]: ValuesByType[T[key]['type']]
};

如果将typeof _source传递给它,您将看到_source中的每个属性如何基于您的ValuesByType接口映射到相应的值类型。

然后,您只需要让函数在其签名中使用它,并保留相同的类型约束即可即可:

function convert<
  TSources extends Record<string, SourceValue<any>>
  >(source: TSources): ConvertedSources<TSources> { ... }

请注意,您还需要将reduce()调用的结果强制转换为ConvertedSources<TSources>,或更改一些内部代码以保留类型。

TS Playground Demo