我有一个像这样的翻译字符串的嵌套对象:
viewName: {
componentName: {
title: 'translated title'
}
}
我使用一个翻译库,它接受点符号中的字符串来获取字符串,如translate('viewName.componentName.title')
。
有什么方法可以强制translate的输入参数跟随typescript的对象形状?
我可以通过这样做来完成第一级:
translate(id: keyof typeof languageObject) {
return translate(id)
}
但我希望这种打字能够嵌套,这样我就可以像上面的例子一样调整我的翻译范围。
答案 0 :(得分:1)
如果您希望TypeScript为您提供帮助,您必须帮助TypeScript。它对串联字符串文字的类型一无所知,因此不会起作用。我对如何帮助TypeScript的建议可能比你想要的更多,但它确实带来了一些相当不错的类型安全保证:
首先,我假设您有languageObject
和translate()
函数知道它(意味着languageObject
可能用于生成特定translate()
translate()
1}}功能)。 string
函数需要一个虚线字符串,表示嵌套属性的键列表,其中最后一个属性为const languageObject = {
viewName: {
componentName: {
title: 'translated title'
}
}
}
// knows about languageObject somehow
declare function translate(dottedString: string): string;
translate('viewName.componentName.title'); // good
translate('view.componentName.title'); // bad first component
translate('viewName.component.title'); // bad second component
translate('viewName.componentName'); // bad, not a string
- 值。
Translator<T>
介绍translate()
课程。您可以通过为该对象提供一个对象和一个get()
函数来创建一个对象,并在链中调用其T
方法以深入查看键。 get()
的当前值始终指向您通过translate()
方法链选择的属性类型。最后,当您达到所关注的string
值时,请致电class Translator<T> {
constructor(public object: T, public translator: (dottedString: string)=>string, public dottedString: string="") {}
get<K extends keyof T>(k: K): Translator<T[K]> {
const prefix = this.dottedString ? this.dottedString+"." : ""
return new Translator(this.object[k], this.translator, prefix+k);
}
// can only call translate() if T is a string
translate(this: Translator<string>): string {
if (typeof this.object !== 'string') {
throw new Error("You are translating something that isn't a string, silly");
}
// now we know that T is string
console.log("Calling translator on \"" + this.dottedString + "\"");
return this.translator(this.dottedString);
}
}
。
languageObject
使用translate()
和const translator = new Translator(languageObject, translate);
函数初始化它:
const translatedTitle = translator.get("viewName").get("componentName").get("title").translate();
// logs: calling translate() on "viewName.componentName.title"
并使用它。这可以根据需要使用:
const badFirstComponent = translator.get("view").get("componentName").get("title").translate();
const badSecondComponent = translator.get("viewName").get("component").get("title").translate();
const notAString = translator.get("viewName").translate();
根据需要,这些都会产生编译器错误:
<div *ngfor='let current of users'>
<p>{{current?.name}} <a (click)='more(current?.id)'>Click for more</a>
<span [id]='current?.id + "_info"'></span>
</p>
</div>
希望有所帮助。祝你好运!
答案 1 :(得分:0)
如果它的目的是提供自动完成功能,我想到的唯一方法就是创建一个类型来限制允许的字符串:
type LanguageMap = 'viewName.componentName.title' | 'viewName.componentName.hint';
function translate(id: LanguageMap) {
return translate(id)
}
您将无法使用keyof技巧自动生成此功能,因为嵌套会阻止此操作。
另一种方法是删除嵌套,在这种情况下,你的keyof技巧会为你创建语言地图类型:
let languageObject = {
'viewName.componentName.title': 'translated title',
'viewName.componentName.hint': 'translated hint'
};
function translate(id: keyof typeof languageObject) {
return translate(id)
}
但是我知道没有办法充分利用两个世界,因为一方面是嵌套,另一方面是关键名称之间的逻辑中断。