Setiap kali saya menulis sebagai Foo dalam TypeScript, saya merasakan beratnya kekalahan.
Terdapat satu senario di mana perasaan ini sangat sengit: apabila fungsi mengambil parameter yang bergantung pada "mod" yang aktif.
lebih jelas dengan beberapa contoh kod:
1 2 3 4 5 6 7 8 9 10 11 12 | type Provider = "PROVIDER A" | "PROVIDER B" ;
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };
function connect(provider: Provider, options: ProviderAOpts | ProviderBOpts) {
switch (provider) {
case "PROVIDER A" :
case "PROVIDER B" :
}
}
|
Salin selepas log masuk
(Saya cuba menggunakan nama yang lebih realistik berbanding foo, goo, anjing dan kucing).
Jika anda telah meluangkan sedikit masa dengan TypeScript, anda mungkin mengesyaki kami pernah mengendalikan perkara ini sebagai ProviderAOpts, sebagai ProviderBOpts.
Tetapi ada masanya anda menghentak penumbuk anda di atas meja dan mendakwa: "Tiada lagi!"
1. Apa yang tidak berkesan
Perkara pertama yang selalu terlintas di fikiran saya dalam kes ini ialah menggunakan fungsi lebih muatan:
1 2 3 4 5 6 7 8 9 10 11 | function connect(provider: "PROVIDER A" , options: ProviderAOpts): void;
function connect(provider: "PROVIDER B" , options: ProviderBOpts): void;
function connect(provider: Provider, options: ProviderAOpts | ProviderBOpts) {
switch (provider) {
case "PROVIDER A" :
case "PROVIDER B" :
}
}
|
Salin selepas log masuk
Yang tidak berkesan. Tandatangan fungsi tidak disimpulkan dengan betul. Parameter pilihan sentiasa ProviderAOpts | ProviderBOpts. yang akan menyelesaikan kepada kesatuan bersama.
Ts tidak memautkan kedua-dua parameter dengan betul.
2. Perkara yang berfungsi tetapi tidak memautkan parameter
Alat seterusnya yang saya cuba ialah Jenis Predikat:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | type ConnectOptions = ProviderAOpts | ProviderBOpts;
function isAOptions(options: ConnectOptions): options is ProviderAOpts {
return (options as ProviderAOpts).$$$ !== undefined;
}
function isBOptions(options: ConnectOptions): options is ProviderBOpts {
return (options as ProviderBOpts).$$$ !== undefined;
}
function connect(provider: Provider, options: ConnectOptions) {
switch (provider) {
case "PROVIDER A" :
if (isAOptions(options)) {
...
}
case "PROVIDER B" :
if (isBOptions(options)) {
...
}
}
...
}
|
Salin selepas log masuk
Tetapi secara jujur, kami tidak menyelesaikan apa-apa. Kami baru sahaja memindahkan as di bawah permaidani ?. Memperkenalkan ifs tambahan dan, kami masih tidak memautkan parameter.
3. Apa yang tidak berkesan dan membuatkan saya menangis
Generik. Saya cuba menggunakan generik untuk memautkan parameter. Tidak berfungsi:
1 2 3 4 5 6 7 8 9 10 11 | function connect<T extends Provider>(
provider: T,
options: T extends "PROVIDER A" ? ProviderAOpts : ProviderBOpts
) {
switch (provider) {
case "PROVIDER A" :
case "PROVIDER B" :
}
}
|
Salin selepas log masuk
Saya cuba bersungguh-sungguh dan berjaya setakat ini
Tapi akhirnya tak kisah pun
Saya terpaksa jatuh untuk kehilangan semuanya
Tapi akhirnya tak kisah pun
?
4. Apa yang berfungsi tetapi memaksa kita menukar tandatangan fungsi
Mengubah suai parameter opts menambahkan jenis pembekal melakukan silap mata:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | type Provider = "PROVIDER A" | "PROVIDER B" ;
type ProviderOptsBase = {
provider: Provider;
}
type ProviderAOpts = ProviderOptsBase & {
provider: "PROVIDER A" ;
...;
};
type ProviderBOpts = ProviderOptsBase & {
provider: "PROVIDER B" ;
...;
};
function connect(options: ConnectOptions) {
switch (options.provider) {
case "PROVIDER A" :
case "PROVIDER B" :
}
}
|
Salin selepas log masuk
Ini adalah penyelesaian yang paling biasa, tetapi tidak selalu boleh menukar tandatangan fungsi. Atau mungkin anda tidak mahu. Soal prinsip ?.
Twitter untuk menyelamatkan
Terima kasih kepada Mateusz Burzyński (@AndaristRake) dan Lenz Weber (@phry)
kita boleh ke... ??
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | type Provider = "PROVIDER A" | "PROVIDER B" ;
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };
function connect(
...[provider, options]:
| [ "PROVIDER A" , ProviderAOpts]
| [ "PROVIDER B" , ProviderBOpts]
) {
switch (provider) {
case "PROVIDER A" :
case "PROVIDER B" :
...
}
}
|
Salin selepas log masuk
5. Apa yang berfungsi: tupel yang dimusnahkan
1 2 3 | connect( "PROVIDER A" , { ... });
connect( "PROVIDER B" , { ... });
^ autocomplete works ✅
|
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Jadi perkaranya ialah kami sedang memusnahkan tuple (array) dengan jenis yang tepat yang kami mahukan.
Satu-satunya kelemahan, jika kita memilih, menambah lebih banyak pasangan pada tupel... kita boleh mengekstrak jenis generik di sini:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | type Provider = "PROVIDER A" | "PROVIDER B" ;
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };
type ProviderOpts = {
"PROVIDER A" : ProviderAOpts;
"PROVIDER B" : ProviderBOpts;
};
type ConnectOptions = {
[K in keyof ProviderOpts]: [K, ProviderOpts[K]];
}[keyof ProviderOpts];
function connect(...[provider, options]: ConnectOptions) {
switch (provider) {
case "PROVIDER A" :
case "PROVIDER B" :
...
}
}
|
Salin selepas log masuk
6. Apakah yang berfungsi: penyelesaian tuple umum
1 2 3 | connect( "PROVIDER A" , { ... });
connect( "PROVIDER B" , { ... });
^ autocomplete works ✅
|
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | type Provider = "PROVIDER A" | "PROVIDER B" ;
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };
type ProviderOpts = {
"PROVIDER A" : ProviderAOpts;
"PROVIDER B" : ProviderBOpts;
};
type KeyOpts<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T];
function connect(...[provider, options]: KeyOpts<ProviderOpts>) {
switch (provider) {
case "PROVIDER A" :
case "PROVIDER B" :
...
}
}
|
Salin selepas log masuk
7. TL;DR. COPY PASTE, TERIMA KASIH
1 2 3 | connect( "PROVIDER A" , { ... });
connect( "PROVIDER B" , { ... });
^ autocomplete works ✅
|
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Terima kasih kepada Mateusz dan Lenz atas bantuan ?.
terima kasih kerana membaca ?.
<script>
// Detect dark theme
var iframe = document.getElementById('tweet-1840828253684056557-683');
if (document.body.className.includes('dark-theme')) {
iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1840828253684056557&theme=dark"
}
</script>
<script>
// Detect dark theme
var iframe = document.getElementById('tweet-1840346445334864141-950');
if (document.body.className.includes('dark-theme')) {
iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1840346445334864141&theme=dark"
}
</script>
Atas ialah kandungan terperinci Ts Lanjutan: Parameter bergantung, kesatuan yang disimpulkan dan interaksi yang sihat di Twitter.. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!