Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
IT Security ToolsMeta_SecAlign(01.10.2026 um 02:46 Uhr)
•••
IT Security NachrichtenAlphabet Aktie: Gemini 4 Argon startet - Börse Express(01.10.2026 um 01:57 Uhr)
••••
Sichere Programmierung[$] LWN.net Weekly Edition for October 1, 2026(01.10.2026 um 02:30 Uhr)
•
KI & AI VideosJulian Goldie SEO: Gemini 4 Argon just dropped!(01.10.2026 um 02:45 Uhr)
•
KI & AI VideosJulian Goldie SEO: Gemini 4 Argon!(01.10.2026 um 02:48 Uhr)
•
IT Security ToolsMeta_SecAlign(01.10.2026 um 02:46 Uhr)
•••
IT Security NachrichtenAlphabet Aktie: Gemini 4 Argon startet - Börse Express(01.10.2026 um 01:57 Uhr)
••••
Sichere Programmierung[$] LWN.net Weekly Edition for October 1, 2026(01.10.2026 um 02:30 Uhr)
•
KI & AI VideosJulian Goldie SEO: Gemini 4 Argon just dropped!(01.10.2026 um 02:45 Uhr)
•
KI & AI VideosJulian Goldie SEO: Gemini 4 Argon!(01.10.2026 um 02:48 Uhr)
•
Intelligence View
⚡ tsecurity.de Intelligence

Advanced Ts: Dependent parameters, inferred unions and a healthy interaction on Twitter.

Every time I write as Foo in TypeScript, I feel the weight of defeat. There's one scenario where this feeling is particularly intense: when a function takes a…

Beitrag
0
Seite
0
↗ Quelle (dev.to)
Social ReaktionenReagiere als Erste:r — dein Feedback zählt!




Every time I write as Foo in TypeScript, I feel the weight of defeat.



There's one scenario where this feeling is particularly intense: when a function takes a parameter that depends on which "mode" is active.



clearer with some example code:




type Provider = "PROVIDER A" | "PROVIDER B";
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };

function connect(provider: Provider, options: ProviderAOpts | ProviderBOpts) {
switch (provider) {
case "PROVIDER A":
// options is ProviderAOpts
case "PROVIDER B":
// options is ProviderBOpts
}
}






(I tried to use more realistic names rather than foo, goo, dog and cat).



If you’ve spent some time with TypeScript, you might suspect we used to handle this with as ProviderAOpts, as ProviderBOpts.






But there’s a time you slam your fist on the table and claim: "No more!"









1. What doesn't work



The first thing that always comes to my mind in these cases is to use function overloading:




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":
// (options as ProviderAOpts) ❌
case "PROVIDER B":
// (options as ProviderBOpts) ❌
}
}






Which doesn't work. The function signature is not inferred correctly. The options parameter is always ProviderAOpts | ProviderBOpts. which will resolve to the common union.


Ts doesn't link both parameters correctly.







2. What works but isn't linking the parameters



The next tool I try are Type Predicates:




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)) {
...
}
}
...
}






But honestly, we did not solve anything. We just moved the as under the rug 🧹. Introduced extra ifs and, we are still not linking the parameters.









3. What doesn't work and makes me cry



Generics. I tried to use generics to link the parameters. Doesn't work:




function connect<T extends Provider>(
provider: T,
options: T extends "PROVIDER A" ? ProviderAOpts : ProviderBOpts
) {
switch (provider) {
case "PROVIDER A":
// (options as ProviderAOpts) ❌
case "PROVIDER B":
// (options as ProviderBOpts) ❌
}
}







I tried so hard and got so far

But in the end, it doesn't even matter

I had to fall to lose it all

But in the end, it doesn't even matter

🧑‍🎤










4. What does work but forces us to change the function signature



Modifying the opts parameters adding the provider type does the trick:




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":
// options is ProviderAOpts ✅
case "PROVIDER B":
// options is ProviderBOpts ✅
}
}






This is the most common solution, but it's not always possible to change the function signature. Or maybe you just don't want to. Matter of principles 🫖.









Twitter to the rescue



Thanks to Mateusz Burzyński (@AndaristRake) and Lenz Weber (@phry)






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








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





we can get to... 🥁🥁









5. What does work: the destructured tuple






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":
// options is ProviderAOpts ✅
case "PROVIDER B":
// options is ProviderBOpts ✅
...
}
}









connect("PROVIDER A", { ... });
connect("PROVIDER B", { ... });
^ autocomplete works ✅






So the thing is that we are destructuring a tuple (array) with the exact types we want.



The only downside, if we're picky, adding more pairs to the tuple... we can extract a generic type here:









6. What does work: generalized tuple solution






type Provider = "PROVIDER A" | "PROVIDER B";
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };

type ProviderOpts = {
"PROVIDER A": ProviderAOpts;
"PROVIDER B": ProviderBOpts;
};

// solves to
// ["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":
// options is ProviderAOpts ✅
case "PROVIDER B":
// options is ProviderBOpts ✅
...
}
}









connect("PROVIDER A", { ... });
connect("PROVIDER B", { ... });
^ autocomplete works ✅









7. TL;DR. COPY PASTE, THANKS






type Provider = "PROVIDER A" | "PROVIDER B";
type ProviderAOpts = { ... };
type ProviderBOpts = { ... };

type ProviderOpts = {
"PROVIDER A": ProviderAOpts;
"PROVIDER B": ProviderBOpts;
};

// aux type to extract the key and the options from ProviderOpts
type KeyOpts<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T];


function connect(...[provider, options]: KeyOpts<ProviderOpts>) {
switch (provider) {
case "PROVIDER A":
// options is ProviderAOpts ✅
case "PROVIDER B":
// options is ProviderBOpts ✅
...
}
}









connect("PROVIDER A", { ... });
connect("PROVIDER B", { ... });
^ autocomplete works ✅









Thanks to Mateusz and Lenz for the help 🙏.



thanks for reading 💙.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Advanced Ts: Dependent parameters, inferred unions and a healthy interaction on Twitter.

Thematisch verwandte Begriffe: Advanced, Dependent, parameters, inferred · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag