打字稿,将一个对象映射到另一个对象?

时间:2020-02-19 07:09:47

标签: typescript

我有两个对象,我的自定义map函数将一个对象的prop映射到另一个对象的值,例如:

const obj1 = {
  host: 'clientNameHost',
  pass: 'clientNamePass',
};

const obj2 = {
  clientNamePass: '12345',
  clientNameHost: 'http://localhost:3000',
};

const mapParams = <T, K>(source: T, params: K) => Object.entries(params)
.reduce((acc, [param, sourceProp]) => ({ ...acc, [param]: source[sourceProp] }), {});

mapParams(obj2, obj1) //{host: "http://localhost:3000", pass: "12345"}

我很难输入此函数。有什么方法可以正确键入mapParams函数吗?

2 个答案:

答案 0 :(得分:0)

解决方案是缩小泛型类型,以显示两个参数中键和值之间的关系:

const obj1 = {
    host: 'clientNameHost',
    pass: 'clientNamePass',
  } as const;

  const obj2 = {
    clientNamePass: '12345',
    clientNameHost: 'http://localhost:3000',
  } as const;

  const mapParams = <T extends Record<string, any>, K extends keyof T, P extends Record<T[K], any>>(source: T, params: P) => Object.entries(params)
  .reduce((acc, [param, value]) => ({ ...acc, [param]: source[value as T[K]] }), {});

  console.log(mapParams(obj1, obj2)) //{host: "http://localhost:3000", pass: "12345"}

关键部分:

  • T extends Record<string, any>的第一种类型是带有字符串键的记录
  • K extends keyof T代表T
  • 的键
  • P extends Record<T[K], any>的关键部分-我们希望对象在T中具有相等的键值
  • 添加了
  • as const是为了正确推断缩小的类型

以上类型会在第一个参数值和第二个参数键之间创建一个边界。

PS。很抱歉还原参数顺序。

答案 1 :(得分:0)

在键入函数时,我最关心的是参数和返回类型。

您可以这样输入参数:

<InputProps, TargetProps extends Record<keyof TargetProps, keyof InputProps>>(
  source: InputProps,
  params: TargetProps
) => ...

如果第二个对象与第一个对象不匹配,Typescript将抱怨。

对于返回值,您可以定义以下实用程序类型:

type MapFrom<A, B> = Record<keyof A, B[keyof B]>;

通过使用Object.proptotype.entries类型的参数,我们不必强制转换sourceProp

要保留函数签名,我们需要在reduce中声明initialValue的类型。

我还使用const断言为对象文字赋予只读属性

这是完整的结果:

type MapFrom<A, B> = Record<keyof A, B[keyof B]>;

const obj1 = {
  host: "clientNameHost",
  pass: "clientNamePass"
} as const;

const obj2 = {
  clientNamePass: "12345",
  clientNameHost: "http://localhost:3000"
} as const;

const mapParams = <InputProps, TargetProps extends Record<keyof TargetProps, keyof InputProps>>(
  source: InputProps,
  params: TargetProps
) =>
  Object.entries<keyof InputProps>(params).reduce(
    (acc, [param, sourceProp]) => ({
      ...acc,
      [param]: source[sourceProp]
    }),
    {} as MapFrom<TargetProps, InputProps>
  );

const obj3 = mapParams(obj2, obj1);

Here,您可以尝试一下。