Typescript: Création de types à partir de valeurs dans un tableau

Créé le 22 oct. 2018  ·  16Commentaires  ·  Source: microsoft/TypeScript


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'

Question

Commentaire le plus utile

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];
}

Tous les 16 commentaires

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;
}

image

_ 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éfinir list comme étant static

@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éfinir list comme étant static

@vegerot Vous ne pouvez pas utiliser const directement dans la portée du class , 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éfinir list comme étant static

@vegerot Vous ne pouvez pas utiliser const directement dans la portée du class , 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

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

wmaurer picture wmaurer  ·  3Commentaires

uber5001 picture uber5001  ·  3Commentaires

dlaberge picture dlaberge  ·  3Commentaires

MartynasZilinskas picture MartynasZilinskas  ·  3Commentaires

kyasbal-1994 picture kyasbal-1994  ·  3Commentaires