TypeScript Initial Knowledge-Generics

Keywords: Javascript TypeScript Attribute

Generics refer to a feature that defines functions, interfaces, or classes without specifying specific types in advance, and then specifies types when used.
Generics are used to create reusable components that support multiple types of data.

Simple use

Defining functions using any type is similar to generics, but not really generics:

// Input variables of any type, but also return values of any type, inconsistent between the type of input and the type of return
// Even if a number variable is passed in, it is still possible to return a string value
function identity(arg: any): any {
    return arg;
}

When an incoming type is consistent with the returned type, a type variable, which is a special variable, can be used to represent the type rather than the value:

function identity<T>(arg: T): T {
    return arg;
}

// Explicit incoming type parameters, specifying generic T as string, are generally used in correct type inference
console.log(identity<string>('myString'));
// It is more common to use type inference of TypeScript without passing in types.
console.log(identity('myString'));

This is the generic type in TypeScript, which uses T to represent a certain type, so that the incoming type is consistent with the returned type.

Multiple Type Parameters

When defining generics, you can specify multiple type parameters:

function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}

// ['seven', 7]
swap([7, 'seven']);

Generic constraints

When using a generic variable inside a function, because you don't know what type the variable is, TypeScript is not allowed to manipulate its properties or methods at will:

function loggingIdentity<T>(arg: T): T {
    // There is no attribute length on type T
    console.log(arg.length);
    return arg;
}

However, a constraint can be imposed on generic variables so that TypeScript can more accurately infer the type of generic variables and provide some operational methods:

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    // T inherits the Lengthwise interface to access the length attribute
    console.log(arg.length);
    return arg;
}

Multiple types of parameters can also be constrained by each other:

// T inherits U, T is the superset of U, so there will be no sub-end where T does not exist in U.
function copyFields<T extends U, U>(target: T, source: U): T {
    for (let id in source) {
        target[id] = (<T>source)[id];
    }
    return target;
}

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

copyFields(x, { b: 10, d: 20 });

generic interface

Interfaces can define the shape a function needs to conform to, or they can use interfaces with generics to define the shape of a function:

interface CreateArrayFunc {
    <T>(length: number, value: T): Array<T>;
    // The generic parameter is considered as a parameter of the whole interface: (length: number, value: T): Array < T >;
}

let createArray: CreateArrayFunc;
createArray = function<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
};

createArray(3, 'x'); // ['x', 'x', 'x']

generic class

Similar to generic interfaces, generics can also be used in class type definitions:

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) {
    return x + y;
};

Generics specify default types

After TypeScript 2.3, you can specify default types for generic type parameters. When the actual type of the type parameter is not specified or the actual type cannot be inferred, TypeScript uses the default type as the type of the incoming parameter:

// The default parameter type for generics is string
function createArray<T = string>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

Posted by dsdintn on Wed, 04 Sep 2019 21:10:39 -0700