Pull to refresh

Вывод типов в TypeScript. Неизменяемый массив конкретных строковых значений

Level of difficultyEasy
Reading time2 min
Views5.9K

Введение

Решим реальную практическую задачу, с которой мне пришлось столкнуться на моем проекте React/TypeScript.

Задача

У нас есть массив конкретных строковых значений, таких как "first", "second", "third", "fourth" и "fifth". Необходимо отобразить их на странице, т.е как-то использовать, а также убедиться, чтобы эти данные были строго типизированы и TypeScript нам выдавал всплывающие подсказки при их использовании в коде.

Решение

Сначала поместим данные в неизменяемый (readonly) массив:

const numberNames = ["first", "second", "third", "fourth", "fifth"] as const
  • Мы объявили константу numberNames и присвоили ей массив строковых литералов;

  • Конструкция as const используется чтобы сделать из данного массива неизменяемый кортеж (tuple), где конкретные строковые литералы сохраняются как литеральные типы;

  • Сохранение строковых литералов в качестве литеральных типов означает, что компилятор TypeScript рассматривает каждый элемент в массиве как отдельный тип, соответствующий его точному строковому значению. Например, тип первого элемента 'first' не является просто общим строковым типом (string), а конкретно типом 'first';

  • Убедитесь в этом сами, создав два массива - один с as const, а другой без. А затем наведите на переменную и посмотрите разницу.

Теперь создадим тип на основе этого массива:

type NumberName = typeof numberNames[number]
  • Здесь мы создали тип NumberName, значением которого является объединение (union) типов строковых литералов из массива;

  • Индексатор числа [number] извлекает объединенный тип отдельных элементов массива. В результате typeof numberNames[number] представляет собой объединенный тип элементов массива:

"first" | "second" | "third" | "fourth" | "fifth"
  • Почему [number], а не, например [string]? Все просто - как мы знаем, к элементам массива можно получить доступ через числовой индекс: например, numberNames[0] => "first";

  • Даже если бы у нас был массив со значениями других типов, например [1, 'blabla', 555], то в любом случае мы бы использовали [number] для того, чтобы создать тип объединения на его основе 1 | 'blabla' | 555;

  • Кстати, данная возможность извлечения типа из кортежа при помощи индексатора [number], как у нас в примере, появилась в версии TypeScript 4.1.

Заключение

Для чего это все нужно - чтобы строго типизировать данный список строк и когда мы будем с ним работать, получать такого рода подсказки:

Я выбрал выбор типов (Type inference) и as const в качестве решения, потому что хотел реализовать его максимально гибким и с минимальным количеством кода.

P.S. Это мои первые шаги в области написания веб-статей, и это соответственно моя первая статья. Поэтому я хотел начать с чего-то небольшого, чтобы поделиться полезной информацией со всеми вами. Буду рад вашим комментариям. Спасибо!

Tags:
Hubs:
Total votes 20: ↑17 and ↓3+16
Comments25

Articles