英文:
How to convert a JSON object to a type, converting strings to types, in TypeScript?
问题
如何将base
对象通过typeof base
转换为GoalType
,就像我尝试使用type FoundType = InterpolateType<typeof base>
那样?
英文:
I have this TS playground:
const base = {
user: {
id: { type: 'string' },
name: { type: 'string' }
},
post: {
id: { type: 'string' },
title: { type: 'string' },
published: { type: 'boolean', defaultsTo: false },
likes: { type: 'number', defaultsTo: 0 }
}
}
type GoalType = {
user: {
id: string
name: string
}
post: {
id: string
title: string
published: boolean
}
}
type InterpolateType<T> = {
[K1 in T]: {
[K2 in T[K1]]: T[K1]['type'] extends 'string' ? string : boolean
}
}
type FoundType = InterpolateType<typeof base>
How can I convert the base
object through typeof base
to the GoalType
, as I tried to do with type FoundType = InterpolateType<typeof base>
?
答案1
得分: 1
我们首先需要使用const assertion来防止编译器扩展类型:
const base = {
user: {
id: { type: "string" },
name: { type: "string" },
},
post: {
id: { type: "string" },
title: { type: "string" },
published: { type: "boolean", defaultsTo: false },
likes: { type: "number", defaultsTo: 0 },
likesArr: { list: "true", type: ["string", "boolean"] },
},
} as const;
我们还需要一个字符串到类型映射类型:
type StringToType = {
string: string;
boolean: boolean;
number: number;
};
为了插值,我们将遍历类型并检查其属性的“type”是否在“StringToType”中。如果在那里,我们只返回“StringToType[type]”,否则,我们检查属性是否是具有{list: "true", type: readonly unknown[]}
的列表。如果条件为真,我们通过使用“number”作为索引将“type”的元素传递给“StringToType”以检索“StringToType”中的所有元素:“StringToType[T[K][K2]["type"][number] & keyof StringToType]”。我们需要与“keyof StringToType”相交,以确保我们只传递存在于“StringToType”中的值。最后,我们通过在末尾添加“[]”来创建该数组。如果以上条件都不成立,我们只是返回“type”本身而没有任何修改。
type InterpolateType<T> = {
[K in keyof T]: {
[K2 in keyof T[K]]: "type" extends keyof T[K][K2]
? T[K][K2]["type"] extends keyof StringToType
? StringToType[T[K][K2]["type"]]
: T[K][K2] extends { list: "true"; type: readonly unknown[] }
? StringToType[T[K][K2]["type"][number] & keyof StringToType][]
: T[K][K2]["type"]
: T[K][K2];
};
};
用法:
// type Result = {
// readonly user: {
// readonly id: string;
// readonly name: string;
// };
// readonly post: {
// readonly id: string;
// readonly title: string;
// readonly published: boolean;
// readonly likes: number;
// readonly likesArr: (string | boolean)[];
// };
// }
type Result = InterpolateType<typeof base>;
英文:
We first need to use const assertion to prevent the compiler from widening the type:
const base = {
user: {
id: { type: "string" },
name: { type: "string" },
},
post: {
id: { type: "string" },
title: { type: "string" },
published: { type: "boolean", defaultsTo: false },
likes: { type: "number", defaultsTo: 0 },
likesArr: { list: "true", type: ["string", "boolean"] },
},
} as const;
We will also need a string to type map type:
type StringToType = {
string: string;
boolean: boolean;
number: number;
};
To interpolate, we will map through the type and check if the type
of its property is in the StringToType
. If it is there, we just return the StringToType[type]
, otherwise, we check whether the property is a list with {list: "true", type: readonly unknown[]}
. If the condition is true we pass the elements of type
to StringToType
by using number
as the index to retrieve all the elements in the type
: StringToType[T[K][K2]["type"][number] & keyof StringToType]
. We need to intersect with keyof StringToType
to make sure that we only pass the values that exist in the StringToType
. Finally, we make the array out of that by appending []
at the end. If none of the above conditions are true we just return the type
itself without any modification.
type InterpolateType<T> = {
[K in keyof T]: {
[K2 in keyof T[K]]: "type" extends keyof T[K][K2]
? T[K][K2]["type"] extends keyof StringToType
? StringToType[T[K][K2]["type"]]
: T[K][K2] extends { list: "true"; type: readonly unknown[] }
? StringToType[T[K][K2]["type"][number] & keyof StringToType][]
: T[K][K2]["type"]
: T[K][K2];
};
};
Usage:
// type Result = {
// readonly user: {
// readonly id: string;
// readonly name: string;
// };
// readonly post: {
// readonly id: string;
// readonly title: string;
// readonly published: boolean;
// readonly likes: number;
// readonly likesArr: (string | boolean)[];
// };
// }
type Result = InterpolateType<typeof base>;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论