Typescript递归通用对象映射功能

时间:2019-02-08 20:47:45

标签: typescript generics recursion

我想知道是否可以键入此功能。我递归地检查对象内部的值的类型(shouldReplace是类型保护),并将该值传递给函数fn

const replaceInObject = (shouldReplace, fn) => {
  const recurse = object => {
    for (const [key, val] of Object.entries(object)) {
      if (shouldReplace(val)) object[key] = fn(val)
      else if (Array.isArray(object)) object[key] = val.map(recurse)
      else if (typeof object === 'object') object[key] = recurse(val)
    }
  }
  return recurse
}

为清楚起见,这是一个示例用法:

const isEs6Map = (val: any): val is Map<any, any> => val instanceof Map
const es6MapToObject = <K, V>(map: Map<K, V>): { [key: string]: V } => {
  const obj: { [key: string]: V } = {}
  for (const [key, val] of map) obj[key.toString()] = val
  return obj
}
const marshal = replaceInObject(isEs6Map, es6MapToObject)

const sampleInput = {
  m: new Map([['a', 1], ['b', 2]]),
  meta: 'info',
  children: [
    {
      m: new Map([['c', 3], ['d', 4]]),
      meta: 'child'
    }
  ]
}

const serializedData = marshal(sampleInput)

用例本质上是创建一个通用的编组函数。我使用Google地图将对象存储在内存中,并且希望通过网络发送这些对象,以便可以在Web UI中查看它们。我需要将所有类转换为纯数据对象,以便可以通过JSON.stringify对其进行正确的序列化。

如果无法键入此函数,我当然可以通过几个特定于每个输入对象的序列化函数和类型来完成相同的任务。但是,我希望可以避免编写使用此简单功能描述输出的类型。

这个stackoverflow问题是相关的,但不涉及递归或选择要替换的值。 Typescript: Generic object mapping function

1 个答案:

答案 0 :(得分:0)

我想我去做些事。您必须在sampleInput的值上应用递归映射。

所以输入类型看起来像这样: type Input = { meta: string, m: Map<string, number>, children?: Array<Input> };

让我们使用输入作为输入的通用类型并返回解析后的一个:

type Parse<I extends Input> = {
    [K in keyof I]: I[K] extends Map<any, infer Value>
     ? { [key: string]: Value } : I[K] extends Array<any>
  ? Array<Parse<I[K][number]>> : I[K]
}

我们需要3种情况:用于字符串,映射和数组。通过A extends B ? :语法,我们可以根据类型应用不同的逻辑,因此:

string => string
Map<K, V> => { [K]: V }
Array<Item> => Array<Parse<Item>

Playground