我想实现动态值映射:
type A = { name: string; age: number; dictionary: { type: 'Dictionary'; id: string; name: string } }
至:
type B = { name: string, age: number; dictionary: { label: string; value: string } }
使用 lodash 地图值:
const mapData = (data) => {
if (!data) { return {} }
return mapValues(data, cb)
}
其中回调指的是:
const cb = (value: string | boolean | number | null | Dictionary) => {
if (typeof fieldValue === 'string') {
return fieldValue as string;
}
if (typeof fieldValue === 'boolean') {
return fieldValue as boolean;
}
if (typeof fieldValue === 'number') {
return fieldValue as number;
}
if (fieldValue === null) {
return null;
}
if (has(fieldValue, 'type')) {
return mapDictionary(fieldValue)
}
}
const mapDictionary = ({ id, name }: Dictionary) => ({ label: name, value: id })
问题: mapValues 无法识别输入/输出的内容。
我可以更轻松地以通用方式进行映射吗?它将推断原始输入对象的键,但在映射后具有新的值类型?
您可以使用映射类型、条件类型和
infer
关键字来实现此目的。
type MyType = { name: string; age: number; dictionary: { type: 'Dictionary'; id: string; name: string } }
type MyTypeMoreSpecific = { name: string; age: number; dictionary: { type: 'Dictionary'; id: 'static id'; name: 'static name' } }
type Convert<T extends {}> = {
[key in keyof T]: ConvertField<T[key]>
}
type ConvertField<T> = T extends (string | number | boolean | null)
? T
: T extends {type: string, id: infer ID, name: infer NAME}
? {label: NAME, value: ID}
: never;
type MyTypeConverted = Convert<MyType>;
type MyTypeMoreSpecificConverted = Convert<MyTypeMoreSpecific>;
您可以在playground上查看此代码。当您将鼠标悬停在转换后的类型上时,您将看到有关它的详细信息。
这是如何工作的:
Convert<T>
接受一个对象类型并返回新的映射对象类型,其中对于原始对象的每个键,我们都有ConvertField<T>
,我们在其中传递原始值。 ConvertField<T>
依次检查传递的类型是否为字符串、数字、布尔值或 null,如果是,则按原样返回。如果传递的参数是形状为 {type: string, id: <something>, name: <something>}
的对象,那么我们“提取” id
和 name
的类型,并使用之前提取的类型返回带有字段 label
和 value
的新类型。
如果您以前没有使用过条件类型(尤其是
infer
),可能会有点棘手,所以如果需要的话,我建议您查看 TypeScript 手册中的本章。