TypeScript tutorial: Lesson 22 – Generics


Simple example about Generics

function simpleArrayNumber(...args:number[]):number[]{
    return [...args]
}

function simpleArrayString(...args:string[]):string[]{
    return [...args]
}

Instead, we need a way of capturing the type of the argument in such a way that we can also use it to denote what is being returned. Here, we will use a type variable, a special kind of variable that works on types rather than values.

function simpleArray<T>(...args:T[]):T[]{
    return [...args]
}

Use generic function:

let myArrayNumber = simpleArray<number>(0,1,2,3)
let myArrayString = simpleArray<string>("a","b")

console.log(myArrayNumber) //[ 0, 1, 2, 3 ]
console.log(myArrayString) //[ 'a', 'b' ]

Generic with Array

function myArray<T>(arg: Array<T>): Array<T> {
    console.log(arg.length)
    return arg
}

let myArray1 = myArray<string>(["hello","world"])

console.log(myArray1) //[ 'hello', 'world' ]

Generic Types , Generic Interface

Method 1: we can define a type:

type myType = <T>(arg: Array<T>) => Array<T>
let myFunc:myType = myArray
let myArray2 = myFunc<string>(["hello","world"])
console.log(myArray2) //[ 'hello', 'world' ]

Method 2: use interface

interface myGeneric{
    <T>(arg: Array<T>): Array<T>
}
let MyFunc:myGeneric = myArray
let myArray3 = MyFunc<string>(["hello","world"])
console.log(myArray3) //[ 'hello', 'world' ]

Method 3: generic interface

interface myGenericFn<T>{
    (arg: Array<T>): Array<T>
}
let MyFunc2:myGenericFn<string> = myArray
let myArray4 = MyFunc2(["hello","world"])
console.log(myArray4) //[ 'hello', 'world' ]

When we use myGenericFn, we now will also need to specify the corresponding type argument (here: string), effectively locking in what the underlying call signature will use.

Generic Classes

class myClass<T> {
    value: T    
    run:(a:T,b:T)=>T
}

var myVar = new myClass<string>()
myVar.value = "hello"
myVar.run = function(a,b){
    return a+b
}
console.log(myVar.run("hello"," world"))

Note: Static members cannot reference class type parameters.

 
    class Base<T> {
      static prop: T; //error TS2302: Static members cannot reference class type parameters.
    }

Generic Constraints

Use the extends keyword to denote the constraint:

interface hasLength {
    length: number
}
  
function func1<T extends hasLength>(arg: T): T { //type T must has length property
    console.log(arg.length)
    return arg
}

Using Type Parameters in Generic Constraints

You can declare a type parameter that is constrained by another type parameter. For example, here we’d like to get a property from an object given its name. We’d like to ensure that we’re not accidentally grabbing a property that does not exist on the obj, so we’ll place a constraint between the two types:

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

let x = { a: 1, b: 2, c: 3, d: 4 }

getProperty(x, "a")

Using Class Types in Generics

//Method 1
function createInstance<T>(c: { new (): T }): T {
    return new c();
}
//Method 2
function createInstance2<T>(c: new ()=> T): T {
    return new c();
}
console.log(createInstance(myClass)) //myClass {}
console.log(createInstance2(myClass)) //myClass {}

Leave a Reply