TypeScript знает об использовании JavaScript-операторов instanceof и typeof. Если вы используете их в блоке условия, TypeScript поймет, что тип переменной будет отличаться в этом блоке условия. Вот небольшой пример, где TypeScript понимает, что конкретной функции не существует в string, и указывает, что это, вероятно, было опечаткой пользователя:
12345678
functiondoSomething(x:number|string){if(typeofx==='string'){// Внутри блока TypeScript знает, что `x` должно быть строкойconsole.log(x.subtr(1));// Ошибка, 'subtr' не существует для `string`console.log(x.substr(1));// OK}x.substr(1);// Ошибка: Нет гарантии, что `x` является `строкой`}
TypeScript даже понимает else, поэтому, когда if уточняет один тип, он знает, что внутри else это определенно уже другой тип. Вот пример:
1 2 3 4 5 6 7 8 9101112131415161718192021
classFoo{foo=123;}classBar{bar=123;}functiondoStuff(arg:Foo|Bar){if(arginstanceofFoo){console.log(arg.foo);// OKconsole.log(arg.bar);// Ошибка!}else{// ДОЛЖЕН БЫТЬ Bar!console.log(arg.foo);// Ошибка!console.log(arg.bar);// OK}}doStuff(newFoo());doStuff(newBar());
JavaScript не имеет встроенной поддержки интроспекции. Когда вы используете простые объекты JavaScript (используя структурную типизацию себе на пользу), у вас даже нет доступа к instanceof или typeof. Для этих случаев вы можете создавать функции для защиты типа, определяемой пользователем. Это просто функции, которые возвращают какойТоПараметрФункции - КакогоТоТипа. Вот пример:
/** * Просто несколько интерфейсов */interfaceFoo{foo:number;common:string;}interfaceBar{bar:number;common:string;}/** * Определяемая пользователем защита типа! */functionisFoo(arg:any):argisFoo{returnarg.foo!==undefined;}/** * Простой пример использования защиты типа, определяемой пользователем */functiondoStuff(arg:Foo|Bar){if(isFoo(arg)){console.log(arg.foo);// OKconsole.log(arg.bar);// Ошибка!}else{console.log(arg.foo);// Ошибка!console.log(arg.bar);// OK}}doStuff({foo:123,common:'123'});doStuff({bar:123,common:'123'});
TypeScript не предполагает, что защиты типов остаются активными в колбэках, поскольку делать такое предположение опасно. Например
1 2 3 4 5 6 7 8 910111213
// Примерdeclarevarfoo:{bar?:{baz:string}};functionimmediate(callback:()=>void){callback();}// Защита типаif(foo.bar){console.log(foo.bar.baz);// OkayfunctionDoingSomeStuff(()=>{console.log(foo.bar.baz);// TS ошибка: Возможно объект 'undefined'});}
Для исправления просто достаточно сохранить значение в локальной переменной, автоматически гарантируя, что оно не будет изменено извне, и TypeScript легко сможет это понять:
12345678
// Защита типаif(foo.bar){console.log(foo.bar.baz);// Okayconstbar=foo.bar;functionDoingSomeStuff(()=>{console.log(bar.baz);// Okay});}