Typescript: Criação de tipos a partir de valores na matriz

Criado em 22 out. 2018  ·  16Comentários  ·  Fonte: microsoft/TypeScript


Versão TypeScript: 3.0.3


Termos de pesquisa: tipo baseado em valores na matriz

Existe um recurso atual ou planejado para criar um tipo de strings em uma matriz?

Código

const values = ['A', 'B']
type Foo = OneOf<values> // Is there a way of doing this?

const v1: Foo = 'A' // This should work
const v2: Foo = 'D' // This should give me an error since 'D' doesn't exist in values

Semelhante a como funciona keyof :

const values = {
  A: 'A',
  B: 'B'
}
type Foo = keyof typeof values
const v1: Foo = 'A'
const v2: Foo = 'D' // Type '"D"' is not assignable to type '"A" | "B"'

Assuntos relacionados:https://github.com/Microsoft/TypeScript/issues/20965

Link para o playground http://www.typescriptlang.org/play/#src = let% 20vals1% 20% 3D% 20% 5B'A '% 2C% 20'B'% 5D% 0D% 0Atype% 20Foo1% 20% 3D% 20OneOf% 3Cvals1% 3E% 20% 2F% 2F% 20Is% 20there% 20a% 20way% 20of% 20doing% 20this% 3F% 0D% 0A% 0D% 0Alet% 20v1% 3A% 20Foo1% 20% 3D% 20 ' A '% 20% 2F% 2F% 20Este% 20deve% 20trabalho% 0D% 0Alet% 20v2% 3A% 20Foo1% 20% 3D% 20'D'% 20% 2F% 2F% 20Este% 20devem% 20give% 20me% 20an% 20error% 20since% 20'D '% 20não% 20existe% 20in% 20values% 0D% 0A% 0D% 0Alet% 20vals2% 20% 3D% 20% 7B% 0D% 0A% 20% 20A% 3A% 20'A '% 2C% 0D% 0A% 20% 20B% 3A% 20'B'% 0D% 0A% 7D% 0D% 0Atype% 20Foo2% 20% 3D% 20keyof% 20typeof% 20vals2% 0D% 0Alet% 20v3% 3A% 20Foo2 % 20% 3D% 20'A '% 0D% 0Alet% 20v4% 3A% 20Foo2% 20% 3D% 20'D'% 20% 2F% 2F% 20Type% 20 '% 22D% 22'% 20is% 20not% 20atribuível % 20to% 20type% 20 '% 22A% 22% 20% 7C% 20% 22B% 22'

Question

Comentários muito úteis

em [email protected] e acima. resolva assim

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Todos 16 comentários

keyof só funciona porque usa informações conhecidas estaticamente em tempo de compilação. Tipos no TS são totalmente apagáveis ​​e não existem no código transpilado, portanto, simplesmente não é possível criar um tipo com base no conteúdo de tempo de execução de um array.

Isso é possível:

function stringLiterals<T extends string>(...args: T[]): T[] { return args; }
type ElementType<T extends ReadonlyArray<unknown>> = T extends ReadonlyArray<infer ElementType> ? ElementType : never;

const values = stringLiterals('A', 'B');
type Foo = ElementType<typeof values>;

const v1: Foo = 'A' // This should work
const v2: Foo = 'D' // This should give me an error since 'D' doesn't exist in values

Definitivamente não está claro como fazer isso. # 27179 está relacionado.

Isso ainda está usando informações conhecidas estaticamente pelo compilador; nesse ponto, não entendo qual é a vantagem de apenas dizer ”A” | “B” .

@fatcerberus É útil evitar a repetição de informações - se você apenas escrever const values = ["A", "B"]; type Foo = "A" | "B"; , é fácil para alguém mudar um deles enquanto se esquece de mudar o outro. Você poderia escrever const values: Foo[] =["A", "B"]; , mas isso ainda é suscetível de adicionar uma entrada adicional a Foo e esquecer de colocá-la em values .

Onde estamos nisso agora?

Como @ andy-ms disse, seria muito útil evitar a repetição de informações manualmente.
E, como disse @fatcerberus , os tipos são totalmente apagáveis. Às vezes, precisamos verificar os dados de tempo de execução que obtemos, por exemplo, de uma parte não pura do aplicativo (como serviço da web ou do usuário).

