Hur kan jag kontrollera typen på en Array i Typescript?
Jag har en funktion med följande signatur
public async sequenceAnimations(animations: AnimationPlayer[] | AnimationTracker[]): Promise<any>
I själva funktionen vill jag förgrena baserat på om det är en AnimationPlayer-array eller en AnimationTracker-array, så jag försökte detta:
let mappedAnimations = animations;
if (animations instanceof Array<AnimationTracker>) {
mappedAnimations = animations.map(anim => anim.animationPlayer)
}
Som du kan se försöker jag tillåta att anroparen skickar antingen en AnimationPlayer-array eller en AnimationTracker-array som har en instans av animationPlayer. Men jag får ett fel när jag kontrollerar instanceof arrayen med en typ
Högersidan av ett 'instanceof'-uttryck måste vara av typen 'any' eller av en typ som kan tilldelas typen 'Function'.
Autokompletteringen registrerar inte heller typen av arrayen i if-blocket, så jag antar att jag inte kan kontrollera arraytypen på det här sättet.
Vad är det korrekta sättet att avgöra vilken typ av array som skickas?
Svar #1
Du kan inte använda instanceof med en generisk typ med typparametrar. Efter kompilation tas alla generiska typer bort, så animations instanceof Array<AnimationTracker> skulle bli animations instanceof Array vilket inte skulle göra det du förväntar dig.
Eftersom arrayer i Javascript inte är typade finns det inget inbyggt sätt att skilja mellan AnimationPlayer[] och AnimationTracker[] och om arrayerna är tomma är de vid körning verkligen oskiljbara. Du kan dock skapa ett eget typvakt som använder det första icke-nollvärdet i arrayen för att bestämma typen. För tomma arrayer skulle detta alltid returnera false, men det kan vara en okej lösning i de flesta fall:
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);
}
}
Svar #2
Kort svar: Du kan inte.
Huvudidén med TypeScript är att lägga till typer vid kompileringstid och generera vanlig JavaScript-kod efter kompileringen. JavaScript i sig har inget stöd för avancerad typkontroll och därför är ditt enda alternativ att göra duck-typing vid körning.
