0

I have a situation where I need a function to accept a variety of different types. They will be separated by type guards within the function. So I am using a Union Type like this:

function(param: TypeA | TypeB): void {
    let callback: (param: TypeA | TypeB): void = () => {};

    if (isTypeA(param)) {
        callback = doSomethingWithTypeA;
    } else if (isTypeB(param)) {
        callback = doSomethingWithTypeB;
    }

    return callback(param);
}

Where the function doSomethingWithTypeA only accepts typeA and so on.

As you can see, always writing out (TypeA | TypeB) is very verbose, especially since it's more than two types in my actual code.

Is there some way to create an interface that is (TypeA | TypeB) ?
Or is there some other way to achieve this?

1
  • 5
    type TypeAorB = TypeA | TypeB ? Commented Apr 20, 2017 at 10:10

2 Answers 2

6

Use type aliases:

type YourType = TypeA | TypeB // | ... and so on
Sign up to request clarification or add additional context in comments.

Comments

-1

How about creating an interface:

interface MyType {
}

class TypeA implements MyType {
}

class TypeB implements MyType {
}

Then you can check it in the method:

function(param: MyType): void {
    let callback: (param: MyType): void = () => {};

    if (param instanceof TypeA) {
        callback = doSomethingWithTypeA;
    } else if (param instanceof TypeB) {
        callback = doSomethingWithTypeB;
    }

    return callback(param);
}

5 Comments

How come? The bad idea is having a function do more than 1 thing but that is in the question... curious what else you see as bad in the above?
No, that is not why. This is not a union type. It is two classes (which incidentally implies a major interface change) and it does not support exhaustive checking. The type cases due not subtract from one another and the classes are not related except for being structurally equivalent (since both are empty). Creating empty classes and interfaces is bad because TypeScript has structural typing, not nominal typing. Your answer looks like case object in Scala, that won't work in TypeScript. Also, implements is 100% irrelevant.
The empty classes are just indicative, they would obvioulsy have properties / methods specific to the implementation. This is not an answer in completeness, but in general I find using an interface a better approach, as there will likely be behaviour in TypeA and TypeB you can abstract to the interface and save the case checking. But I come from a C# background and still getting to grips with the Typescript way of doing things, so i take your points.
Right, the C# background will lead you astray if you try to use at a as a basis for intuition. Interfaces serve a different role in typescript. A better approach here would be two interfaces, A and B, with no common heritage and a union type created as type U = A | B
When people start to learn this language, they tend to conflate types and classes. Consider that in TypeScript a instanceof A is an operation on two values, A is not a type in that expression.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.