Use of TypeScript Generics

Use of TypeScript Generics

Preface:

In JavaScript , encapsulating an API can have many uses because it is a weakly typed language, but the final result obtained just because of the weak typing is not what we want.

The emergence of TypeScript just solves this problem, but when considering the reuse of API, TypeScript does not seem to be so flexible. At this time, you can use the any type to solve the problem of inflexibility, but it returns to the problem in JavaScript, and the final result may not be what you expect.

To solve this problem, TypeScript introduced the concept of generics. When using generics, you don't need to specify the specific type in advance when defining functions, interfaces, or classes. Instead, you can specify the type when using it. The purpose of this is to reuse our code to a greater extent.

1. Easy to use

Now we need to define a join function, which mainly accepts two values ​​of the same type and returns the concatenated value of the two parameters. The sample code is as follows:

// The so-called generics, in a more popular way, are types that are generally referred to. // Define a join function that accepts two parameters of the same type and returns the concatenated value.
function join<T>(first: T, second: T) {
  return `${first}${second}`
}
// Here, T is specified as string typejoin<string>('第一', '第二') //第一第二// Here, through type inference, the compiler will automatically infer the type based on the passed parametersjoin(1, 2) // 12

Generics are defined using angle brackets <>. When we define the join function, we don't know what types can be accepted, but we can be sure that the two types must be the same. If we want to meet such a requirement, it is not so easy to solve it without generics.

When calling a function, there are two ways to use it. One is to directly specify the type as string type; the other is to use type inference. The editor will automatically help us determine the type based on the passed in parameters.

2. Using generics in functions

When defining a function, we can use multiple generics, and the return value type can also be specified through generics, as long as the quantity and usage methods correspond.

The sample code is as follows :

function identity<T, Y, P>(first: T, second: Y, third: P): Y {
  return second
}
//Specified type identity<boolean, string, number>(true, 'string', 123) // string // Type inference identity('string', 123, true) // true

3. Using Generics in Classes

We can use generics not only in functions but also in classes.

The sample code is as follows:

class DataManager<T> {
  // Define a class with a private array of type T constructor(private data: T[]) {}
  // Get the value in the array based on the index getItem(index: number): T {
    return this.data[index]
  }
}
const data = new DataManager(['一碗周'])
data.getItem(0) // A bowl of Zhou

Moreover, generics can also inherit from an interface. The sample code is as follows:

interface Item {
  name: string
}
class DataManager<T extends Item> {
  // Define a class with a private array of type T constructor(private data: T[]) {}
  // Get the value in the array based on the index getItem(index: number): string {
    return this.data[index].name
  }
}
const data = new DataManager([{ name: '一碗周' }])
data.getItem(0) // A bowl of Zhou

Use extends to achieve the effect of a generic constraint. For the code above, we must constrain the passed value to have a name attribute, otherwise an exception will be thrown.

4. Using type parameters in generic constraints

Suppose there is the following requirement: we define a class with a private object in it, which contains some properties; then we define a method to get the corresponding value through the key.

The implementation code is as follows:

// Define an interface interface Person {
  name: string
  age: number
  hobby: string
}
// Define a class class Me {
  constructor(private info: Person) {}
  getInfo(key: string) {
    return this.info[key]
  }
}
const me = new Me({
  name: 'A bowl of Zhou',
  age: 18,
  hobby: 'coding',
})
// Calling me.getInfo() may result in an undefined value. For example, me.getInfo('myName') // undefined

In the above code, if we call the getInfo() method in the instance object and pass in a non-existent property, we will get undefined. It is not the style in TypeScript to call a method that returns undefined .

This problem can be solved by the keyof operator, which can be used to obtain all keys of a certain type, and its return type is a union type.

The sample code is as follows:

type myPerson = keyof Person // 'name' | 'age' | 'hobby'

Now we can use this operator to solve the problem above.

The sample code is as follows:

class Me {
  constructor(private info: Person) {}
  // This is the same as getInfo<T extends keyof Person>(key: T): Person[T] {
    return this.info[key]
  }
  // getInfo<T extends 'name' | 'age' | 'hobby'>(key: T): Person[T] {
  // return this.info[key]
  // }
}
const me = new Me({
  name: 'A bowl of Zhou',
  age: 18,
  hobby: 'coding',
})
// Calling me.getInfo() will result in a compilation error if an unknown property is passed me.getInfo('myName') // error: Argument of type '"myName"' is not assignable to parameter of type 'keyof Person'.

Now if we access a property that does not exist in the object, the compilation will be abnormal.

This is the end of this article about the use of TypeScript generics. For more related TypeScript generics content, please search for previous articles on 123WORDPRESS.COM or continue to browse the related articles below. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • How to explain TypeScript generics in a simple way
  • TypeScript generic parameter default types and new strict compilation option
  • In-depth understanding of Typescript generic concepts in the front end
  • TypeScript generic usage and generic interface combination

<<:  The difference and choice between datetime and timestamp in MySQL

>>:  Summary of several commonly used CentOS7 images based on Docker

Recommend

Detailed tutorial on installing Docker on Windows

Since my local MySQL version is relatively low, I...

How to use react-color to implement the front-end color picker

background We can use react-color to implement th...

How to solve the problem of clicking tomcat9.exe crashing

A reader contacted me and asked why there were pr...

CocosCreator general framework design resource management

Table of contents Problems with resource manageme...

How to define data examples in Vue

Preface In the development process, defining vari...

Detailed introduction to logs in Linux system

Table of contents 1. Log related services 2. Comm...

JS removeAttribute() method to delete an attribute of an element

In JavaScript, use the removeAttribute() method o...

Detailed usage of js array forEach instance

1. forEach() is similar to map(). It also applies...

Implementation of Vue single file component

I recently read about vue. I found a single-file ...

VMware + Ubuntu18.04 Graphic Tutorial on Building Hadoop Cluster Environment

Table of contents Preface VMware clone virtual ma...

MySQL merge and split by specified characters example tutorial

Preface Merging or splitting by specified charact...

Example of how to embed H5 in WeChat applet webView

Preface WeChat Mini Programs provide new open cap...

In-depth analysis of Linux NFS mechanism through cases

Continuing from the previous article, we will cre...

How to change the database data storage directory in MySQL

Preface The default database file of the MySQL da...

How to configure Hexo and GitHub to bind a custom domain name under Windows 10

Hexo binds a custom domain name to GitHub under W...