Reputation: 1025
I'm trying to figure out how to use typeguards on promises based on parameters.
function request({ logic }: { logic: boolean }) {
return new Promise((resolve, reject) => {
if (l)
resolve("something");
resolve(1);
});
}
request({ logic: true }).then(a => {
a.length
})
In this example, I'd like to make sure that the typeof 'a' == 'string'. I tried writing some typeguards in request
but their results get lost. I don't know if this is just a limitation of typescript or I just need to do some smart type casting or what.
This is a toy example of what I am actually trying to do, which is to make an async call whose result varies slightly based on some parameters. And I am loath to make another function just to cover an altered return type
Upvotes: 2
Views: 758
Reputation: 29906
Typescript function overloading to the rescue:
function request(logic: true): Promise<string>;
function request(logic: false): Promise<number>;
function request(logic: boolean) {
return new Promise((resolve, reject) => {
if (logic)
resolve("something");
resolve(1);
});
}
request(true).then(a => {
console.log(a.length); //<-- knows that a is a string
});
request(false).then(a => {
console.log(a.length); //<-- error: prop 'length' does not exist on number
});
Typeguards are meant to be used in if
statements.
EDIT
You would be surprised! Typescript supports overloading distinction based on fields too! Check the following code:
function request(opts: { logic: true }): Promise<string>;
function request(opts: { logic: false }): Promise<number>;
function request(opts: { logic: boolean }) {
return new Promise((resolve, reject) => {
if (opts.logic)
resolve("something");
resolve(1);
});
}
request({ logic: true }).then(a => {
console.log(a.length); //<-- knows that a is a string
});
request({ logic: false }).then(a => {
console.log(a.length); //<-- error: prop length cannot be found on type number
});
EDIT
With a little generic magic you can achieve the desired behavior. This way only the logic
field matters from the caller's point of view. Downside is that you loose typecheck even for opts.logic
inside the request
functions implementation.
function request<T extends { logic: true }>(opts: T): Promise<string>;
function request<T extends { logic: false }>(opts: T): Promise<number>;
function request(opts: any) {
return new Promise((resolve, reject) => {
if (opts.logic)
resolve("something");
resolve(1);
console.log(opts.anything);
});
}
request({ logic: true, foo: 'bar' }).then(a => {
console.log(a.length); //<-- knows that a is a string
});
request({ logic: false, foo: 'baz' }).then(a => {
console.log(a.length); //<-- error: prop length cannot be found on type number
});
Upvotes: 3
Reputation: 154
Correct overloading is the next (should add type):
function request(logic: boolean): Promise<string>;
function request(logic: boolean): Promise<number>;
function request(logic: boolean): Promise<any>;
function request(logic: boolean) {
return new Promise((resolve, reject) => {
if (logic)
resolve("something");
resolve(1);
});
}
request(true).then((a) => {
console.log(a.length); //<-- knows that a is a string
});
request(false).then((a) => {
console.log(a.length); //<-- error: prop 'length' does not exist on number
});
Upvotes: -1