Часто в TypeScript коде можно столкнуться с тем, что типы недостаточно точны. Это бывает в случаях, когда мы определяем типы, например, через union — string | number и других подобных случаях.
Рассмотрим пример
typescript1const value: string | number = ... 2 3parseInt(value) // ошибка 4
В таком случае мы получим TypeError , а всё потому что переменная value имеет более общий тип, чем тот, что ожидает parseInt — эта функция ожидает первым аргументом на вход только строку. В таком случае нам может помочь сужение типов, которое нам дают дополнительные проверки — тайпгарды.
Тайпгарды — Type Guards — это языковые конструкции, проверки, которые позволяют определить или уточнить тип переменной средствами JavaScript. Тайпгарды бывают двух видов — уточняющие и определяющие.
Уточняющие тайпгарды — проверки, которые позволяют вывести более узкий тип из общего типа, например вывести string из типа string | number | boolean | null.
Определяющие же тайпгарды — проверки, которые позволяют вывести узкий тип из неизвестного типа, который в идеальном мире обозначается типом unknown
Есть несколько способов сузить тип
- Через оператор typeof
typescript1const value: string | number = ... 2 3if (typeof value === 'string') { 4 // ошибки не будет, т.к. 5 // тип value в этом условии 6 // строго равняется "string" 7 parseInt(value) 8} 9
- Через ключевое слово in или метод hasOwnProperty
typescript1const value: any[] | number = ... 2 3if ("map" in value) { 4 // value === array 5 value.map(...) 6} 7 8const animal = Cat | Dog = ... 9 10if (animal.hasOwnProperty('meow')) { 11 // animal === Cat 12 animal.meow() 13} 14
- Через ключевое слово instanceof
typescript1const person: Fireman | Programmer = ... 2 3// при условии что Programmer - класс 4// а person - инстанс класса 5if (person instanceof Programmer) { 6 person.code() 7} 8
- Через встроенные в язык функции проверки типа
typescript1const value: any[] | number = ... 2 3if (Array.isArray(value)) { 4 value.map(...) 5} 6
- Через existed check, например, для null и undefined
typescript1const user: User | null = ... 2 3if (user) { 4 console.log(user.name) 5} 6
Также подобные проверки можно выносить в отдельные функции, которые обычно именуются по следующему шаблону — is + <название типа или интерфейса>, например, для типа User будет логично создать тайпгард isUser, вот небольшой пример:
typescript1type Account = User | Admin | Manager 2 3const isUser = (account: Account): account is User => { 4 return account.type === "user" 5} 6
В данном случае мы используем предикат для пользователя. Вообще, предикат — это базовый математический термин, но если кто-то не знал или подзабыл, также напоминаю:
В нашем контексте, предикат — уникальное определяющее свойство сущности, относительно которого можно быть точно уверенным в её идентичности.
Если более просто, то мы знаем, что если account.type === “user”, то перед нами ни что иное как User. В этом случае тип аккаунта является предикатом, на основе которого можно делать выводы о типе аккаунта без дополнительных проверок.
И всё это касается лишь уточняющих тайпгардов, пост об определяющих тайпгардах можно прочитать в отдельной статье
Статья была полезной?
Читайте также:
— 3 минуты
Составные компоненты
Есть такой паттерн для реакта, который называется Compound Components. Это...
— 2 минуты
Определяющие тайпгарды
Как я и писал в одном из своих постов в телеге, тайпгарды есть двух видов:...
— 2 минуты
Как реагировать на изменения объекта
В JavaScript обычные объекты не умеют уведомлять о своих изменениях, однако...