如何从给定TypeScript对象动态生成指定结构的类型?
问题描述
给定以下TypeScript对象:
const myObject = { AdminInviteStudent: ['inviterGivenName', 'inviterFamilyName', 'link'], DeleteMappingStudent: ['teacherGivenNameAndInitialOfFamilyName', 'studentGivenName', 'noteLink'] };
需要编写一个工具类型GetType,实现如下用法:
export type EmailTemplateParameters = GetType<typeof myObject>;
最终生成的类型结构需将数组中每个值设为必填的string类型,如下:
{ AdminInviteStudent: { inviterGivenName: string; inviterFamilyName: string; link: string; }; DeleteMappingStudent: { teacherGivenNameAndInitialOfFamilyName: string; studentGivenName: string; noteLink: string; }; }
同时需要优化原问题:如何将TypeScript类型导出为对象以暴露可用的键。
解决方案
1. 修正对象定义(保留字面量类型)
首先要让TypeScript保留数组元素的字面量类型,需给对象添加as const断言——否则TS会将数组推断为string[],无法获取具体的键名:
const myObject = { AdminInviteStudent: ['inviterGivenName', 'inviterFamilyName', 'link'], DeleteMappingStudent: ['teacherGivenNameAndInitialOfFamilyName', 'studentGivenName', 'noteLink'] } as const;
2. 编写工具类型GetType
通过映射类型实现需求:遍历对象的每个键,再遍历对应数组的每个元素,生成必填的string属性:
type GetType<T extends Record<string, readonly string[]>> = { [K in keyof T]: { [P in T[K][number]]: string; }; };
3. 生成目标类型
直接使用工具类型即可得到所需结构:
export type EmailTemplateParameters = GetType<typeof myObject>;
原问题优化方案
原问题核心是让类型与运行时对象共享单一数据源,避免重复定义导致不一致,推荐以下优化:
强制单一数据源:用
as const或封装函数确保运行时对象和类型同步,比如封装一个模板定义函数:function defineTemplates<T extends Record<string, readonly string[]>>(templates: T) { return templates; } const myTemplates = defineTemplates({ AdminInviteStudent: ['inviterGivenName', 'inviterFamilyName', 'link'], DeleteMappingStudent: ['teacherGivenNameAndInitialOfFamilyName', 'studentGivenName', 'noteLink'] } as const);这样既能约束输入,又能自动推导类型,避免遗漏
as const。运行时获取键列表:如果需要在运行时获取可用的模板名称,可编写工具函数:
function getTemplateKeys() { return Object.keys(myObject) as Array<keyof typeof myObject>; }确保运行时获取的键与类型完全匹配,不会出现类型不兼容问题。
扩展灵活性:如果后续需要支持非
string类型的参数,可将数组改为对象结构,比如:const myObject = { AdminInviteStudent: [ { key: 'inviterGivenName', type: 'string' as const }, { key: 'expireDays', type: 'number' as const } ] } as const;再修改工具类型推导对应类型,满足更复杂的参数类型需求。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

