TypeScript 4.1 представил template literal types. На первый взгляд звучит неинтересно, позволяет создавать объединение литеральных типов на основе других.

Однако есть пара случаев, когда эта функция очень полезна.

Vuex с TypeScript

После этого TypeScript выдаст ошибку компиляции, когда кто-то отправит/совершит действие/мутацию с неправильной полезной нагрузкой. например:

Отправка действий из другого модуля

Но как насчет случая, когда нам нужно отправить действие от module2? Module1ActionContext не знает об действиях и мутациях из другого пространства имен. Чтобы сообщить ему, нам нужно добавить что-то вроде этого:

Звучит неплохо, но мы должны вызывать диспетчер с ${module2Namespace}/actionB2, а не с actionB2. Так что лучшее, что мы можем сделать, это ввести тип

Выглядит как типобезопасный код, однако ${module2Namespace}/actionB2 as 'actionB2' является дублированием, компилятор должен знать, какие действия мы отправляем. Также мы должны помнить о { root: true }, потому что TS не будет выдавать ошибку, когда эта часть отсутствует.

С литеральными типами шаблонов

После обновления TypeScript до 4.1+ (и красивее до 2.0+) мы можем объявлять контекст следующим образом.

Этот синтаксис означает, что мы отображаем объединение actionB1 | actionB2в module2Namespace/actionB1 | module2Namespace/actionB2. Почти идеально, почти…

По умолчанию такое значение ${module2Namespace}/actionB2 вводится как string, а не как литерал. Чтобы изменить это, мы можем использовать as const:

Итак, мы изменили as actionB2 на as const. Большой успех? Да потому что с as const нет дублирования и нельзя сделать такой баг: dispatch({module2Namespace}/actionB2 as actionB1, actionB1Payload)с полезной нагрузкой от actionB1 без уведомления об этом в сообщении компиляции.

Заключение

Это не первая функция TypeScript, которая выглядит глупо, но со временем становится полезной.

Ссылки