Type guards are particular expression patterns involving the 'typeof' and 'instanceof' operators that cause the types of variables or parameters to be narrowed to more specific types. For example, in the code below, knowledge of the static type of 'x' in combination with a 'typeof' check makes it safe to narrow the type of 'x' to string in the first branch of the 'if' statement and number in the second branch of the 'if' statement.
function foo(x: number | string) { if (typeof x === "string") {
return x.length; // x has type string here
} else {
return x + 1; // x has type number here
} }
The type of a variable or parameter is narrowed in the following situations:
In the true branch statement of an 'if' statement, the type of a variable or parameter is narrowed
by any type guard in the 'if' condition when true, provided the true branch statement contains no assignments to the variable or parameter.
79
In the false branch statement of an 'if' statement, the type of a variable or parameter is narrowed
by any type guard in the 'if' condition when false, provided the false branch statement contains no assignments to the variable or parameter.
In the true expression of a conditional expression, the type of a variable or parameter is narrowed
by any type guard in the condition when true, provided the true expression contains no assignments to the variable or parameter.
In the false expression of a conditional expression, the type of a variable or parameter is narrowed
by any type guard in the condition when false, provided the false expression contains no assignments to the variable or parameter.
In the right operand of a && operation, the type of a variable or parameter is narrowed by any type guard in the left operand when true, provided the right operand contains no assignments to the variable or parameter.
In the right operand of a || operation, the type of a variable or parameter is narrowed by any type guard in the left operand when false, provided the right operand contains no assignments to the variable or parameter.
A type guard is simply an expression that follows a particular pattern. The process of narrowing the type of a variable x by a type guard when true or when false depends on the type guard as follows:
A type guard of the form x instanceof C, where C is of a subtype of the global type 'Function'
and C has a property named 'prototype'
o when true, narrows the type of x to the type of the 'prototype' property in C provided it is
a subtype of the type of x, or
o when false, has no effect on the type of x.
A type guard of the form typeof x === s, where s is a string literal with the value 'string',
'number', or 'boolean',
o when true, narrows the type of x to the given primitive type, or o when false, removes the primitive type from the type of x.
A type guard of the form typeof x === s, where s is a string literal with any value but 'string',
'number', or 'boolean',
o when true, removes the primitive types string, number, and boolean from the type of x, or o when false, has no effect on the type of x.
A type guard of the form typeof x !== s, where s is a string literal,
o when true, narrows the type of x by typeof x === swhen false, or
o when false, narrows the type of x by typeof x === swhen true.
A type guard of the form !expr
o when true, narrows the type of x by exprwhen false, or o when false, narrows the type of x by exprwhen true.
A type guard of the form expr1 && expr2
80
o when false, narrows the type of x to T1 | T2, where T1 is the type of x narrowed by expr1
when false, and T2 is the type of x narrowed by expr1when true and then by expr2when
false.
A type guard of the form expr1 || expr2
o when true, narrows the type of x to T1 | T2, where T1 is the type of x narrowed by expr1
when true, and T2 is the type of x narrowed by expr1when false and then by expr2when
true, or
o when false, narrows the type of x by expr1when false and then by expr2when false.
A type guard of any other form has no effect on the type of x. A primitive type P is removed from a type T as follows:
If T is a union type P | T1 | T2 | … | Tn, the result is the type T1 | T2 | … | Tn.
Otherwise, the result is T.
Note that type guards affect types of variables and parameters only and have no effect on members of objects such as properties. Also note that it is possible to defeat a type guard by calling a function that changes the type of the guarded variable.
In the example
function isLongString(obj: any) {
return typeof obj === "string" && obj.length > 100; }
the 'obj' parameter has type string in the right operand of the && operator. In the example
function f(x: string | number | boolean) {
if (typeof x === "string" || typeof x === "number") {
var y = x; // Type of y is string | number
} else {
var z = x; // Type of z is boolean
} }
the type of 'x' is string | number | boolean in left operand of the || operator, number | boolean in the right operand of the || operator, string | number in the first branch of the 'if' statement, and boolean in the second branch of the 'if' statement.
81
function processData(data: string | { (): string }) { var d = typeof data !== "string" ? data() : data;
// Process string in d
}
the inferred type of 'd' is string. In the example
class NamedItem {
name: string;
}
function getName(obj: any) {
return obj instanceof NamedItem ? obj.name : "unknown"; }
83
5
Statements
This chapter describes the static type checking TypeScript provides for JavaScript statements. TypeScript itself does not introduce any new statement constructs.