This is the 24th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

// The basic definition of generics
// in this case T is the type variable, and this type variable is usually called generic
// The generic is usually a capital letter, not necessarily T, T is just the parameter name
// In function definitions, generics are usually written after the name and before the argument list
const getArr = <T>(item: T, length: number) = > {
  return new Array(length).fill(item)
}

// After the function name, prefix the parentheses with <> to write the actual generic value to be used
// The argument value of the type variable
console.log(getArr<number> (3.3)) // => [3, 3, 3]

// Type inconsistent error
// console.log(getArr<number>('3', 3)) // error

// If no specific generic value is specified
// Then TS will automatically infer the specific value of the generic based on the parameters passed in
console.log(getArr(3.3)) // => [3, 3, 3]
Copy the code
// Multiple generics can be used within a function
// For this function, you need to manually specify the return value type of the function, because TS cannot accurately infer the return value type of the function
function getTupleArr<T.K> (param1: T, param2: K, length: number) :Array"[T.K] >{
  return new Array(length).fill([param1, param2])
}

// both T and K are strings
console.log(getTupleArr('key'.'value'.5))
Copy the code

The use of generics in different types

Define a function

// Define the function interface
let sumFun: 
      
       (param1: T, param2: V) => number // The param1 and param2 parameters are of a specific type sumFun = (param1: any, param2: any) => param1 + param2 console.log(sumFun(10, 20))
      ,>Copy the code

Type the alias

// Define the type alias
type sumType = 
      
       (param1: T, param2: V) => number const sumFun: sumType = (param1: any, param2: any) => param1 + param2 console.log(sumFun(10, 20))
      ,>Copy the code

Defines the interface

// Define the type alias
// If there is only a function definition in an interface, it is recommended to use a type alias to define the data type of that function
interface Isum {
  <T, V>(param1: T, param2: V): number
}

const sumFun: Isum = (param1: any, param2: any) = > param1 + param2

console.log(sumFun(10.20))
Copy the code
// Generics can also be defined on function interfaces
// All data in the interface can use the corresponding generic variable
interface ISum<T, V> {
  (param1: T, param2: V): number
  arr: Array<[T, V]>
}
Copy the code

Generic constraint

Although we can use generics to define type variables, we find that there are no constraints on the types passed to generic variables. We can use generic constraints if we need to restrict the types of values that can be assigned to generic variables

// The generic variable T extends from the interface {length: number}
// Indicates that the data type that can be assigned to the generic variable T must be an object of the function length property
function getLength<T extends { length: number }>(param: T) {
  console.log(param.length)
}

getLength('abc') / / = > 3
// getLength(3) // error
Copy the code
// keyof O --> the union type of all keys of O
function getProperty<O.K extends keyof O> (obj: O, key: K) {
  return obj[key]
}

const obj = {
  name: 'Klaus'.age: 24
}

console.log(getProperty(obj, 'name'))
Copy the code

Defining class types

In TS, instances created by a class are of that type

Even the data is a type

// foo: new(username: string) => T
// foo is a class whose constructor needs to pass a variable of type string
The return value of the getInstance method is an instance object of the class foo
function getInstance<T> (foo: new(username: string) => T, username: string) {
  return new foo(username)
}

class Foo {
  constructor(public name: string) {
    this.name = name
  }
}

// The instance created is of type Foo
console.log(getInstance(Foo, 'Klaus'))
Copy the code