The use of generics in TypeScript

Generic

For generics in TypeScript, you can understand it as a parameterized type , and encapsulate the type of each parameter into the form of a parameter, and this encapsulation method is generic.

1. Function generics

If we want to write a function that receives two parameters, both of these parameters may be of string type or both of number type, and finally do the splicing operation.
For this function, in fact, it can be realized through the above joint type and type protection, but let's analyze the conditions of this function, "These two parameters may be string type or both number type" , think about it, we can Can't you directly tell the parameter type passed in this function when you call it? The answer is yes, generics can achieve this function.

function f<T>(one: T, two: T) {
    return `${one}${two}`
}
f<string>("ok", "fine")

One more mention here. Because TypeScript has type inference capabilities, we don't even need to write generic parameters when calling functions, such as this:

f("ok", "fine")

Of course, we can also define multiple generics.

function f<T, P>(one: T, two: P) {
    return `${one}${two}`
}
f<string, number>("ok", 2)

2. Generic type

Initialize the generic type of the class

Create a class, and write the constructor by the way, with two parameters:

class Student {
    constructor(private name: string, private age: number) { }
}

Parameterize the type of the parameter, realize the generic initialization of the class, and then realize a simple call.

class Student<T, P> {
    constructor(private name: T, private age: P) { }
}
const stu = new Student<string, number>("小白", 21)

Generic inheritance

Following the Student example above, there is now a data structure like this: each Student comes from a Person interface, which has a NAME attribute (string type), and now we need to take out the NAME in a Student object.
First, let's improve the interface and getter functions:

interface Person {
    NAME: string
}
class Student<T> {
    constructor(private name: T) { }
    get getName() {
        return this.name
    }
}

The current interface Person and Student classes are still not related. Next, we use generic inheritance to pass the name in Person to the name in Student. When you understand this, pay attention to the case of the two names, lowercase Is defined in the class, the uppercase is the interface passed to the class .

interface Person {
    NAME: string
}
class Student<T extends Person> {
    constructor(private name: T) { }
    get getName() {
        return this.name.NAME
    }
}

Finally call it.

const stu = new Student({ NAME: "小白" })

If you observe carefully, we will find that when we passed the constructor, we passed an object directly , with braces. The reason is actually very simple. We can think of Person as a description of the object to be passed in. This description is passed to the name attribute in Student through the extends statement. Finally, when we initialize the object, what we seem to initialize is An object, but what we initialize is the name in the constructor.
At first I saw this place for a long time, but finally I wrote an example based on someone else's code, and after reading it several times, I found that I could understand it.

Guess you like

Origin blog.csdn.net/qq_43592084/article/details/109542526