我尝试使用Typescript 3实现翻译功能。要使用的应用程序/视图的最终API应该如下所示:
const translatedPasswordLabel = translator.Get('loginform.labels.password');
我喜欢检查翻译键(字符串参数)编译器。我让这一部分使用这样的字符串文字类型:
export type TranslationKeys =
| 'loginform.labels.password'
| 'loginform.labels.username'
| 'loginform.actions.submit';
现在,我被困在设置翻译存储库中以定义和访问此翻译。这是我尝试过的事情之一:
interface IDefaultTranslation {
defaultText: string;
}
interface ITranslations {
[key: TranslationKeys]: IDefaultTranslation;
}
const translations: ITranslations = {
'loginform.labels.password': {defaultText: 'Password'},
'loginform.labels.username': {defaultText: 'Username'},
'loginform.actions.submit': {defaultText: 'Submit'},
};
我不喜欢的是我必须两次指定翻译键。我也不知道如何以完全经过编译器检查的方式访问它们。尝试过类似
function getText<T, K extends keyof T>(translations: T, key: K): IDefaultTranslation {
return translations[key];
}
但是编译器在这里不喜欢IDefaultTranslation
。
基本上,我喜欢一种类型化的字典,其中的键是一个选中的字符串,而值是一个IDefaultTranslation
对象。如果我在translations
中拼错了翻译密钥,或者如果我完全错过了在translations
中定义的translationKeys
中的翻译,我也想得到编译器错误。不确定这部分是否可以完成。
这种字典,必须定义/设置给定集合的所有键。
我还考虑过用我刚刚定义“字典”并直接针对.get('key')
函数的键对其进行导出/检查的方式来验证逻辑,但是我不知道该怎么做。
我尝试的另一件事是将它们存储在类型数组中。这行得通,但我看不到如何检查所有键是否已定义/推入数组的方法。
有什么想法如何使用固定键或导出键进行编译检查来设置这种类型的字典?
答案 0 :(得分:0)
据我了解,您的要求是:
数字1和2可以使用映射类型完成。可以使用keyof
类型的运算符来完成数字3。
export type TranslationKeys =
| 'loginform.labels.password'
| 'loginform.labels.username'
| 'loginform.actions.submit';
interface IDefaultTranslation {
defaultText: string;
}
// TKeys will be the union of all keys
type ITranslations<TKeys extends string> = { [P in TKeys]: IDefaultTranslation }
// If we miss a field or have a missing one we will get an errror here
const translations: ITranslations<TranslationKeys> = {
'loginform.labels.password': {defaultText: 'Password'},
'loginform.labels.username': {defaultText: 'Username'},
'loginform.actions.submit': {defaultText: 'Submit'},
};
// Function that gets the text:
function getText<T extends ITranslations<any>>(translations: T, key: keyof T): IDefaultTranslation {
return translations[key];
}
// We get an error if we call with a missing key
getText(translations, "loginform.actions.submit")
注意 ITranslations<TKey>
基本上等同于内置类型Record<TKey, IDefaultTranslation>
。保留专用名称以明确类型的语义是很有意义的。
您也可以有一个代表键入字典的类:
class TypedTranslation<TKeys extends string> {
public constructor(private translations: ITranslations<TKeys>) {}
Get(key: TKeys) : IDefaultTranslation {
return this.translations[key];
}
}
var t = new TypedTranslation({
'loginform.labels.password': {defaultText: 'Password'},
'loginform.labels.username': {defaultText: 'Username'},
'loginform.actions.submit': {defaultText: 'Submit'},
});
t.Get("loginform.actions.submit")
修改
在我的上一个示例中,实际上是根据传入的对象来推断类TKeys
的。您可以通过实例化TypedTranslation
类并从中提取键来避免重新声明所有键。
type TypedTranslationKeys<T extends TypedTranslation<any>> = T extends TypedTranslation<infer Keys> ? Keys : never;
type keysForT = TypedTranslationKeys<typeof t> // will be "loginform.labels.password" | "loginform.labels.username" | "loginform.actions.submit"