Nov 26, 2018

Using Typescript Type Guard to Narrow Down Type

Typescript is aware of usage of the Javascript instanceof and typeof operators, and will narrow down the type accordingly when you use those operators in conditional block.

ts
function doSomething(x: number | string) {
if (typeof x === 'string') {
// Within the block TypeScript knows that `x` must be a string
console.log(x.substr(1));
}
x.substr(1);
Property 'substr' does not exist on type 'string | number'. Property 'substr' does not exist on type 'number'.2339Property 'substr' does not exist on type 'string | number'. Property 'substr' does not exist on type 'number'.
}
ts
function doSomething(x: number | string) {
if (typeof x === 'string') {
// Within the block TypeScript knows that `x` must be a string
console.log(x.substr(1));
}
x.substr(1);
Property 'substr' does not exist on type 'string | number'. Property 'substr' does not exist on type 'number'.2339Property 'substr' does not exist on type 'string | number'. Property 'substr' does not exist on type 'number'.
}

(Example stolen from Typescript Deep Dive)

Usually, those typechecking are used frequently, and you may want to create some utility function to abstract it away. However, with those abstraction, you lose the narrowing down of typescript.

ts
function isString(value: any) {
return typeof value === 'string';
}
 
function doSomething(x: number | string) {
if (isString(x)) {
// Typescript doesn't know that x must be a string
console.log(x.substr(1)); // Error
Property 'substr' does not exist on type 'string | number'. Property 'substr' does not exist on type 'number'.2339Property 'substr' does not exist on type 'string | number'. Property 'substr' does not exist on type 'number'.
}
}
ts
function isString(value: any) {
return typeof value === 'string';
}
 
function doSomething(x: number | string) {
if (isString(x)) {
// Typescript doesn't know that x must be a string
console.log(x.substr(1)); // Error
Property 'substr' does not exist on type 'string | number'. Property 'substr' does not exist on type 'number'.2339Property 'substr' does not exist on type 'string | number'. Property 'substr' does not exist on type 'number'.
}
}

Solution: Custom Type Guard

Typescript introduces the concept of custom type guard, which allows you to create utility function that assert the type of the parameters.

ts
function isString(value: any): value is string {
return typeof value === 'string';
}
 
function doSomething(x: number | string) {
if (isString(x)) {
console.log(x.substr(1)); // OK
}
}
ts
function isString(value: any): value is string {
return typeof value === 'string';
}
 
function doSomething(x: number | string) {
if (isString(x)) {
console.log(x.substr(1)); // OK
}
}

Side Note: npm package for common type checking

I’ve published a npm package, typesafe-is that consists of common type-checking with typeguard, as those are required in almost are javascript applications.

Thanks for reading!

Love what you're reading? Sign up for my newsletter and stay up-to-date with my latest contents and projects.

    I won't send you spam or use it for other purposes.

    Unsubscribe at any time.