我想使用这样的实用程序功能:
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 }
我认为表现最好的打字是这样的:
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
)
好的,希望能帮助您继续;祝你好运!