Массив TypeScript для строкового литерала
В настоящее время у меня есть как массив строк, так и строковый литерал, содержащий те же строки:
const furniture = ['chair', 'table', 'lamp'];
type Furniture = 'chair' | 'table' | 'lamp';
Мне нужно как в моем приложении, но я пытаюсь сохранить код DRY. Так есть ли способ сделать вывод один из другого?
Я в основном хочу сказать что-то вроде type Furniture = [any string in furniture array]
, поэтому нет повторяющихся строк.
Ответы
Ответ 1
Обновление для TypeScript 3.0:
С использованием универсальных параметров отдыха есть способ правильно вывести string[]
как тип литерального кортежа, а затем получить тип объединения литералов.
Это выглядит так:
const tuple = <T extends string[]>(...args: T) => args;
const furniture = tuple('chair', 'table', 'lamp');
type Furniture = typeof furniture[number];
Подробнее об общих параметрах отдыха
Обновление для TypeScript 3.4:
В TypeScript версии 3.4 введены так называемые const contexts, которые позволяют объявлять тип кортежа как неизменяемый и получать узкий литеральный тип напрямую (без необходимости вызывать функцию, подобную показанной выше).
С этим новым синтаксисом мы получаем это хорошее краткое решение:
const furniture = <const> ['chair', 'table', 'lamp'];
type Furniture = typeof furniture[number];
Подробнее о новых контекстах const можно найти в этом PR, а также в заметках о выпуске.
Ответ 2
Лучший доступный обходной путь:
const furnitureObj = { chair: 1, table: 1, lamp: 1 };
type Furniture = keyof typeof furnitureObj;
const furniture = Object.keys(furnitureObj) as Furniture[];
В идеале мы могли бы сделать это:
const furniture = ['chair', 'table', 'lamp'];
type Furniture = typeof furniture[number];
К сожалению, сегодня furniture
выводится как string[]
, что означает, что Furniture
теперь также является string
.
Мы можем ввести типизацию как литерал с ручной аннотацией, но это возвращает дублирование:
const furniture = ["chair", "table", "lamp"] as ["chair", "table", "lamp"];
type Furniture = typeof furniture[number];
Выпуск TypeScript # 10195 отслеживает возможность подсказки TypeScript, что список должен выводиться как статический кортеж, а не как string[]
, поэтому, возможно, в будущем это будет возможно.
Ответ 3
Единственная корректировка, которую я хотел бы предложить, - сделать const
гарантированной совместимой с типом, например:
type Furniture = 'chair' | 'table' | 'lamp';
const furniture: Furniture[] = ['chair', 'table', 'lamp'];
Это даст вам предупреждение, если вы сделаете орфографическую ошибку в массиве или добавите неизвестный элемент:
// Warning: Type 'unknown' is not assignable to furniture
const furniture: Furniture[] = ['chair', 'table', 'lamp', 'unknown'];
Единственный случай, который вам не поможет, - это то, где массив не содержит одно из значений.
Ответ 4
оказывается, есть более простой способ сделать это, и он работает с обычными старыми объектами.
Таким образом, вы могли бы это сделать.
const furnitureObj = { chair: 'chair', table: {$:1.00}, lamp: 2 };
type Furnitures = keyof typeof furnitureObj;
Или вы можете это сделать
import { furnitureObj } from './your-furniture-path';
type Furnitures = keyof typeof furnitureObj;