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'
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;
}
_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 definirlist
comostatic
@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 definirlist
comostatic
@vegerot Você não pode usar
const
diretamente no escopo declass
, 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 definirlist
comostatic
@vegerot Você não pode usar
const
diretamente no escopo declass
, 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
Comentários muito úteis
em [email protected] e acima. resolva assim