Type Protection
What's type protection
Before introducing type protection, let's look at an example, we want to call the printing method after creating the instance:
enum Type {
Strong,
Week
}
class Java {
helloJava() {
console.log('Hello Java');
}
}
class JavaScript {
helloJavaScript() {
console.log('Hello JavaScript');
}
}
function getLanguage(type: Type) {
let lang = type === Type.Strong ? new Java() : new JavaScript(); // let lang: Java | JavaScript
// Error: Property 'helloJava' does not exist on type 'Java | JavaScript'.
if (lang.helloJava) {
lang.helloJava(); // Error: Property 'helloJava' does not exist on type 'JavaScript'.
} else {
lang.helloJavaScript(); // Error: Property 'helloJavaScript' does not exist on type 'Java'.
}
return lang;
}
getLanguage(Type.Strong);
To resolve above issues, we can use type protection. TypeScript can guarantee that a variable belongs to a certain type in a specific block. You can safely use the properties or methods of this type in the block.
How to create type protection context
instanceof
function getLanguage(type: Type) {
let lang = type === Type.Strong ? new Java() : new JavaScript();
// OK
if (lang instanceof Java) {
lang.helloJava(); // OK, this is block one
} else {
lang.helloJavaScript(); // OK, this is block two
}
return lang;
}
TypeScript will create two different blocks automatically and lang
in each block has different methods accorrding to the type:
in
This keyword can determine whether the specified property is in the specified object or its prototype chain. See more in MDN: in operator
function getLanguage(type: Type) {
let lang = type === Type.Strong ? new Java() : new JavaScript();
// OK
if ('helloJava' in lang) {
lang.helloJava(); // OK
} else {
lang.helloJavaScript(); // OK
}
return lang;
}
typeof
For demonstration purposes, we can add second parameter x: string | number
in getLanguage()
:
function getLanguage(type: Type, x: string | number) {
let lang = type === Type.Strong ? new Java() : new JavaScript();
// OK
if (typeof x === 'string') {
x.length; // OK, this is block one
} else {
x.toFixed(); // OK, this is block two
}
return lang;
}
getLanguage(Type.Strong, '');
In the block one, the type of x
is string
so we can call the method under String
. In the block two, x
is number
, so it can have an access to toFixed()
.
Type protection function
We can also create a type protection function. The returned type of this function is a special type which is called a type predicate. When returning, we must judge whether the object has hellojava
method. Here we also need to use type assertions:
function isJava(lang: Java | JavaScript): lang is Java {
return (lang as Java).helloJava !== undefined;
}
Then we can use this function in getLanguage
:
// OK
if (isJava(lang)) {
lang.helloJava(); //OK
} else {
lang.helloJavaScript(); //OK
}