以下TypeScrip中的示例代码片断使用mapper
对象将数组arr
的值映射到Mappings
中包含的类型,该对象包含每个arr
项的转换器函数:(Playground)
const arr = ["foo", "12", 42] as const;
type Mappings = { foo: boolean, "12": number, 42: string };
type MapperArgs<K extends (typeof arr)[number]> = {
v: K,
i: number
};
const mapper: {
[K in (typeof arr)[number]]: (o: MapperArgs<K>) => Mappings[K]
} = {
foo: ({ v, i }) => v.length + i > 4,
"12": ({ v, i }) => Number(v) + i,
42: ({ v, i }) => `${v}${i}`,
}
要在所有项目上运行mapper
,通常的arr.map
不会像预期的那样工作:
arr.map((v) => mapper[v]({ v })); /* TS error 2345: ... intersection was reduced to 'never' because ... has conflicting types in some constituents */
显然,这是因为TypeScripts limitations regarding correlated union types美元.可以使用通用函数来解决此问题:
const resolveMapper = <K extends keyof typeof mapper>(key: K, o: MapperArgs<K>) => mapper[key](o);
arr.map((v, i) => resolveMapper(v, { v, i })); // ok ✅
但是,在将某些映射设置为可选后,这将不起作用:
type SetOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
// ...
const mapper: SetOptional<{
[K in (typeof arr)[number]]: (o: MapperArgs<K>) => Mappings[K]
}, "foo"> = /* ... */
const resolveMapper = <K extends keyof typeof mapper>(key: K, o: MapperArgs<K>) => mapper[key]?.(o); /* not ok ❌ */
有没有办法在不 suppress 错误或使用类型断言/any
的情况下解决这个问题?