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, которая выглядит глупо, но со временем становится полезной.