为递归deepTranslate函数实现TypeScript类型转换:I18nObject转string
实现递归翻译函数并保留原对象类型结构(替换I18nObject为string)
完全可行,通过TypeScript的递归条件类型可以精准实现这个需求:既保留原对象的结构,又将所有I18nObject类型替换为string,同时让函数返回类型自动匹配转换后的结构。
步骤1:定义核心类型
首先明确I18nObject以及递归转换的工具类型:
// 定义多语言字段类型 type I18nObject = { [lang: string]: string }; // 递归类型转换:将所有I18nObject替换为string,保留其他结构 type DeepTranslated<T> = T extends I18nObject ? string : T extends Array<infer U> ? Array<DeepTranslated<U>> : T extends object ? { [K in keyof T]: DeepTranslated<T[K]> } : T;
这个工具类型的逻辑:
- 若输入是
I18nObject,直接转为string - 若输入是数组,递归处理数组内的每个元素
- 若输入是普通对象,递归处理对象的每个属性
- 其他基础类型(如number、boolean)保持不变
步骤2:调整递归翻译函数的类型约束
修改deepTranslate函数,让它的返回类型自动推导为DeepTranslated<T>:
function deepTranslate<T>(obj: T, locale: string): DeepTranslated<T> { // 处理null/undefined if (obj == null) return obj as DeepTranslated<T>; // 匹配I18nObject,返回对应语言的字符串 if (typeof obj === 'object' && locale in obj && typeof (obj as I18nObject)[locale] === 'string') { return (obj as I18nObject)[locale] as DeepTranslated<T>; } // 处理数组:递归翻译每个元素 if (Array.isArray(obj)) { return obj.map(item => deepTranslate(item, locale)) as DeepTranslated<T>; } // 处理普通对象:递归翻译每个属性 if (typeof obj === 'object') { const translatedObj: Record<string, unknown> = {}; for (const key in obj) { translatedObj[key] = deepTranslate(obj[key], locale); } return translatedObj as DeepTranslated<T>; } // 基础类型直接返回 return obj as DeepTranslated<T>; }
步骤3:使用示例验证
// 示例输入类型 type Product = { id: number; name: I18nObject; description: I18nObject; tags: I18nObject[]; details: { price: number; category: I18nObject; }; }; // 模拟从数据库获取的原始数据 const rawProduct: Product = { id: 1, name: { en: "Apple", fr: "Pomme" }, description: { en: "Fresh organic apple", fr: "Pomme bio fraîche" }, tags: [{ en: "Fruit", fr: "Fruit" }, { en: "Organic", fr: "Bio" }], details: { price: 1.99, category: { en: "Food", fr: "Aliment" } } }; // 翻译后自动推导类型:所有I18nObject已转为string,结构完全保留 const frenchProduct = deepTranslate(rawProduct, 'fr'); // frenchProduct类型为: // { // id: number; // name: string; // description: string; // tags: string[]; // details: { // price: number; // category: string; // }; // }
注意事项
- 若你的
I18nObject有固定的语言键规则(比如仅包含en/fr/de等),可以用类型守卫函数替代简单的locale in obj判断,进一步提升类型准确性。 - TypeScript递归类型存在默认深度限制(通常为100层),但普通业务场景下完全足够。
内容的提问来源于stack exchange,提问作者Binajmen
相关产品推荐
相关产品推荐

