Захисники типу дозволяють звузити тип об’єкта в межах умовного блоку.
typeof
TypeScript знає про використання операторів instanceof і typeof JavaScript. Якщо ви використовуєте їх в умовному блоці, TypeScript зрозуміє, що тип змінної буде іншим у цьому умовному блоці. Ось короткий приклад, коли TypeScript розуміє, що певна функція не існує в string, і вказує на те, що, ймовірно, було помилкою користувача:
functiondoSomething(x:number|string) {if (typeof x ==='string') { // Within the block TypeScript knows that `x` must be a stringconsole.log(x.subtr(1)); // Error, 'subtr' does not exist on `string`console.log(x.substr(1)); // OK }x.substr(1); // Error: There is no guarantee that `x` is a `string`}
instanceof
Ось приклад із класом і instanceof:
classFoo { foo =123; common ='123';}classBar { bar =123; common ='123';}functiondoStuff(arg:Foo|Bar) {if (arg instanceofFoo) {console.log(arg.foo); // OKconsole.log(arg.bar); // Error! }if (arg instanceofBar) {console.log(arg.foo); // Error!console.log(arg.bar); // OK }console.log(arg.common); // OKconsole.log(arg.foo); // Error!console.log(arg.bar); // Error!}doStuff(newFoo());doStuff(newBar());
TypeScript навіть розуміє else, тому, коли if звужує один тип, він знає, що всередині else it's definitely not that type. Ось приклад:
classFoo { foo =123;}classBar { bar =123;}functiondoStuff(arg:Foo|Bar) {if (arg instanceofFoo) {console.log(arg.foo); // OKconsole.log(arg.bar); // Error! }else { // MUST BE Bar!console.log(arg.foo); // Error!console.log(arg.bar); // OK }}doStuff(newFoo());doStuff(newBar());
in
Оператор in виконує безпечну перевірку наявності властивості об'єкта та може використовуватися як захист типу. наприклад
interfaceA { x:number;}interfaceB { y:string;}functiondoStuff(q:A|B) {if ('x'in q) {// q: A }else {// q: B }}
Literal Type Guard
Ви можете використовувати === / == / !== / !=, щоб розрізняти літеральні значення
typeTriState='yes'|'no'|'unknown';functionlogOutState(state:TriState) {if (state =='yes') {console.log('User selected yes'); } elseif (state =='no') {console.log('User selected no'); } else {console.log('User has not made a selection yet'); }}
Це навіть працює, коли у вас є буквальні типи в об’єднанні. Ви можете перевірити значення назви спільної властивості, щоб розрізнити об’єднання, наприклад.
typeFoo= { kind:'foo',// Literal type foo:number}typeBar= { kind:'bar',// Literal type bar:number}functiondoStuff(arg:Foo|Bar) {if (arg.kind ==='foo') {console.log(arg.foo); // OKconsole.log(arg.bar); // Error! }else { // MUST BE Bar!console.log(arg.foo); // Error!console.log(arg.bar); // OK }}
null and undefined with strictNullChecks
TypeScript достатньо розумний, щоб виключити як null, так і undefined за допомогою перевірки == null / != null. Наприклад:
functionfoo(a?:number|null) {if (a ==null) return;// a is number now.}
User Defined Type Guards
У JavaScript не надто багато вбудованої підтримки інтроспекції під час виконання. Коли ви використовуєте звичайні об’єкти JavaScript (використовуючи структурну типізацію для вашої переваги), ви навіть не маєте доступу до instanceof або typeof. Для цих випадків ви можете створити User Defined Type Guard functions. Це лише функції, які повертають someArgumentName is SomeType. Ось приклад:
/** * Just some interfaces */interfaceFoo { foo:number; common:string;}interfaceBar { bar:number; common:string;}/** * User Defined Type Guard! */functionisFoo(arg:any): arg isFoo {returnarg.foo !==undefined;}/** * Sample usage of the User Defined Type Guard */functiondoStuff(arg:Foo|Bar) {if (isFoo(arg)) {console.log(arg.foo); // OKconsole.log(arg.bar); // Error! }else {console.log(arg.foo); // Error!console.log(arg.bar); // OK }}doStuff({ foo:123, common:'123' });doStuff({ bar:123, common:'123' });
Type Guards and callbacks
TypeScript не передбачає, що guards залишаються активними у зворотних викликах, оскільки робити це припущення небезпечно.
// Example Setupdeclarevar foo:{bar?: {baz:string}};functionimmediate(callback: ()=>void) {callback();}// Type Guardif (foo.bar) {console.log(foo.bar.baz); // OkayfunctionDoingSomeStuff(() => {console.log(foo.bar.baz); // TS error: Object is possibly 'undefined'" });}
Виправити це так само просто, як зберегти виведене безпечне значення в локальній змінній, автоматично гарантуючи, що воно не буде змінено ззовні, і TypeScript може легко зрозуміти, що: