Update: thanks to https://stackoverflow.com/users/5575595/drag13 completed version can be found here: https://github.com/web-ridge/react-ridge-translations/blob/main/src/index.ts
I'm working on a translation library for React / React Native but I can't get the types to work.
https://github.com/web-ridge/react-ridge-translations
You can create a translation in the following way
// first describe which languages are allowed/required (Typescript)
type TranslationLanguages = {
nl: string
fr: string
en: string
}
// create a translation object with your translations
export default const translate = createTranslations<TranslationLanguages>({
homeScreen:{
yesText: {
nl: 'Ja',
fr: 'Oui',
be: 'Yes',
},
welcomeText: ({ firstName }: { firstName: string }) => ({
nl: `Hoi ${firstName}`,
fr: `Hello ${firstName}`,
be: `Hello ${firstName}`,
}),
}
}, {
language: 'nl',
fallback: 'en',
})
The library changes the object to the following
{
homeScreen:{
yesText: 'Ja',
welcomeText: ({ firstName }: { firstName: string }) => `Hoi ${firstName}`,
}
}
In your component you will use the types in this way
const {yesText,welcomeText} = translate.use().appScreen
It won't autocomplete the types.
Library code (simplified)
type val<T> = (...params: any[]) => T
type val1<T> = T
type Translations<T> = {
[group: string]: {
[key: string]: val<T> | val1<T>
},
}
type TranslationsObject<T> = {
translations: Translations<string>,
use: () => Translations<string>;
}
export function createTranslations<T>(t: Translations<T>): TranslationsObject<T>
How can I let Typescript understand that it needs to autocomplete?
Issue is here
type Translations<T> = {
[group: string]: {
[key: string]: val<T> | val1<T>
},
}
Because of the indexer declaration, TypeScript doesn't know anything about the inner structure. If you want to have more strong types, here is the option:
type val<T> = (...params: any[]) => T
type val1<T> = T
type TransltionGroup = 'homeScreen' | 'personalCabinet';
type Translations<T> = {
[group in TransltionGroup]: {
[key: string]: val<T> | val1<T>
}
}
type TranslationsObject<T> = {
translations: Translations<string>,
use: () => Translations<string>;
}
export function createTranslations<T>(t: Translations<T>): TranslationsObject<T> { }
const test = createTranslations({ homeScreen: { test: '4' }, personalCabinet: { test: '6' } });
const x = test.use().personalCabinet
And of course, you may declare the type for the subgroup
Hope this helps!
So, you want to allow TypeScript to define interface himself. In this case, you need to use more generics. Something like this:
type ValueOf<T> = T[keyof T];
type Translations<TGroup> = {
[group in keyof TGroup]: { [key in keyof ValueOf<TGroup>]: ValueOf<TGroup>[key] }
}
type TranslationsObject<TGroup> = {
translations: Translations<TGroup>,
use: () => Translations<TGroup>;
}
export function createTranslations<TGroup>(data: TGroup): TranslationsObject<TGroup> { }
const test = createTranslations({
homeScreen:{
yesText: {
nl: 'Ja',
fr: 'Oui',
be: 'Yes',
},
welcomeText: ({ firstName }: { firstName: string }) => ({
nl: `Hoi ${firstName}`,
fr: `Hello ${firstName}`,
be: `Hello ${firstName}`,
}),
}
});
const x = test.use().homeScreen.yesText
Type checking should work fine for now. Does this look good?
Updated with code from comment
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.