Close

TypeScript - Generic Constraints

[Last Updated: Dec 23, 2018]

In TypeScript we can apply constraints on Generic type parameters (e.g. T) by using keyword extends (e.g. T extends Serializable).

Examples

generic-constraints-example.ts

interface Shape {
    draw();
}

//applying constraint on Type Parameter S to be of only Shape type
function drawShapes<S extends Shape>(shapes: S[]): void{
     shapes.forEach(shape => shape.draw());
}

class Circle implements Shape{
    draw() {
        console.log(`drawing Circle`)
    }
}

class Rectangle implements Shape{
    draw() {
        console.log(`drawing Rectangle`)
    }
}

let circle = new Circle();
let rectangle = new Rectangle();
drawShapes([circle, rectangle]);

Output

drawing Circle
drawing Rectangle

Passing anything other than Shape type to drawShape() function will cause compile time error:

generic-constraints-example2.ts

interface Shape {
    draw();
}

//applying constraint on Type Parameter S to be of only Shape type
function drawShapes<S extends Shape>(shapes: S[]): void{
     shapes.forEach(shape => shape.draw());
}

drawShapes(["my shape"]);

Output

generic-constraints-example2.ts(10,13): error TS2322: Type 'string' is not assignable to type 'Shape'.

Using other Type Parameters in Generic Constraints

We can declare a type parameter that is constrained by another type parameter.

Following example applies the constraint on K to be keyof of type T:

generic-constraint-type-param.ts

function getProp<T, K extends keyof T>(key: K, obj: T): any {
    return obj[key];
}

let obj = {a: 2, b: 3, c: 4};
let prop = getProp('c', obj);
console.log(prop);

Output

4

Generic constraint on constructor function

A constructor can be used as a function parameter via function type syntax (i.e. new() => MyObj). This might be useful for creating factory functions involving generic:

generics-in-factories.ts

function createInstance<T>(t: new () => T): T {
    return new t();
}

class Test {
    x: number = 4;
}

let test: Test = createInstance(Test);
console.log(test);

Output

Test { x: 4 }

A constructor with parameters:

generics-in-factories2.ts

function createInstance2<T>(t: new(...constructorArgs:any[]) => T, ...args: any[]): T {
    return new t(args);
}

class Test2 {
   private x: number;

	constructor(x: number) {
		this.x = x;
	}

}

let test2: Test2 = createInstance2(Test2, 5);
console.log(test2);

Output

Test2 { x: [ 5 ] }

In above examples we used generics to specify return type T only. We can use generics for the constructor type as well:

generics-in-factories3.ts

function createInstance3<R, T extends { new(...constructorArgs: any[]): R }>(constructor: T, ...args: any[]): R {
	return new constructor(args);
}

class Test3 {
	private x: number;

	constructor(x: number) {
		this.x = x;
	}

}

let test3: Test3 = createInstance3(Test3, 6);
console.log(test3);

Output

Test3 { x: [ 6 ] }

Example Project

Dependencies and Technologies Used:

  • TypeScript 3.1.1
Generic Constraints Examples Select All Download
  • typescript-generic-constraints
    • generic-constraint-type-param.ts

    See Also