Pesquisa de site

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){
}

Artigos relacionados