英文:
Expect function Parameter to be Key of Object with Dynamic Properties
问题
我想制作一个多语言应用程序。
我希望尽可能严格和简单地构建输入。我的代码如下:
//=== 在我的 Hook 内部: ===//
interface ITranslation {
[key:string]:[string, string]
}
const useTranslator = (translations:ITranslation) => {
const language = useLanguage() // 从另一个 Hook 获取语言设置
const translate = (key:keyof typeof translations) => {
// 映射并返回正确的翻译
}
return translate;
}
//=== 在组件内部: ===//
const translation:ITranlation = {
"something in english": [ "something in german", "something in spanish" ],
"anotherthing in english": ["anotherthing in german", "anotherthing in spanish"]
}
const translate = useTranslation(translation)
return(
<Text>{translate("something in english")}</Text>
)
我想要实现的目标:
-
当传递包含动态键的
translation
对象到 Hook 中时:useTranslation(translations)
,应该有一个类型检查来验证是否提供了两种语言(任何属性都具有包含两个字符串的数组)。 -
当使用翻译函数(在 Text 组件内部)时,如果键不匹配
translations
对象内的动态键,则 TypeScript 应该引发错误。因此,这应该引发错误:tranlate("not a key in object")
。
但是我无法使其正常工作。我可以将 translations
对象设置为 as const
,但是这样一来,将对象传递给 Hook 时就没有类型检查。或者我按上面的方式设置为 translation:ITranslation
,但是在组件内部的 translate
函数的参数中就没有类型检查。
是否可能实现这一点?(如果是,如何实现?)
先行致谢!
英文:
Im making an application multi Language.
I want to build typing as strict and simpel as possible. My Code is the following:
//=== Inside my Hook: ===//
interface ITranslation {
[key:string]:[string, string]
}
const useTranslator = (translations:ITranslation) => {
const language = useLanguage() // just getting the language setting from another hook
const translate = (key:keyof typeof translations) => {
// mapping and returning the right translation
}
return translate;
}
//=== Inside the component: ===//
const translation:ITranlation = {
"something in english": [ "something in german", "something in spanish" ],
"anotherthing in english": ["anotherthing in german", "anotherthing in spanish"]
}
const translate = useTranslation(translation)
return(
<Text>{translate("something in english")}</Text>
)
What i want to achieve:
-
When passing the
translation
Object, with Dynamic Keys to the Hook:useTranslation(translations)
, there should be a typecheck validating, that both languages are provided (any property has an Array with 2 Strings) -
When using the translate function (inside the Text component) typescript should bring an error, if a key is not matching the Dynamic Keys inside the
translations
object. So this should throw an error:tranlate("not a key in object")
But i can't get it to work properly. I can either set the translations
object as const
, but then there is no typecheck when passing the object to the Hook.
Or i set it as shown above with translation:ITranslation
but then there is no typechecking for the parameter in the ´translate´ function inside the component.
Is it possible to achive that? (If yes, how?)
Thanks in advance!
答案1
得分: 1
这个解决方案仅适用于 TypeScript >= 4.9
,因为它使用了在 4.9
中引入的satisfies操作符。
我们将采用添加 as const
的方法,并且 satisfies
将允许我们进行类型检查。
const translation = {
'something in english': ['something in german', 'something in spanish'],
'anotherthing in english': ['anotherthing in german', 'anotherthing in spanish'],
} as const satisfies ITranslation;
由于我们添加了 as const
,ITranslation
中的值将变为 readonly [string, string]
,因此我们必须更新 ITranslation
如下:
interface ITranslation {
[key: string]: readonly [string, string];
}
接下来,我们需要为 useTranslator
添加一个泛型参数,以便它能够在 ITranslation
的特定实例上工作。对于 translate
函数也是如此。它应该接受关于 ITranslation
键的泛型参数,并返回该特定键的值:
const useTranslator = <T extends ITranslation>(translations: T) => {
const language = useLanguage(); // 从另一个钩子中获取语言设置
const translate = <K extends keyof T>(key: K): T[K][number] => {
// 返回检索到的值
};
return translate;
};
由于问题中没有要求,translate
将返回特定键的翻译的联合类型,这是通过 T[K][number]
实现的。
用法:
const Component = () => {
const translate = useTranslator(translation);
// "something in german" | "something in spanish"
const case1 = translate('something in english');
// "anotherthing in german" | "anotherthing in spanish"
const case2 = translate('anotherthing in english');
return null;
};
英文:
This solution will work only for Typescript >= 4.9
since it uses the satisfies operator introduced in the 4.9
.
Adding as const
is the approach we will go with, and satisfies
will allow us to type-check it.
const translation = {
'something in english': ['something in german', 'something in spanish'],
'anotherthing in english': ['anotherthing in german', 'anotherthing in spanish'],
} as const satisfies ITranslation;
Since we added as const
the values in the ITranslation
will be readonly [string, string]
, thus we have to update the ITranslation
to the following:
interface ITranslation {
[key: string]: readonly [string, string];
}
Next, we need to add a generic parameter to useTranslator
so it works over the specific instance of ITranslation
. The same goes for the translate
function. It should accept the generic parameter for the key of ITranslation
and return the value for that specific key:
const useTranslator = <T extends ITranslation>(translations: T) => {
const language = useLanguage(); // just getting the language setting from another hook
const translate = <K extends keyof T>(key: K): T[K][number] => {
// return retrieved value
};
return translate;
};
Since it is not asked in the question translate
will return a union of the translations for the specific key, which is achieved by T[K][number]
Usage:
const Component = () => {
const translate = useTranslator(translation);
// "something in german" | "something in spanish"
const case1 = translate('something in english');
// "anotherthing in german" | "anotherthing in spanish"
const case2 = translate( 'anotherthing in english');
return null;
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论