javascript - typescript: ¿Cómo definir un tipo como cualquier parte de un enum?
Estoy intentando crear un módulo de traducción usando TypeScript.
Quiero definir los idiomas como un parámetro enum para la función create-text, así como:
export enum Language {
He = "he",
En = "en",
}
const { createI18n, createI18nText } = createTextFunctions(Language);
const firstExample = createI18nText({
he: {
firstText: "שלום",
sc: {
hello: "שלום שוב"
}
},
en: {
firstText: "hello",
sc: {
hello: "hello again"
}
}
})
export const i18n = createI18n({
welcome: firstExample,
})
Pero mi problema es que, debido a que los idiomas se pasan como parámetros a una función de TypeScript y la función infiere los tipos, TypeScript no está señalando nada. Puedo crear texto con un idioma que no existe y lo aceptará, como createI18nText({ ar:{ hi : "hi" }}).
Mis funciones de texto son estas:
export type Languages = { [key: string]: string };
export const createTextFunctions = (languages: LanguagesD) => {
type I18nText<T extends object> = {
[k in keyof typeof languages]: T;
}
const createI18n = <T extends { [key: string]: I18nText<any>; }>(i18n: T) => {
return i18n;
};
const createI18nText = <T extends object>(text: I18nText<T>) => {
return text;
}
return {
createI18n,
createI18nText
}
}
Entonces el código está ejecutándose y haciendo lo que necesita hacer, pero estoy perdiendo el control de tipos.
Prefiero tener mis valores de enumeración en minúsculas, así que también es un problema. Si esta es la solución, la aceptaré, pero si hay alguna manera de pasar un parámetro de enumeración y ejecutarlo por sus valores, sería genial.
Respuesta #1
Puedes hacer que createTextFunctions use un genérico. Podrás personalizar las claves como desees cuando crees la función de texto :
// *L* must be a union of strings.
const createTextFunctions = <L extends string>() => {
type I18nText<T extends object> = Record<L, T>;
type I18n = Record<string, I18nText<any>>;
const createI18n = <T extends I18n>(i18n: T): T => {
return i18n;
};
const createI18nText = <T extends object>(text: I18nText<T>): I18nText<T> => {
return text;
}
return {
createI18n,
createI18nText
}
}
Luego especifica el Language como una unión de cadenas:
type Language = "en" | "he";
Y crear/utilizar las funciones de texto:
const { createI18n, createI18nText } = createTextFunctions<Language>();
const firstExample = createI18nText({
he: {
firstText: "שלום",
sc: {
hello: "שלום שוב"
}
},
// If the key *en* is missing, typescript will complain.
en: {
firstText: "hello",
sc: {
hello: "hello again"
}
},
// If we add the key *us*, typescript will complain.
})
export const i18n = createI18n({
welcome: firstExample,
})
En mi opinión, los tipos unión son más cómodos de usar que los enums.
