Given a function with a parameter of different types, how do I find out which type was passed to the function?
Example
interface SomeCustomInterface {
title: string
}
interface OtherCustomInterface {
subtitle: string
}
interface A {
value: string
}
interface B {
value: number
}
interface C {
value: SomeCustomInterface
}
interface D {
value: OtherCustomInterface
}
function doSomething(parameter: A | B | C | D): string {
switch(parameter.type) {
// I know the cases are not valid TS. What should I do instead?
case A:
return parameter.value
case B:
return parameter.value.toString()
case C:
return parameter.value.title
case D:
return parameter.value.subtitle
}
}
I know that there are type guards but I have concerns with those
They need to be able to uniquely identify each type. I see that some people add a property
kind
ortype
which allows them to identify a type in order to type guard it. This seems like a lot of overhead and boilerplate to me though.You need to write a custom function for each type like
type is A
ortype is B
which again would lead to massive overhead in my context.
What is the appropriate way to approach this in typescript?
Given a function with a parameter of different types, how do I find out which type was passed to the function?
Example
interface SomeCustomInterface {
title: string
}
interface OtherCustomInterface {
subtitle: string
}
interface A {
value: string
}
interface B {
value: number
}
interface C {
value: SomeCustomInterface
}
interface D {
value: OtherCustomInterface
}
function doSomething(parameter: A | B | C | D): string {
switch(parameter.type) {
// I know the cases are not valid TS. What should I do instead?
case A:
return parameter.value
case B:
return parameter.value.toString()
case C:
return parameter.value.title
case D:
return parameter.value.subtitle
}
}
I know that there are type guards but I have concerns with those
They need to be able to uniquely identify each type. I see that some people add a property
kind
ortype
which allows them to identify a type in order to type guard it. This seems like a lot of overhead and boilerplate to me though.You need to write a custom function for each type like
type is A
ortype is B
which again would lead to massive overhead in my context.
What is the appropriate way to approach this in typescript?
Share Improve this question edited Jul 9, 2020 at 11:44 matteok asked Jul 9, 2020 at 11:35 matteokmatteok 2,2093 gold badges32 silver badges58 bronze badges 6-
Would paring the type be enough? i.e.
parameter.value
being anumber
,string
orobject
. If so, you could always usetypeof
? – Dane Brouwer Commented Jul 9, 2020 at 11:41 - It might also be different types of objects. I updated my question – matteok Commented Jul 9, 2020 at 11:45
- Does this answer your question? How to check the object type on runtime in TypeScript? – Dane Brouwer Commented Jul 9, 2020 at 11:47
-
I looked into this possibility but saw that it would create a lot of overhead. All the properties are named
value
so even if I create the 4 extraisA
,isB
,isC
,isD
methods I would still need to inspect thevalue
forisSomeCustomType
andisOtherCustomType
and with this cascading requirement it would add too much overhead to support it in my project. – matteok Commented Jul 9, 2020 at 11:52 - Why don't you check the typeof the parameter? You don't really need to access it's members for this. – user3647971 Commented Jul 9, 2020 at 12:23
1 Answer
Reset to default 3Basically there are only 2 options as described in the accepted answer of this question.
What you can do is check that the shape of an object is what you expect, and TypeScript can assert the type at pile time using a user-defined type guard that returns true (annotated return type is a "type predicate" of the form arg is T) if the shape matches your expectation:
For class types you can use JavaScript's
instanceof
to determine the class an instance es from, and TypeScript will narrow the type in the type-checker automatically.
A side note from myself:
If you have the same propertyname you can potentially refactor your code using generics, like:
interface A {
value: string
}
interface B {
value: number
}
interface C {
value: SomeCustomInterface
}
interface D {
value: OtherCustomInterface
}
can be
interface GenericInterface<T>{
value: T
}