Rumah > Soal Jawab > teks badan
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粉5093831502024-01-11 10:57:21
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 (
Rest
作为字符串传递以验证 Original
,并将 AlreadyUsed
< /code>Panggil jenis ini secara rekursif, tambahkan
T
是尺寸映射的键,不包括 AlreadyUsed
原始
Sudah Digunakan从不
KembaliKembali
tidak pernah
Item
添加一个通用参数来表示大小
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 | undefined
到 string
并将其传递给 _SizeValue
Kita 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🎜🎜