Как определить тип строкового литерала как подтип другого типа строкового литерала?

#typescript

Вопрос:

Как я могу создать тип строкового литерала как подтип другого типа строкового литерала?

Или, другими словами, как я могу выбрать значения из строкового литерального типа для создания нового типа?

Пример:

 type Animal = 'goldfish' | 'tuna' | 'elephant'

// I would like to use Pick:
type Fish = Pick<Animal, 'goldfish', 'tuna'>

// So that the desired result is: 'goldfish | 'tuna'
 

Однако это не работает, потому что выбор работает только при выборе ключей свойств (объекта).

Комментарии:

1. Можете ли вы уточнить свои ограничения? Вы могли бы сделать это просто как отдельный литерал , подобный type Fish = 'goldfish' | 'tuna'; , или как пересечение, подобное type Fish = Animal amp; ('goldfish' | 'lion'); .

2. Я добавил желаемый результат к вопросу, возможно, это было не совсем ясно. Вы правы, я хочу type Fish = 'goldfish' | 'tuna'; получить конечный результат, но я хочу выбрать значения, Animal чтобы обеспечить соблюдение правильных значений.

Ответ №1:

Вместо Pick этого ты можешь Extract . Однако в данном случае со строковыми литералами это не продвинет вас дальше amp; , чем.

 type Fish = Extract<Animal, 'goldfish' | 'lion'>   // 'goldfish'
type Fish2 = Animal amp; ('goldfish' | 'lion')        // 'goldfish'
 

В обоих этих случаях обратите внимание, что это не будет ошибкой во время компиляции, если вы попытаетесь выбрать запись, которая не является частью исходного набора; она просто будет опущена. С помощью общих ограничений ( extends ) вы можете написать свой собственный Subset тип, который выполняет эту задачу.

 type Subset<K, T extends K> = T;

type Fish3 = Subset<Animal, 'goldfish' | 'lion'>;  // compile error
type Fish4 = Subset<Animal, 'goldfish' | 'tuna'>;  // 'goldfish' | 'tuna'
 

Ссылка на игровую площадку

Комментарии:

1. Именно то, что мне нужно, спасибо, Джефф. Из любопытства, знаете ли вы, почему это не поддерживается встроенным типом утилиты? Типы строковых литералов популярны, и интуитивно я ожидаю, что они будут работать и для этого…

2. @rei Рад помочь! У меня нет хорошего ответа на вопрос, почему это не встроено, но, к счастью, это достаточно легко написать самостоятельно. Использование двух общих аргументов и возврат одного неизмененного немного необычно; если бы я предположил предложенную альтернативу, это было бы определить объединение строк без проверки, введите свои сайты вызовов как Animal и позвольте TS применять на сайте вызовов вместо определения типа. Конечно, это уводит ошибку от проблемы/исправления, поэтому, возможно, подмножество (или набор животных, если вы сделали конкретное) в этом случае все же лучше, за счет одной дополнительной строки кода для определения подмножества.