如何在TypeScript中增强vue-i18n的useI18n返回的t函数的参数类型提示?
如何在TypeScript中增强vue-i18n的useI18n返回的t函数的参数类型提示?
嗨,我之前刚好遇到过一模一样的需求!不用直接修改vue-i18n的源码,只需要写一个简单的包装函数,结合TypeScript的泛型和类型工具就能实现你想要的效果——既保留原useI18n的所有功能,又给t函数加上额外的key类型提示。下面给你一步步讲清楚:
核心思路
我们的目标是:
- 保留原useI18n从传入的
messages中自动推断key类型的能力 - 给t函数的key参数额外添加自定义的类型(比如你说的"aaa")
- 完全保留t函数原本的其他参数和返回值类型(比如插值、指定locale这些功能不能丢)
具体实现代码
首先,我们先导入vue-i18n的相关类型,然后定义包装函数:
import { useI18n, UseI18nOptions, UseI18nReturn } from "vue-i18n"; // 1. 先定义你想要添加的额外翻译key类型 type ExtraTranslationKeys = "aaa"; // 2. 写包装函数,用泛型保留原useI18n的类型推断能力 function useEnhancedI18n< Messages extends Record<string, any>, Locale = string, DefaultLocale = Locale >(options: UseI18nOptions<Messages, Locale, DefaultLocale>) { // 调用原生的useI18n获取所有返回值 const originalI18n = useI18n(options); // 3. 增强t函数的类型:把原始的key类型和额外key类型合并 // 这里用TypeScript的Parameters和ReturnType工具类型,确保保留t函数的其他参数和返回值类型 const enhancedT = originalI18n.t as ( key: keyof Messages[Locale] | ExtraTranslationKeys, ...rest: Parameters<UseI18nReturn<Messages, Locale, DefaultLocale>["t"]> extends [any, ...infer RestArgs] ? RestArgs : never ) => ReturnType<typeof originalI18n.t>; // 4. 返回合并后的对象,替换t为增强版,其他属性完全保留 return { ...originalI18n, t: enhancedT, }; }
怎么使用这个包装函数?
和你之前用原生useI18n的方式几乎一样,只是换成我们写的useEnhancedI18n:
const { t } = useEnhancedI18n({ messages: { zh: { title: "zh", test: "TEST" }, en: { title: "en", test: "test" } } }); // 现在输入t("")的时候,会自动提示title、test和aaa三个选项! t("title"); // 正常工作,保留原类型推断 t("test"); // 同样正常 t("aaa"); // 新增的key也会有类型提示,不会报TypeScript错误
进阶优化(可选)
如果你希望额外的key也对应真实的多语言消息(而不只是类型提示),可以把ExtraTranslationKeys改成从额外的消息对象中提取key,这样更严谨:
// 定义额外的多语言消息 type ExtraMessages = { zh: { aaa: "中文测试aaa" }, en: { aaa: "English test aaa" } }; // 自动提取额外消息的key类型 type ExtraTranslationKeys = keyof ExtraMessages[string];
这样做的话,你还可以把额外消息合并到传入useEnhancedI18n的messages里,确保实际翻译也能生效:
const baseMessages = { zh: { title: "zh", test: "TEST" }, en: { title: "en", test: "test" } }; // 合并基础消息和额外消息 const mergedMessages = { zh: { ...baseMessages.zh, ...ExtraMessages.zh }, en: { ...baseMessages.en, ...ExtraMessages.en } }; const { t } = useEnhancedI18n({ messages: mergedMessages });
这样既保证了类型提示,又能让实际翻译正常工作~
内容来源于stack exchange




