#typescript #typescript-typings
#машинописный текст #typescript-типизации
Вопрос:
Учитывая что-то вроде
interface Country {
"SE": {
langs: {sv:"sv", fi: "fi", en: "en"}
}
'US': {langs: {us:"us", ca: "ca", es: "es"} }
}
type Market = "SE" | "US"
Я хотел бы, чтобы система типов знала, что единственными допустимыми локалями являются:
"sv-SE"
"fi-SE"
"en-SE"
"ca-US"
"en-US"
"es-US"
Возможно ли это? Лучшее, что я мог придумать, это:
type Locale = `${keyof Country}-${keyof Country[Market]["langs"]}`
let locale: Locale = "" => never
Ответ №1:
interface Country {
"SE": {
langs: { sv: "sv", fi: "fi", en: "en" }
}
'US': { langs: { us: "us", ca: "ca", es: "es" } }
}
type Code<T> =
T extends keyof Country
? keyof Country[T]['langs'] extends string
? `${keyof Country[T]['langs']}-${T}`
: never
: never
type US = Code<'US'>
type SE = Code<'SE'>
//thanks @sroes
type Locale = Code<keyof Country>
Комментарии:
1. И затем
type Locale = Code<keyof Country>
Ответ №2:
Вы также можете использовать один общий вспомогательный сопоставленный тип, который не зависит от текущего Country
списка, чтобы получить желаемый результат:
interface Country {
"SE": {
langs: {sv:"sv", fi: "fi", en: "en"}
}
'US': {langs: {us:"us", ca: "ca", es: "es" } }
}
type Locale<CL> = {
[ U in keyof CL ] : CL[U] extends { langs: { [ x: string ] : string } } ? `${keyof CL[U]["langs"] amp; string}-${U amp; string}` : never
}[keyof CL amp; string];
type invalid = Locale<{ "UU": { langs: "EEE" } }>; //never;
type custom = Locale<{ "EU": { langs: { fr: "fr" } } }>; //"fr-EU";
type valid = Locale<Country>; //"sv-SE" | "fi-SE" | "en-SE" | "us-US" | "ca-US" | "es-US"
Ответ №3:
Для ребят, приезжающих из будущего, это теперь возможно с помощью литеральных типов шаблонов. Например,
type Country = 'US' | 'GB';
type Lang = 'en';
type Locale = `${Lang}_${Country}`; // type Locale = "en_US" | "en_GB"