嵌套对象的Typescript字符串点表示法

时间:2017-11-01 14:54:49

标签: typescript

我有一个像这样的翻译字符串的嵌套对象:

viewName: {
    componentName: {
        title: 'translated title'
    }
}

我使用一个翻译库,它接受点符号中的字符串来获取字符串,如translate('viewName.componentName.title')

有什么方法可以强制translate的输入参数跟随typescript的对象形状?

我可以通过这样做来完成第一级:

translate(id: keyof typeof languageObject) {
    return translate(id)
}

但我希望这种打字能够嵌套,这样我就可以像上面的例子一样调整我的翻译范围。

2 个答案:

答案 0 :(得分:1)

如果您希望TypeScript为您提供帮助,您必须帮助TypeScript。它对串联字符串文字的类型一无所知,因此不会起作用。我对如何帮助TypeScript的建议可能比你想要的更多,但它确实带来了一些相当不错的类型安全保证:

首先,我假设您有languageObjecttranslate()函数知道它(意味着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)
}

但是我知道没有办法充分利用两个世界,因为一方面是嵌套,另一方面是关键名称之间的逻辑中断。