“This is the fifth day of my participation in the November Gwen Challenge. See details of the event: The Last Gwen Challenge 2021”.

The role of generics

What generics do:

  • useThe genericTo create reusable components that can support multiple types of data.
  • No multiple function overloading, lengthy joint type declaration, enhance code readability.
  • Flexible control of constraints between types.

For example, requiring that the type of the return value of a method be the same as the type of the parameter passed in can be defined using generics.

Example:

function print1<T> (params:T) :T {
    return params;
}
print1<string> ('name');
Copy the code

In the example above, we define a generic print1 that captures the string passed in by the user using the type variable T. The type variable T used in the generic print1 can be regarded as a string. You can keep input parameters and return values of the same type without having to define a type beforehand.

2. Generic functions

In the example above, we define a generic function that calls a method that, in addition to passing in the type argument string above, has another way of saying that no type argument is passed directly, and the compiler automatically determines the type (type inference).

print1('name');
Copy the code

Generic function types

Generics can define function types as well as functions.

type Print = <T>(value:T) = > T;
let myPrint: Print = print1; 
Copy the code

The above example uses the type keyword to define the function type Print, and defines the myPrint function as Print.

Generic interfaces

Generics can also define interfaces:

interface Log<T> {
    (value: T):T
}
let myLog:Log<string> = print1;
myLog('aaa')
Copy the code

In the example above, we define the generic interface Log of the function type, specify the type parameter as T, and set the received parameter and return value of the interface Log as T.

You can set the default value for the type parameter T:

interface Log<T=string> {
    (value: T):T
}
Copy the code

When there is a default value, we can use generics without passing in the type:

let myLog:Log = print1;
myLog('aaa')
Copy the code

5. Generic classes

Generic classes are similar to generic interfaces. The class name is followed by the parameter type.

class Log<T> {
    run(value:T):T {
        returnvalue; }}Copy the code

In the example above, we create a generic class Log that defines the run method with parameters and return values of type T.

The type can be set when the class is used, or the type can not be set. If the type is not set, the value can be arbitrarily passed:

let log1 = new Log<number> (); log1.run(1);

let log2 = new Log();
log2.run('sss');
Copy the code

6. Generic constraints

A generic constraint is both a type constraint on the type variable T.

Here’s an example:

function getLength<T> (arg: T) {
    console.log(arg.length);/ / an error
    return arg
}

getLength<string> ('22')
Copy the code

In the example above, we want to print the length attribute of the parameter, but the parameter does not necessarily have the length attribute. In this case, we need to constrain the connection of the passed parameter, otherwise an error will be reported.

So how do you constrain the parameters?

The type variable T can inherit an interface for generic constraints, as follows:

interface Length {
    length:number;
}

function getLength<T extends Length> (arg: T) {
    console.log(arg.length)
    return arg
}

getLength<string> ('22')
getLength('33')
Copy the code

In the example above, the type variable T inherits the Length interface for the generic constraint, so the parameter passed must have the Length attribute to avoid an error.