Comment définir un type dans TypeScript qui est une chaîne qui ne peut contenir que des mots d'une liste prédéfinie
P粉139351297
P粉139351297 2024-01-10 17:24:00
0
1
488

J'ai un problème délicat avec TypeScript.

Supposons que j'ai un composant icône avec une taille d'accessoire. La taille peut être « 2 », « 4 », « 6 ». Je mappe ces valeurs à une classe de vent arrière prédéfinie.

Alors je tape comme ça

type SizeValues = '2' | '4' | '6';

function Icon({size = '4'}: {size: SizeValues}) {
   const sizeMap = {
     '2': 'w-2 h-2',
     '4': 'w-4 h-4',
     '6': 'w-6 h-6',
   };
 
   return <span className={sizeMap[size]}>My icon goes here</span>
}

<Icon size="sm" />

Tout va bien. Mais que se passe-t-il si je souhaite avoir des tailles différentes en fonction de la taille de mon écran ? Je veux donc essayer d’avoir une bonne grammaire qui se passe bien.

J'ai donc réécrit le composant Icon comme suit :

type SizeValues = ???

function Icon({size = '4'}: {size: SizeValues}) {
   const sizeMap = {
     '2': 'w-2 h-2',
     '4': 'w-4 h-4',
     '6': 'w-6 h-6',
     'md:2': 'md:w-2 md:h-2',
     'md:4': 'md:w-4 md:h-4',
     'md:6': 'md:w-6 md:h-6',
     'lg:2': 'lg:w-2 lg:h-2',
     'lg:4': 'lg:w-4 lg:h-4',
     'lg:6': 'lg:w-6 lg:h-6',
   };
 
   return <span className={size.split(' ').map(s => sizeMap[s]).join(' ').trim()}>My icon goes here</span>
}

<Icon size="2 md:4 lg:6" />

Cela fonctionne très bien, mais comment puis-je y accéder ? J'ai lu que TypeScript prendrait en charge les expressions régulières à l'avenir. Cela facilitera les choses, mais puis-je taper ceci maintenant ?

Ce n'est pas un composant réel, alors s'il vous plaît, ne me donnez pas de bonnes suggestions sur la façon de l'améliorer. Je me demande simplement comment saisir mon attribut de taille pour qu'il fonctionne comme je l'ai codé.

P粉139351297
P粉139351297

répondre à tous(1)
P粉509383150

Tout d'abord, nous devons extraire sizeMap dans la portée globale et const assert pour faire savoir au compilateur qu'il s'agit d'une constante immuable et l'empêcher d'étendre le type :

const sizeMap = {
  '2': 'w-2 h-2',
  '4': 'w-4 h-4',
  '6': 'w-6 h-6',
  'md:2': 'md:w-2 md:h-2',
  'md:4': 'md:w-4 md:h-4',
  'md:6': 'md:w-6 md:h-6',
  'lg:2': 'lg:w-2 lg:h-2',
  'lg:4': 'lg:w-4 lg:h-4',
  'lg:6': 'lg:w-6 lg:h-6',
} as const;

Ensuite, nous devons obtenir le type de clé de sizeMap :

type SizeMap = typeof sizeMap;
type SizeMapKeys = keyof SizeMap;

Mise en œuvre : Nous allons créer un type qui accepte une chaîne et renvoie cette chaîne si elle est valide, sinon, renvoie never ;

Pseudo-code :

Laissez le type accepter T - 要验证的字符串,Original - 原始字符串,AlreadyUsed - l'union des clés utilisées.

Si T est la chaîne vide

  • Retour原始 Sinon, si T 以大小映射 (ClassName) 的键开头,不包括 AlreadyUsed,后跟一个空格和剩余的字符串(休息 commence par la clé de la carte de taille (

    ClassName), exclut
  • AlreadyUsed, suivi d'un espace et de la chaîne restante (
  • break).

    Rest 作为字符串传递以验证 Original,并将 AlreadyUsed Appelez ce type de manière récursive, en y ajoutant

    et
  • ClassName
.

T 是尺寸映射的键,不包括 AlreadyUsed

    Sinon, si
  • est la clé de la carte des tailles, à l'exclusion de 原始AlreadyUsed
  • 从不Retour
  • Sinon

Retour

jamais

Item 添加一个通用参数来表示大小

Mise en œuvre :

type _SizeValue<
  T extends string,
  Original extends string = T,
  AlreadyUsed extends string = never
> = T extends ""
  ? Original
  : T extends `${infer ClassName extends Exclude<
      SizeMapKeys,
      AlreadyUsed
    >} ${infer Rest extends string}`
  ? _SizeValue<Rest, Original, AlreadyUsed | ClassName>
  : T extends Exclude<SizeMapKeys, AlreadyUsed>
  ? Original
  : never;
size 在组件中是可选的,因此我们将在 SizeValue 周围添加一个包装器,它将把 string | undefinedstring 并将其传递给 _SizeValueNous devons ajouter un paramètre commun à Item pour représenter la

size.

function Icon<T extends string | undefined>({
  size,
}: {
  size: _SizeValue<T>;
}) {
  return null;
}

Puisque size est facultatif dans le composant, nous ajouterons un wrapper autour de SizeValue qui convertira

string | undefined en 🎜string et le transmettra à 🎜_SizeValue , en plus nous ajouterons une valeur par défaut pour la taille : 🎜
type SizeValue<T extends string | undefined> = _SizeValue<NonNullable<T>>;

function Icon<T extends string | undefined>({
  size = "2",
}: {
  size?: SizeValue<T> | "2";
}) {
  return null;
}
🎜Utilisation : 🎜
<Icon size="2" />;
<Icon size="md:2" />;
<Icon size="md:2 md:6" />;
<Icon size="md:2 md:6 lg:6" />;

// expected error
<Icon size="md:2 md:6 lg:5" />;

// no duplicates allowed
<Icon size="2 2" />;
🎜🎜Aire de jeux🎜🎜
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal