Como definir tipo de união de literal de string a partir de constantes em Typescript
Eu sei que posso definir tipos de união de strings para restringir variáveis a um dos possíveis valores de string:
type MyType = 'first' | 'second'
let myVar:MyType = 'first'
Eu preciso construir um tipo assim a partir de strings constantes, por exemplo:
const MY_CONSTANT = 'MY_CONSTANT'
const SOMETHING_ELSE = 'SOMETHING_ELSE'
type MyType = MY_CONSTANT | SOMETHING_ELSE
Mas, por algum motivo, não funciona; diz MY_CONSTANT refere-se a um valor, mas está sendo usado como um tipo aqui.
Por que o Typescript permite o primeiro exemplo, mas não permite o segundo caso? Estou usando o Typescript 3.4.5
Resposta #1
Para obter o tipo de uma variável, você precisa usar o operador de tipo typeof:
const MY_CONSTANT = 'MY_CONSTANT' // must be const, no annotation. let or var will not work
const SOMETHING_ELSE = 'SOMETHING_ELSE' // must be const, no annotation. let or var will not work
type MyType = typeof MY_CONSTANT | typeof SOMETHING_ELSE
Parque infantil
Nota:
Como parece haver muita confusão quando as pessoas usam isso. O const é importante. Se você usar outros tipos de declarações (let ou var), o tipo final seria string. Apenas const preserva os tipos literais de string.
Nota 2:
Para que esta solução funcione, você não deve especificar nenhuma anotação de tipo no const, e deve deixar o compilador inferir o tipo das constantes (por exemplo, isso não funcionará: const MY_CONSTANT: string='MY_CONSTANT')
Resposta #2
Você também pode usar enum para este caso. Por exemplo:
// Define enum.
enum myConstants {
MY_CONSTANT = 'my_constant',
SMTH_ELSE = 'smth_else'
}
// Use it in an interface for typechecking.
interface MyInterface {
myProp: myConstants
}
// Example of correct object - no errors.
let a: MyInterface = {
myProp: myConstants.MY_CONSTANT
}
// Incorrect value - TS reports an error.
let b: MyInterface = {
myProp: 'John Doe'
}
Mais sobre enums
Resposta #3
Enums cobrem o caso muito bem:
export enum ITEM_TYPES {
TYPE1 = 'text',
TYPE2 = 'image'
}
export type IItemType = ITEM_TYPES.TYPE1 | ITEM_TYPES.TYPE2
E então, no código, ITEM_TYPES pode ser referenciado para todos os tipos de comparações em tempo de execução:
if (type === ITEM_TYPES.TYPE1){
}
