Typescript conditional return type based on string argument The 2019 Stack Overflow Developer Survey Results Are InTypescript: declare return type to be dependent on argument value?How do I make the method return type generic?Passing arguments to C# generic new() of templated typeType definition in object literal in TypeScriptTypeScript Objects as Dictionary types as in C#Are strongly-typed functions as parameters possible in TypeScript?TypeScript Converting a String to a numberHow to convert string to enum in TypeScript?Call new Date with union type “number | string”Typescript: Interfaces vs TypesUsing string literals types in Typescript
On the insanity of kings as an argument against monarchy
Why can Shazam do this?
What do the Banks children have against barley water?
Are USB sockets on wall outlets live all the time, even when the switch is off?
What tool would a Roman-age civilization have to grind silver and other metals into dust?
Springs with some finite mass
What could be the right powersource for 15 seconds lifespan disposable giant chainsaw?
A poker game description that does not feel gimmicky
Is this food a bread or a loaf?
What is the meaning of Triage in Cybersec world?
Monty Hall variation
Output the Arecibo Message
Does duplicating a spell with Wish count as casting that spell?
In microwave frequencies, do you use a circulator when you need a (near) perfect diode?
How to make payment on the internet without leaving a money trail?
The difference between dialogue marks
How can I create a character who can assume the widest possible range of creature sizes?
Inflated grade on resume at previous job, might former employer tell new employer?
What does "rabbited" mean/imply in this sentence?
Unbreakable Formation vs. Cry of the Carnarium
I looked up a future colleague on LinkedIn before I started a job. I told my colleague about it and he seemed surprised. Should I apologize?
Is flight data recorder erased after every flight?
How to create dashed lines/arrows in Illustrator
Are there any other methods to apply to solving simultaneous equations?
Typescript conditional return type based on string argument
The 2019 Stack Overflow Developer Survey Results Are InTypescript: declare return type to be dependent on argument value?How do I make the method return type generic?Passing arguments to C# generic new() of templated typeType definition in object literal in TypeScriptTypeScript Objects as Dictionary types as in C#Are strongly-typed functions as parameters possible in TypeScript?TypeScript Converting a String to a numberHow to convert string to enum in TypeScript?Call new Date with union type “number | string”Typescript: Interfaces vs TypesUsing string literals types in Typescript
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
When using union of string literals as input argument, what would it take to remove the casts and put the type into the function header:
const get = <T extends "barcode" | "mqtt">(s: T) =>
s === "barcode" ?
<T extends "barcode" ? scan: () => string : pan: () => string>scan: () => "we are scanning" :
<T extends "barcode" ? scan: () => string : pan: () => string>pan: () => "we are panning"
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
I ran into this trying to answer someone else's question: https://stackoverflow.com/a/55059318/2684980.
typescript generics
add a comment |
When using union of string literals as input argument, what would it take to remove the casts and put the type into the function header:
const get = <T extends "barcode" | "mqtt">(s: T) =>
s === "barcode" ?
<T extends "barcode" ? scan: () => string : pan: () => string>scan: () => "we are scanning" :
<T extends "barcode" ? scan: () => string : pan: () => string>pan: () => "we are panning"
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
I ran into this trying to answer someone else's question: https://stackoverflow.com/a/55059318/2684980.
typescript generics
add a comment |
When using union of string literals as input argument, what would it take to remove the casts and put the type into the function header:
const get = <T extends "barcode" | "mqtt">(s: T) =>
s === "barcode" ?
<T extends "barcode" ? scan: () => string : pan: () => string>scan: () => "we are scanning" :
<T extends "barcode" ? scan: () => string : pan: () => string>pan: () => "we are panning"
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
I ran into this trying to answer someone else's question: https://stackoverflow.com/a/55059318/2684980.
typescript generics
When using union of string literals as input argument, what would it take to remove the casts and put the type into the function header:
const get = <T extends "barcode" | "mqtt">(s: T) =>
s === "barcode" ?
<T extends "barcode" ? scan: () => string : pan: () => string>scan: () => "we are scanning" :
<T extends "barcode" ? scan: () => string : pan: () => string>pan: () => "we are panning"
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
I ran into this trying to answer someone else's question: https://stackoverflow.com/a/55059318/2684980.
typescript generics
typescript generics
asked Mar 8 at 8:36
Jørgen TvedtJørgen Tvedt
4501416
4501416
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
The cleanest solution is such cases (although not any more type safe than the type assertions) is to use overloads instead. You can use conditional types in the public signature, and a simple union in the implementation signature. You will need to switch to a function declaration as function expressions (arrow or regular) don't easily suport overloads:
function get<T extends "barcode" | "mqtt">(s: T): T extends "barcode" ? scan: () => string : pan: () => string
function get(s: "barcode" | "mqtt"): scan: () => string | pan: () => string
return s === "barcode" ?
scan: () => "we are scanning" :
pan: () => "we are panning"
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
This would be better, although not exactly what I was hoping for. Do you have to specify the return type in the implementation?
– Jørgen Tvedt
Mar 8 at 13:33
@JørgenTvedt I think you can get away with removing it from the implementation. You will get an error id the conditional branches are not in the returned union
– Titian Cernicova-Dragomir
Mar 8 at 14:38
Ok, but I still don't understand why my code does not work without the casts, that's why I hesitate to mark this as the answer.
– Jørgen Tvedt
Mar 9 at 16:37
1
@JørgenTvedt because Typescript does not reason about conditional types that contain unresolved type parameters. Except for very limited circumstances, it will just check for an exact type match.
– Titian Cernicova-Dragomir
Mar 9 at 17:25
1
@JørgenTvedt Typescript does not take flow analysis to this level. Flow analysis will impact just the types of the variables inside the guarded block. It will not help the compiler infer any conditional types.
– Titian Cernicova-Dragomir
Mar 10 at 11:04
|
show 1 more comment
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55059436%2ftypescript-conditional-return-type-based-on-string-argument%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The cleanest solution is such cases (although not any more type safe than the type assertions) is to use overloads instead. You can use conditional types in the public signature, and a simple union in the implementation signature. You will need to switch to a function declaration as function expressions (arrow or regular) don't easily suport overloads:
function get<T extends "barcode" | "mqtt">(s: T): T extends "barcode" ? scan: () => string : pan: () => string
function get(s: "barcode" | "mqtt"): scan: () => string | pan: () => string
return s === "barcode" ?
scan: () => "we are scanning" :
pan: () => "we are panning"
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
This would be better, although not exactly what I was hoping for. Do you have to specify the return type in the implementation?
– Jørgen Tvedt
Mar 8 at 13:33
@JørgenTvedt I think you can get away with removing it from the implementation. You will get an error id the conditional branches are not in the returned union
– Titian Cernicova-Dragomir
Mar 8 at 14:38
Ok, but I still don't understand why my code does not work without the casts, that's why I hesitate to mark this as the answer.
– Jørgen Tvedt
Mar 9 at 16:37
1
@JørgenTvedt because Typescript does not reason about conditional types that contain unresolved type parameters. Except for very limited circumstances, it will just check for an exact type match.
– Titian Cernicova-Dragomir
Mar 9 at 17:25
1
@JørgenTvedt Typescript does not take flow analysis to this level. Flow analysis will impact just the types of the variables inside the guarded block. It will not help the compiler infer any conditional types.
– Titian Cernicova-Dragomir
Mar 10 at 11:04
|
show 1 more comment
The cleanest solution is such cases (although not any more type safe than the type assertions) is to use overloads instead. You can use conditional types in the public signature, and a simple union in the implementation signature. You will need to switch to a function declaration as function expressions (arrow or regular) don't easily suport overloads:
function get<T extends "barcode" | "mqtt">(s: T): T extends "barcode" ? scan: () => string : pan: () => string
function get(s: "barcode" | "mqtt"): scan: () => string | pan: () => string
return s === "barcode" ?
scan: () => "we are scanning" :
pan: () => "we are panning"
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
This would be better, although not exactly what I was hoping for. Do you have to specify the return type in the implementation?
– Jørgen Tvedt
Mar 8 at 13:33
@JørgenTvedt I think you can get away with removing it from the implementation. You will get an error id the conditional branches are not in the returned union
– Titian Cernicova-Dragomir
Mar 8 at 14:38
Ok, but I still don't understand why my code does not work without the casts, that's why I hesitate to mark this as the answer.
– Jørgen Tvedt
Mar 9 at 16:37
1
@JørgenTvedt because Typescript does not reason about conditional types that contain unresolved type parameters. Except for very limited circumstances, it will just check for an exact type match.
– Titian Cernicova-Dragomir
Mar 9 at 17:25
1
@JørgenTvedt Typescript does not take flow analysis to this level. Flow analysis will impact just the types of the variables inside the guarded block. It will not help the compiler infer any conditional types.
– Titian Cernicova-Dragomir
Mar 10 at 11:04
|
show 1 more comment
The cleanest solution is such cases (although not any more type safe than the type assertions) is to use overloads instead. You can use conditional types in the public signature, and a simple union in the implementation signature. You will need to switch to a function declaration as function expressions (arrow or regular) don't easily suport overloads:
function get<T extends "barcode" | "mqtt">(s: T): T extends "barcode" ? scan: () => string : pan: () => string
function get(s: "barcode" | "mqtt"): scan: () => string | pan: () => string
return s === "barcode" ?
scan: () => "we are scanning" :
pan: () => "we are panning"
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
The cleanest solution is such cases (although not any more type safe than the type assertions) is to use overloads instead. You can use conditional types in the public signature, and a simple union in the implementation signature. You will need to switch to a function declaration as function expressions (arrow or regular) don't easily suport overloads:
function get<T extends "barcode" | "mqtt">(s: T): T extends "barcode" ? scan: () => string : pan: () => string
function get(s: "barcode" | "mqtt"): scan: () => string | pan: () => string
return s === "barcode" ?
scan: () => "we are scanning" :
pan: () => "we are panning"
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
answered Mar 8 at 9:09
Titian Cernicova-DragomirTitian Cernicova-Dragomir
73.3k35370
73.3k35370
This would be better, although not exactly what I was hoping for. Do you have to specify the return type in the implementation?
– Jørgen Tvedt
Mar 8 at 13:33
@JørgenTvedt I think you can get away with removing it from the implementation. You will get an error id the conditional branches are not in the returned union
– Titian Cernicova-Dragomir
Mar 8 at 14:38
Ok, but I still don't understand why my code does not work without the casts, that's why I hesitate to mark this as the answer.
– Jørgen Tvedt
Mar 9 at 16:37
1
@JørgenTvedt because Typescript does not reason about conditional types that contain unresolved type parameters. Except for very limited circumstances, it will just check for an exact type match.
– Titian Cernicova-Dragomir
Mar 9 at 17:25
1
@JørgenTvedt Typescript does not take flow analysis to this level. Flow analysis will impact just the types of the variables inside the guarded block. It will not help the compiler infer any conditional types.
– Titian Cernicova-Dragomir
Mar 10 at 11:04
|
show 1 more comment
This would be better, although not exactly what I was hoping for. Do you have to specify the return type in the implementation?
– Jørgen Tvedt
Mar 8 at 13:33
@JørgenTvedt I think you can get away with removing it from the implementation. You will get an error id the conditional branches are not in the returned union
– Titian Cernicova-Dragomir
Mar 8 at 14:38
Ok, but I still don't understand why my code does not work without the casts, that's why I hesitate to mark this as the answer.
– Jørgen Tvedt
Mar 9 at 16:37
1
@JørgenTvedt because Typescript does not reason about conditional types that contain unresolved type parameters. Except for very limited circumstances, it will just check for an exact type match.
– Titian Cernicova-Dragomir
Mar 9 at 17:25
1
@JørgenTvedt Typescript does not take flow analysis to this level. Flow analysis will impact just the types of the variables inside the guarded block. It will not help the compiler infer any conditional types.
– Titian Cernicova-Dragomir
Mar 10 at 11:04
This would be better, although not exactly what I was hoping for. Do you have to specify the return type in the implementation?
– Jørgen Tvedt
Mar 8 at 13:33
This would be better, although not exactly what I was hoping for. Do you have to specify the return type in the implementation?
– Jørgen Tvedt
Mar 8 at 13:33
@JørgenTvedt I think you can get away with removing it from the implementation. You will get an error id the conditional branches are not in the returned union
– Titian Cernicova-Dragomir
Mar 8 at 14:38
@JørgenTvedt I think you can get away with removing it from the implementation. You will get an error id the conditional branches are not in the returned union
– Titian Cernicova-Dragomir
Mar 8 at 14:38
Ok, but I still don't understand why my code does not work without the casts, that's why I hesitate to mark this as the answer.
– Jørgen Tvedt
Mar 9 at 16:37
Ok, but I still don't understand why my code does not work without the casts, that's why I hesitate to mark this as the answer.
– Jørgen Tvedt
Mar 9 at 16:37
1
1
@JørgenTvedt because Typescript does not reason about conditional types that contain unresolved type parameters. Except for very limited circumstances, it will just check for an exact type match.
– Titian Cernicova-Dragomir
Mar 9 at 17:25
@JørgenTvedt because Typescript does not reason about conditional types that contain unresolved type parameters. Except for very limited circumstances, it will just check for an exact type match.
– Titian Cernicova-Dragomir
Mar 9 at 17:25
1
1
@JørgenTvedt Typescript does not take flow analysis to this level. Flow analysis will impact just the types of the variables inside the guarded block. It will not help the compiler infer any conditional types.
– Titian Cernicova-Dragomir
Mar 10 at 11:04
@JørgenTvedt Typescript does not take flow analysis to this level. Flow analysis will impact just the types of the variables inside the guarded block. It will not help the compiler infer any conditional types.
– Titian Cernicova-Dragomir
Mar 10 at 11:04
|
show 1 more comment
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55059436%2ftypescript-conditional-return-type-based-on-string-argument%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown