In the following code, I'm defining a Function union type GetThing
which I'm then using for the getThing
function.
However when I check the type of either name
or thing
, they're both any. I would expect name
to be string
and thing
to be Thing1 | Thing2
Thing1 | Thing2
Additionally I would expect the return type of the getThing
function to depend on the type of the thing
argument, which should be inferred by that switch
, but we're not even getting that far.
interface Thing1 {
type: "thing1";
}
interface Thing2 {
type: "thing2";
}
type GetThing1 = (name: string, thing: Thing1) => string;
type GetThing2 = (name: string, thing: Thing2) => boolean;
type GetThing = GetThing1 | GetThing2;
const getThing: GetThing = (name, thing) => {
switch (thing.type) {
case "thing1": {
return "thingy";
}
case "thing2": {
return true;
}
}
}
Is this a bug in Typescript, is this just too many layers of inference deep for Typescript to handle, or is there something I'm missing?
This is currently a limitation of Typescript.
(For your initial question, they're both any
because it can't identify that function as being of type GetThing1 or GetThing2. But, you'd still have an issue even if you defined them manually to be (name: string, thing: Thing1 | Thing2)
).
I simplified your code a little, to:
type Foo = (v: number) => string;
type Bar = (v: string) => boolean;
type FooBar = Foo | Bar;
const fooBar: FooBar = (v: number | string) => {
switch (typeof v) {
case "number": {
return "thingy";
}
case "string": {
return true;
}
}
}
console.log(fooBar('Bob'));
Which may be a little clearer.
Your snippet doesn't type the inputs to getThing, but they're implied to be:
(name: string, thing: Thing1|Thing2)
So (using the above example for simplicity), FooBar
is defined to be either a Foo
, or a Bar
. That is, either a (number)=>string
, or a (string)=>bool
.
From Typescript's pedantic point of view, (number|string) => string | bool
(number|string) => string | bool
is just not the same as either of those - it doesn't care that you've written it correctly and the types would work out.
I believe the core issue in this feature-request is the same, with a couple work-arounds given further down . It's apparently not a trivial thing for Typescript to handle, conceptually.
I'd recommend one of the following:
type Foo = (v: number) => string;
type Bar = (v: string) => boolean;
type FooBar = Foo | Bar;
let foo: Foo = (v: number) => {
return "heyo";
}
let bar: Bar = (v: string) => {
return true;
}
type FooBarDiscriminator = (v: number | string) => string | boolean;
const fooBar1: FooBarDiscriminator = (v: number | string) => {
switch (typeof v) {
case "number": {
return foo(v);
}
case "string": {
return bar(v);
}
}
}
function fooBar2(v: number | string) {
switch (typeof v) {
case "number": {
return foo(v);
}
case "string": {
return bar(v);
}
}
}
console.log(fooBar1(0));
console.log(fooBar1('Bob'));
console.log(fooBar2(0));
console.log(fooBar2('Bob'));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.