Com base na resposta de @ andy-ms e usando const assertions introduzidas no typescript 3.4, agora é possível fazer algo assim

const values = ['A', 'B'] as const
type ElementType < T extends ReadonlyArray < unknown > > = T extends ReadonlyArray<
  infer ElementType
>
  ? ElementType
  : never

type Foo = ElementType<typeof values> // this is correctly inferred as literal "A" | "B"

Este problema foi marcado como 'Pergunta' e não teve nenhuma atividade recente. Ele foi fechado automaticamente para fins de manutenção. Se você ainda está esperando uma resposta, as perguntas geralmente são mais adequadas para o stackoverflow .

em [email protected] e acima. resolva assim

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Em vez disso:

export const items = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof items[number];
}

Você consegue fazer isso:

export const items = [
  'room',
  'room_with_gifter',
  'user_send'
] as const;

export type Item = typeof items;

export interface Activity {
  id?: string;
  type: Item;
}

image

_Realmente não gosto de usar type como um nome de variável._

@ 7kms

em [email protected] e acima. resolva assim

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Agora, e se eu tiver isso em uma aula?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

Não funciona. Também não posso fazer this.list[number] . Além disso, para meu particular
caso de uso, não posso definir list como static

@ 7kms

em [email protected] e acima. resolva assim

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Agora, e se eu tiver isso em uma aula?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

Não funciona. Também não posso fazer this.list[number] . Além disso, para meu particular
caso de uso, não posso definir list como static

@vegerot Você não pode usar const diretamente no escopo de class , então a sintaxe está incorreta.

@ 7kms

em [email protected] e acima. resolva assim

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Agora, e se eu tiver isso em uma aula?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

Não funciona. Também não posso fazer this.list[number] . Além disso, para meu particular
caso de uso, não posso definir list como static

@vegerot Você não pode usar const diretamente no escopo de class , então a sintaxe está incorreta.

@ 7kms Meu mal. Copiei e colei muito. O que eu quis dizer é

class Class {
  private list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 private withType: typeof list[number];

// OR
  private withType2: typeof this.list[number];

}

etc. nem todos funcionam.
Além disso, para meu caso de uso específico, não posso definir a lista como estática

@ 7kms

em [email protected] e acima. resolva assim

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Agora, e se eu tiver isso em uma aula?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

Não funciona. Também não posso fazer this.list[number] . Além disso, para meu particular
caso de uso, não posso definir list como static

@vegerot Você não pode usar const diretamente no escopo de class , então a sintaxe está incorreta.

@ 7kms Meu mal. Copiei e colei muito. O que eu quis dizer é

class Class {
  private list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 private withType: typeof list[number];

// OR
  private withType2: typeof this.list[number];

}

etc. nem todos funcionam.
Além disso, para meu caso de uso específico, não posso definir a lista como estática

class Class {
  private list = [
    "room",
    "room_with_gifter",
    "user_send"
  ] as const

  private withType: Class["list"][number]
}

@vegerot Que tal isso?

@eyalch isso é incrível! Obrigado. Achei que a solução envolveria typeof ou algo assim. Você daria uma explicação rápida sobre como isso funciona ou me direcionaria para o manual onde isso é discutido?

@eyalch isso é incrível! Obrigado. Achei que a solução envolveria typeof ou algo assim. Você daria uma explicação rápida sobre como isso funciona ou me direcionaria para o manual onde isso é discutido?

@vegerot Claro, acredito que seja um "tipo de índice". Aqui está no Handbook: https://www.typescriptlang.org/docs/handbook/advanced-types.html#index -types

Que bom que pude ajudar!

Ei,% username%, se a solução ElementType não funcionar para você também,
preste atenção em as const após array . É crucial

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

siddjain picture siddjain  ·  3Comentários

CyrusNajmabadi picture CyrusNajmabadi  ·  3Comentários

MartynasZilinskas picture MartynasZilinskas  ·  3Comentários

remojansen picture remojansen  ·  3Comentários

blendsdk picture blendsdk  ·  3Comentários