1. What are generics

Generics, as the name suggests, can be applied to multiple types, and using type variables such as T helps us catch incoming types, which we can then continue to use.

The following defines an identity generic function, adding the type variable T, which helps capture the type of the variable value we pass in, and then uses T again as the return value type, thus constraining the parameter type and return value type to be the same.

function identity <T>(value: T) : T {
  return value;
}
Copy the code

Generic types and generic interfaces

const myIdentity: <T>(arg: T) => T = identity;
Copy the code

There is no difference between generic types and non-generic types, except that type parameters are passed in.

We can also declare function types using object literals:

const myIdentity: { <T>(arg: T): T } = identity;
Copy the code

This introduces the generic interface:

interface GenericIdentityFn {
    <T>(arg: T): T;
}

const myIdentity: GenericIdentityFn = identity;
Copy the code

Lock the type used in the function by passing in the type parameter T as an interface parameter:

interface GenericIdentityFn<T> {
    (arg: T): T;
}

const myIdentity: GenericIdentityFn<number> = identity;
Copy the code

3. A generic class

You can use these generic types in your classes by following the class name with the type variable.

class GenericPerson<T, U> {  
  name: T;
  getAge: (age: U) => U;
}
let person = new GenericPerson<string, number>();
person.name = 'Jane';
person.getAge = function (x) { return x; };
person.getAge(2);
Copy the code

When to use generics

When an interface, function, or class handles multiple data types and uses that type in more than one place.

5. Generic constraints

Constraints are usually described using interfaces and implemented using extends.

Interface Lengthwise {length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; }Copy the code
Function getProperty<T, K extends Keyof T>(obj: T, key: K): T[K] { return obj[key]; }Copy the code

6. Generic conditional types

A condition type uses a condition expression for type relationship detection to choose between two types:

T extends U ? X : Y
Copy the code

Usually used with the infer keyword:

type ParamType<T> = T extends (... args: infer P) => any ? P : T;Copy the code

This allows type extraction if T can be assigned to (… Args: infer P) => any, then return parameter P, otherwise return the type of T itself.