Diga que tenho lista
const list = ['a', 'b', 'c']
É possível derivar desse tipo de união de valor que é 'a' | 'b' | 'c'
?
Eu quero isso porque quero definir o tipo que permite apenas valores de array estático e também precisa enumerar esses valores em tempo de execução, então eu uso array.
Exemplo de como pode ser implementado com um objeto indexado:
const indexed = {a: null, b: null, c: null}
const list = Object.keys(index)
type NeededUnionType = keyof typeof indexed
Gostaria de saber se é possível fazer isso sem usar um mapa indexado.
typescript
COR BRANCA
fonte
fonte
Respostas:
ATUALIZAÇÃO de fevereiro de 2019
No TypeScript 3.4, que deve ser lançado em março de 2019 , será possível dizer ao compilador para inferir o tipo de uma tupla de literais como uma tupla de literais , em vez de, digamos,
string[]
usando aas const
sintaxe . Esse tipo de asserção faz com que o compilador deduza o tipo mais restrito possível para um valor, incluindo fazer tudoreadonly
. Deve ser assim:const list = ['a', 'b', 'c'] as const; // TS3.4 syntax type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';
Isso eliminará a necessidade de uma função auxiliar de qualquer tipo. Boa sorte novamente a todos!
ATUALIZAÇÃO julho de 2018
Parece que, a partir do TypeScript 3.0, será possível para o TypeScript inferir automaticamente os tipos de tupla . Depois de liberada, a
tuple()
função de que você precisa pode ser escrita sucintamente como:export type Lit = string | number | boolean | undefined | null | void | {}; export const tuple = <T extends Lit[]>(...args: T) => args;
E então você pode usá-lo assim:
const list = tuple('a','b','c'); // type is ['a','b','c'] type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'
Espero que funcione para as pessoas!
ATUALIZAÇÃO dezembro de 2017
Desde que postei esta resposta, descobri uma maneira de inferir tipos de tupla se você estiver disposto a adicionar uma função à sua biblioteca. Verifique a função
tuple()
em tuple.ts . Usando-o, você pode escrever o seguinte e não se repetir:const list = tuple('a','b','c'); // type is ['a','b','c'] type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'
Boa sorte!
ORIGINAL julho de 2017
Um problema é que o literal
['a','b','c']
será inferido como tipostring[]
, portanto, o sistema de tipos esquecerá os valores específicos. Você pode forçar o sistema de tipos a lembrar cada valor como uma string literal:const list = ['a' as 'a','b' as 'b','c' as 'c']; // infers as ('a'|'b'|'c')[]
Ou, talvez melhor, interprete a lista como um tipo de tupla:
const list: ['a','b','c'] = ['a','b','c']; // tuple
Essa é uma repetição irritante, mas pelo menos não apresenta um objeto estranho em tempo de execução.
Agora você pode obter o seu sindicato assim:
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'.
Espero que ajude.
fonte
cont xs = ['a','b','c']; const list = tuple(...xs);
const xs = ['a','b','c']
o compilador já aumentouxs
parastring[]
e completamente esquecido os valores específicos. Não posso evitar esse comportamento, pelo menos a partir do TS3.2 (pode haver umaas const
notação futura que funcione). De qualquer forma, acho que a resposta como está ainda é a mais correta que posso fazer (menciono lá que['a','b','c']
está inferido comostring[]
), então não tenho certeza do que mais você precisa.[number]
fazlist[number]
?(typeof list)[number]
... nãotypeof (list[number])
. O tipoT[K]
é um tipo de pesquisa que obtém o tipo da propriedade deT
cuja chave éK
. Em(typeof list)[number]
, você está obtendo os tipos de propriedades de(typeof list)
cujas chaves pertencemnumber
. Arrays comotypeof list
têm assinaturas de índice numérico , portanto, suanumber
chave produz a união de todas as propriedades indexadas numericamente.Atualização para TypeScript 3.4:
Uma nova sintaxe chamada "contextos const" que chegará no TypeScript 3.4 permitirá uma solução ainda mais simples que não requer uma chamada de função conforme demonstrado. Este recurso está atualmente em análise, conforme visto neste PR .
Resumindo, essa sintaxe permite a criação de matrizes imutáveis que possuem um tipo restrito (ou seja, o tipo em
['a', 'b', 'c']
vez de('a' | 'b' | 'c')[]
oustring[]
). Dessa forma, podemos criar tipos de união a partir de literais tão fácil quanto mostrado abaixo:const MY_VALUES = <const> ['a', 'b', 'c'] type MyType = typeof MY_VALUES[number]
Na sintaxe alternativa:
const MY_VALUES = ['a', 'b', 'c'] as const type MyType = typeof MY_VALUES[number]
fonte
Não é possível fazer isso com Array.
O motivo é que, mesmo se você declarar a variável como const, o conteúdo de um array ainda pode mudar, portanto, @jonrsharpe menciona que isso é tempo de execução.
Dado o que você deseja, pode ser melhor usar
interface
comkeyof
:interface X { a: string, b: string } type Y = keyof X // Y: 'a' | 'b'
Ou
enum
:fonte
a
campo ..Pick<T, U>
para isso.Se estiver usando um objeto para armazenar "constantes", esta é uma maneira de implementar a mesma ideia:
(Observe o 'as const' para alterar o tipo de keyOne e keyTwo de string para literal.)
const configObj = { keyOne: 'literalTypeValueOne' as const, keyTwo: 'literalTypeValueTwo' as const, }; const typeValues = [configObj.keyOne, configObj.keyTwo] as const; type MyType = typeof typeValues[number];
fonte