Типизированные локали в typescript на основе страны и доступных языков

#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"