在TypeScript中键入mapShape函数

问题描述 投票:1回答:1

我想使用这样的实用程序功能:

const out = mapShape(
  { foo: 1, bar: '2', baz: 'hello' },
  { foo: x => String(x), bar: x => parseInt(x) }
)
// outputs { foo: '1', bar: 2 }

是否有一种方法可以在TypeScript中对其进行参数化,以便输出的类型为this?

{ foo: string, bar: number }

我尝试这样做:

export default function mapShape<
  I extends Record<any, any>,
  X extends { [K in keyof I]: (value: I[K], key: K, object: I) => any }
>(
  object: I,
  mapper: Partial<X>
): {
  [K in keyof I]: ReturnType<X[K]>
} {
  const result: any = {}
  for (const key in mapper) {
    if (Object.hasOwnProperty.call(mapper, key)) {
      result[key] = (mapper[key] as any)(object[key], key, object)
    }
  }
  return result
}

然而,TS推断out的类型是{ foo: any, bar: any };它不会推断属性的特定类型。

以下代码会产生正确的输出类型,我不确定是否可以对其进行参数设置:

const mappers = {
  foo: x => String(x),
  bar: x => parseInt(x),
}
type outputType = {
  [K in keyof typeof mappers]: ReturnType<typeof mappers[K]>
}
// { foo: string, bar: number }
typescript type-inference
1个回答
0
投票

我认为表现最好的打字是这样的:

function mapShape<T extends { [K in keyof U]?: any }, U>(
    obj: T,
    mapper: { [K in keyof U]: K extends keyof T ? (x: T[K]) => U[K] : never }
): U {
    const result: any = {}
    for (const key in mapper) {
        if (Object.hasOwnProperty.call(mapper, key)) {
            result[key] = (mapper[key] as any)(obj[key], key, obj)
        }
    }
    return result
}

我正在使用inference from mapped types允许在U的键上将输出类型设置为mapper,将U对象设置为同构映射类型。

这将为out生成所需的输出类型,同时仍在映射器参数的回调属性中推断参数类型:

const out = mapShape(
    { foo: 1, bar: '2', baz: 'hello' },
    { foo: x => String(x), bar: x => parseInt(x) }
)
/* const out: {
    foo: string;
    bar: number;
} */

它还应防止向映射器添加在要映射的对象中不存在的属性:

const bad = mapShape(
    { a: 1 },
    { a: n => n % 2 === 0, x: n => n } // error!
    // ------------------> ~  ~ <----------
    // (n: any) => any is             implicit any
    // not never
)

好的,希望能帮助您继续;祝你好运!

Playground link to code

© www.soinside.com 2019 - 2024. All rights reserved.