Version TypeScript: 3.0.3
Termes de recherche: type basé sur les valeurs du tableau
Existe-t-il une fonctionnalité actuelle ou prévue pour créer un type à partir de chaînes dans un tableau?
Code
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
Similaire au fonctionnement de 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"'
Problèmes liés:https://github.com/Microsoft/TypeScript/issues/20965
Lien vers le terrain de jeu 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% 20Ce% 20 devrait% 20 travail% 0D% 0Alet% 20v2% 3A% 20Foo1% 20% 3D% 20'D'% 20% 2F% 2F% 20Ce% 20 devrait% 20give% 20me% 20an% 20error% 20since% 20'D '% 20n'existe pas% 20exist% 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% 20assignable % 20 à% 20 type% 20 '% 22A% 22% 20% 7C% 20% 22B% 22'
keyof
fonctionne uniquement car il utilise des informations connues statiquement au moment de la compilation. Les types dans TS sont entièrement effaçables et n'existent pas dans le code transpilé, il n'est donc tout simplement pas possible de créer un type basé sur le contenu d'exécution d'un tableau.
C'est possible:
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
Cependant, on ne sait vraiment pas comment faire cela. # 27179 est lié.
Cela utilise toujours des informations connues statiquement par le compilateur; à ce stade, je ne comprends pas quel est l'avantage de simplement dire ”A” | “B”
.
@fatcerberus Il est utile d'éviter de répéter des informations - si vous écrivez simplement const values = ["A", "B"]; type Foo = "A" | "B";
il est facile pour quelqu'un de changer l'un d'eux tout en oubliant de changer l'autre. Vous pouvez écrire const values: Foo[] =["A", "B"];
, mais c'est toujours susceptible d'ajouter une entrée supplémentaire à Foo
et d'oublier de la mettre dans values
.
Où en sommes-nous maintenant?
Comme @ andy-ms l'a dit, il serait vraiment utile d'éviter de répéter les informations manuellement.
Et comme @fatcerberus l'a dit, les types sont entièrement effaçables. Nous avons parfois besoin de vérifier les données que nous obtenons par exemple à partir d'une partie non pure de l'application (comme le service Web ou de l'utilisateur).
En s'appuyant sur la réponse de @ andy-ms, et en utilisant les assertions const introduites dans typescript 3.4, il est maintenant possible de faire quelque chose comme ça
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"
Ce problème a été marqué comme "Question" et n'a connu aucune activité récente. Il a été automatiquement fermé à des fins d'entretien ménager. Si vous attendez toujours une réponse, les questions sont généralement mieux adaptées au stackoverflow .
dans [email protected] et au-dessus. résous-le comme ça
export const type = <const>[
'room',
'room_with_gifter',
'user_send'
];
export interface Activity {
id?: string;
type: typeof type[number];
}
Au lieu de cela:
export const items = <const>[
'room',
'room_with_gifter',
'user_send'
];
export interface Activity {
id?: string;
type: typeof items[number];
}
Tu peux le faire:
export const items = [
'room',
'room_with_gifter',
'user_send'
] as const;
export type Item = typeof items;
export interface Activity {
id?: string;
type: Item;
}
_ Je n'aime vraiment pas utiliser type
comme nom de variable._
À 7 km
dans [email protected] et au-dessus. résous-le comme ça
export const type = <const>[ 'room', 'room_with_gifter', 'user_send' ]; export interface Activity { id?: string; type: typeof type[number]; }
Et si j'ai ça dans une classe?
class Class {
const list = <const>[
'room',
'room_with_gifter',
'user_send'
];
const withType: typeof list[number];
}
Ne marche pas. Je ne peux pas non plus faire this.list[number]
. Aussi, pour mon particulier
usecase, je ne peux pas définir list
comme étant static
À 7 km
dans [email protected] et au-dessus. résous-le comme ça
export const type = <const>[ 'room', 'room_with_gifter', 'user_send' ]; export interface Activity { id?: string; type: typeof type[number]; }
Et si j'ai ça dans une classe?
class Class { const list = <const>[ 'room', 'room_with_gifter', 'user_send' ]; const withType: typeof list[number]; }
Ne marche pas. Je ne peux pas non plus faire
this.list[number]
. Aussi, pour mon particulier
usecase, je ne peux pas définirlist
comme étantstatic
@vegerot Vous ne pouvez pas utiliser const
directement dans la portée du class
, donc la syntaxe est incorrecte.
À 7 km
dans [email protected] et au-dessus. résous-le comme ça
export const type = <const>[ 'room', 'room_with_gifter', 'user_send' ]; export interface Activity { id?: string; type: typeof type[number]; }
Et si j'ai ça dans une classe?
class Class { const list = <const>[ 'room', 'room_with_gifter', 'user_send' ]; const withType: typeof list[number]; }
Ne marche pas. Je ne peux pas non plus faire
this.list[number]
. Aussi, pour mon particulier
usecase, je ne peux pas définirlist
comme étantstatic
@vegerot Vous ne pouvez pas utiliser
const
directement dans la portée duclass
, donc la syntaxe est incorrecte.
@ 7kms Mon mauvais. J'ai trop copié et collé. Ce que je voulais dire c'est
class Class {
private list = <const>[
'room',
'room_with_gifter',
'user_send'
];
private withType: typeof list[number];
// OR
private withType2: typeof this.list[number];
}
etc. tout ne fonctionne pas.
De plus, pour mon cas d'utilisation particulier, je ne peux pas définir la liste comme statique
À 7 km
dans [email protected] et au-dessus. résous-le comme ça
export const type = <const>[ 'room', 'room_with_gifter', 'user_send' ]; export interface Activity { id?: string; type: typeof type[number]; }
Et si j'ai ça dans une classe?
class Class { const list = <const>[ 'room', 'room_with_gifter', 'user_send' ]; const withType: typeof list[number]; }
Ne marche pas. Je ne peux pas non plus faire
this.list[number]
. Aussi, pour mon particulier
usecase, je ne peux pas définirlist
comme étantstatic
@vegerot Vous ne pouvez pas utiliser
const
directement dans la portée duclass
, donc la syntaxe est incorrecte.@ 7kms Mon mauvais. J'ai trop copié et collé. Ce que je voulais dire c'est
class Class { private list = <const>[ 'room', 'room_with_gifter', 'user_send' ]; private withType: typeof list[number]; // OR private withType2: typeof this.list[number]; }
etc. tout ne fonctionne pas.
De plus, pour mon cas d'utilisation particulier, je ne peux pas définir la liste comme statique
class Class {
private list = [
"room",
"room_with_gifter",
"user_send"
] as const
private withType: Class["list"][number]
}
@vegerot Et ça?
@eyalch c'est génial! Je vous remercie. Je pensais que la solution impliquerait typeof
ou quelque chose. Pourriez-vous expliquer rapidement comment cela fonctionne ou me relier au manuel où cela est discuté?
@eyalch c'est génial! Je vous remercie. Je pensais que la solution impliquerait
typeof
ou quelque chose. Pourriez-vous expliquer rapidement comment cela fonctionne ou me relier au manuel où cela est discuté?
@vegerot Bien sûr, je crois que c'est un "type d'index". Le voici dans le manuel: https://www.typescriptlang.org/docs/handbook/advanced-types.html#index -types
Heureux d'avoir pu aider!
Hey% username%, si la solution ElementType
ne fonctionne pas pour vous aussi,
attention sur as const
après le tableau . C'est crucial
Commentaire le plus utile
dans [email protected] et au-dessus. résous-le comme ça