Reputation: 6844
Let's say I have a function with the following signature.
function doSomething(bool = false): number | string {
if (bool) {
return '1';
} else {
return 1;
}
}
const value = doSomething();
const valueTwo = doSomething(true);
My issue is that the type
of the value
variable is number | string
in both cases. How can I tell typescript to return the correct type based on the if block without doing something like that:
const value = doSomething() as number;
const valueTwo = doSomething(true) as string;
Upvotes: 0
Views: 100
Reputation: 249536
You can have multiple signatures for a function, and if the return type is dependent on primitive values you can use literal types to discriminate. In your case you could write:
// Public sigantures
function doSomething(bool?: false): number // With false constant
function doSomething(bool: true): string // With true constant or missing
function doSomething(bool?: boolean): number | string // With unknown bool value
// Implementation siganture
function doSomething(bool: boolean = false): number | string {
if (bool) {
return '1';
} else {
return 1;
}
}
var s = doSomething(true) // s is string
var n2 = doSomething() // n2 is number
var n3 = doSomething(false) // n3 is number
declare var b: boolean;
var ns4 = doSomething(b) // ns4 is string | number because it can't be determined at compile time
Upvotes: 3
Reputation: 39615
TypeScript is a statically typed langauge - at compile time it understands the type definitions you have in your code and can help find errors by checking that you're not getting types crossed.
When you mark a method as having the return number | string
, you're giving the compiler information: you know the method will return one of these two possible types. The compiler doesn't have the ability to look at the method in detail to understand the conditions under which your code will return a particular type. This is why we have to tell the compiler all the possible return types in our method signatures; it can't figure it out for itself.
If you want the compiler to know the types, you can give it more information using overload signatures which discriminate a return type based on some constant values:
function doSomething(bool: false): number
function doSomething(bool?: true): string
function doSomething(bool?: boolean): number | string
The compiler can now resolve the return type based on the value of the boolean, but it will only do so if the value is a constant: one which is known at compile-time.
This means that these statements have a known single return type:
var str = doSomething(true);
var bool = doSomething(false);
But this invocation does not:
declare var input: boolean;
var strOrBool = doSomething(input)
Upvotes: 1
Reputation: 45745
Not a direct answer, but:
If you're referring to when you manually pass in a literal, that would likely be a bad design; you're trying to have the function do too much. In this case, just break it into two function with different return types. Both can even rely on a third function that encapsulates the common behavior between the two. To answer the question though, in this case, I don't know of any way to do that. That's a complicated inference to have the compiler make.
If you want it to be able to figure out the type for any arbitrary data passed in, that would be impossible. If you give it user-supplied data at run-time, it's impossible for it to be able to infer the type at compile-time. You're asking it to make decisions based on information that it doesn't have.
Upvotes: 0