Bagaimana untuk menentukan jenis dalam TypeScript yang merupakan rentetan yang hanya boleh mengandungi perkataan daripada senarai yang dipratentukan
P粉139351297
P粉139351297 2024-01-10 17:24:00
0
1
487

Saya menghadapi masalah TypeScript yang rumit.

Andaikan saya mempunyai komponen ikon dengan saiz prop. Saiz boleh menjadi "2", "4", "6". Saya memetakan nilai ini ke kelas tailwind yang telah ditetapkan.

Jadi saya menaip begini

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" />

Semuanya baik-baik saja. Tetapi bagaimana jika saya ingin mempunyai saiz yang berbeza berdasarkan saiz skrin saya? Jadi saya ingin mencuba untuk mempunyai tatabahasa yang baik yang berjalan dengan lancar.

Jadi saya menulis semula komponen Ikon kepada yang berikut:

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" />

Ini berfungsi dengan baik, tetapi bagaimana saya boleh memasukkannya? Saya membaca bahawa TypeScript akan menyokong ungkapan biasa pada masa hadapan. Ini akan memudahkan urusan, tetapi bolehkah saya menaip ini sekarang?

Ini bukan komponen sebenar, jadi tolong jangan berikan saya cadangan yang baik tentang cara untuk memperbaikinya. Saya hanya tertanya-tanya bagaimana untuk memasukkan atribut saiz saya supaya ia berfungsi seperti yang saya kodkannya.

P粉139351297
P粉139351297

membalas semua(1)
P粉509383150

Pertama, kita perlu mengekstrak sizeMap ke dalam skop global dan const menegaskan untuk memberitahu pengkompil mengetahui bahawa ini adalah pemalar tidak berubah dan menyekatnya daripada mengembangkan jenis:

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;

Seterusnya, kita perlu mendapatkan jenis kunci sizeMap:

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

Pelaksanaan: Kami akan mencipta jenis yang menerima rentetan dan mengembalikannya jika rentetan itu sah, sebaliknya, mengembalikan never.

Kod pseudo:

Biarkan jenis menerima T - 要验证的字符串,Original - 原始字符串,AlreadyUsed - penyatuan kunci terpakai.

Jika T ialah rentetan kosong

  • Kembali原始 Jika tidak, jika T 以大小映射 (ClassName) 的键开头,不包括 AlreadyUsed,后跟一个空格和剩余的字符串(休息 bermula dengan kekunci peta saiz (

    Nama Kelas), tidak termasuk
  • Sudah Digunakan, diikuti dengan ruang dan rentetan yang tinggal (
  • break).

    Rest 作为字符串传递以验证 Original,并将 AlreadyUsed Panggil jenis ini secara rekursif, tambahkan

    dan
  • ClassName
padanya.

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

    Lain jika
  • ialah kunci peta saiz, tidak termasuk 原始Sudah Digunakan
  • 从不Kembali
  • Jika tidak

Kembali

tidak pernah

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

Perlaksanaan:

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 并将其传递给 _SizeValueKita perlu menambah parameter biasa pada Item untuk mewakili

saiz.

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

Memandangkan size adalah pilihan dalam komponen, kami akan menambah pembalut di sekeliling SizeValue yang akan menukar

string | undefined kepada 🎜string dan menyerahkannya kepada 🎜_SizeValue , selain itu kami akan menambah nilai lalai untuk saiz: 🎜
type SizeValue<T extends string | undefined> = _SizeValue<NonNullable<T>>;

function Icon<T extends string | undefined>({
  size = "2",
}: {
  size?: SizeValue<T> | "2";
}) {
  return null;
}
🎜Penggunaan: 🎜
<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" />;
🎜🎜Taman permainan🎜🎜
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan