Типы строк шаблона машинописного текста как дискриминанты

Улучшенные типы литералов шаблона в Typescript 4.5

Что такое «сужение» в TS?

Прежде чем мы рассмотрим улучшение типов литералов в Typescript 4.5 и более поздних версиях, я просто хочу кратко повторить, что на самом деле означает «сужение» в этом контексте. По сути, вы можете сузить тип в Typescript, проверив свойства объекта. Если в сущности существует свойство, доступное только для определенного типа, TypeScript понимает это и, следовательно, может предоставить правильные типы.

Следующий пример кода демонстрирует, что я имею в виду.

type Addition = {
    sum: number;
}

type Subtraction = {
    result: number;
}

function calculate(action: Addition | Subtraction) {
    if ('sum' in action) {
      // Simple example of using properties
      // of an entity to narrow down its
      // actual type.
      //
      // 'action' is at this point of type
      // 'Addition'. Nice!
      const addition = action;
    }
}

Сужение для типов строк шаблона

Начиная с Typescript версии 4.5, этот шаблон также можно применять к типам литералов шаблона, также известным как специальные строки с обратными кавычками. Сопоставление с образцом становится действительно мощным инструментом в языке.

Конечно, чтобы сужение стало пригодным для использования, все типы в сравнении должны иметь один и тот же ключ свойства. В противном случае вы можете просто использовать обычное сужение, как указано выше.

В следующем примере кода показано, как строки шаблона могут использовать сужение:

type Addition = {
    variant: `${string}-addition`;
    sum: number;
}

type Subtraction = {
    variant: `${string}-subtraction`;
    result: number;
}

function process(action: Addition | Subtraction) {
    if (action.variant === "simple-addition") {
        // Stupid simple example, but you get the idea:
        // We used 'simple-addition', and the pattern 
        // matching by TS understood that '...-addition'
        // can be discriminated to 'Addition'.
        const addition = action;
    }
}
//
// Example that DOES NOT work.
//
// This demo illustrates that the
// discriminante has to be a string,
// else the pattern matching worn't work.

type Addition = {
    variant: `${string}-arithemtic`;
    sum: number;
}

type Subtraction = {
    variant: `${number}-arithemtic`;
    result: number;
}

function process(action: Addition | Subtraction) {
    if (action.variant === "123-arithemtic") {
        // Still 'Addion | Subtraction',
        // as we can only compare against
        // a string '123-arithmetic', which
        // is of course the same for both.
        const addition = action;
    }
}

А теперь вы знаете о сужении шаблонных литералов в Typescript! Это может быть функция, которую вы не будете использовать очень часто, но я думаю, что когда это уместно, она может значительно снизить сложность кода и сделать вашу базу кода немного чище, чем без этой функции.

Предложения

Связанные

Приложение

Языки