recherche

Maison  >  Questions et réponses  >  le corps du texte

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

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粉139351297P粉139351297353 Il y a quelques jours518

répondre à tous(1)je répondrai

  • P粉509383150

    P粉5093831502024-01-11 10:57:21

    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 < /code>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🎜🎜

    répondre
    0
  • Annulerrépondre