3

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

  1. They need to be able to uniquely identify each type. I see that some people add a property kind or type 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.

  2. You need to write a custom function for each type like type is A or type is B which again would lead to massive overhead in my context.

What is the appropriate way to approach this in typescript?

matteok
  • 2,189
  • 3
  • 30
  • 54
  • Would comparing the type be enough? i.e. `parameter.value` being a `number`, `string` or `object`. If so, you could always use `typeof`? – Dane Brouwer Jul 09 '20 at 11:41
  • It might also be different types of objects. I updated my question – matteok Jul 09 '20 at 11:45
  • Does this answer your question? [How to check the object type on runtime in TypeScript?](https://stackoverflow.com/questions/44078205/how-to-check-the-object-type-on-runtime-in-typescript) – Dane Brouwer Jul 09 '20 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 extra `isA`, `isB`, `isC`, `isD` methods I would still need to inspect the `value` for `isSomeCustomType` and `isOtherCustomType` and with this cascading requirement it would add too much overhead to support it in my project. – matteok Jul 09 '20 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 Jul 09 '20 at 12:23
  • Nevermind. I suppose this [question](https://stackoverflow.com/questions/36332665/how-to-use-instanceof-in-a-switch-statement) answers yours to some extent. – user3647971 Jul 09 '20 at 12:35

1 Answers1

3

Basically 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 compile 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 comes 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
}
  • Using classes feels superior to me. They come with typechecks out of the box that don't rely on the shape and as far as I understand they are just plain JS objects at runtime. – matteok Jul 12 '20 at 11:16