5

I have a function with the following signature

public async sequenceAnimations(animations: AnimationPlayer[] | AnimationTracker[]): Promise<any>

In the function itself I want to branch based on if it is an AnimationPlayer array or an AnimationTracker array so I tried this:

let mappedAnimations = animations;
if (animations instanceof Array<AnimationTracker>) {
    mappedAnimations = animations.map(anim => anim.animationPlayer)
}

As you can see I am trying to allow the caller to pass either an AnimationPlayer array or an AnimationTracker array which has an instance of animationPlayer. But I get an error when checking instanceof the Array with a type

The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type.

Also the autocomplete isn't registering the type of the array in the if-block so I assume I can't check the array type like this.

What is the proper way to determine what the type of array being passed is?

1
  • Can you create a wrapper class AnimationPlayerList and AnimationTrackerList and test against these classes? Commented Feb 9, 2018 at 14:57

2 Answers 2

6

You can't use instanceof with a generic type with type parameters. After compilation all generics are erased so animations instanceof Array<AnimationTracker> would turn into animations instanceof Array which would not do what you expect it to do.

Since in Javscript arrays are not typed there is no build-in way of differentiate between AnimationPlayer[] and AnimationTracker[] and if the arrays are empty, at runtime they are really indistinguishable. You can however create a custom type guard that uses the first non-null item in the array to determine the type. For empty arrays this would always return false but it might be an ok solutions in most cases:

function isArrayOf<T>(array:any[], cls: new (...args: any[]) => T) : array is T[] {
    for(let item of array) {
        if(item != null) return  item instanceof cls;
    }
    return  false;
}
async function sequenceAnimations(animations: AnimationPlayer[] | AnimationTracker[]): Promise<any> {
    let mappedAnimations = animations;
    if (isArrayOf(animations, AnimationTracker)) {
        // animations is AnimationTracker[]
        mappedAnimations = animations.map(anim => anim.animationPlayer);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Short answer: You can't.

The main idea of TypeScript is to add types at compile time and emit plain JavaScript code after compilation. JavaScript itself has no support for advanced type checking and thus you're only option is to do duck-typing at runtime.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.