Front end programmers may not know generics very well. They may know generics if they know Java, a strongly typed language. They can use generics to write dynamically reusable TS code. In TS, generics are generally used for classes, interfaces and functions.
Today, let's learn how to use generics in TypeScript and the scenarios where generics are usually used.
1. Quickly understand generics
Many front ends familiar with JS development may not understand what generics are. Let's understand generics through the simplest example.
The two functions are the same, but the input and return types are different. If you do not use generics in TS, you need to define two functions, but their types are different.
// Number type function fun(args: number): number { return args; } // String type function fun(args: string): string { return args; }
Of course, you can use any type
function fun(args: any): any { return args; }
But using any is actually avoiding type checking. Just like using JS, why use TS.
Let's use generics to implement it
2. Use generics
To create a generic Type, you need to use the Type parameter, which is generally defined with T or < T > to represent the data Type of a class, interface or function.
Let's rewrite the above function with generics
function fun<T>(args:T):T { return args; }
Using generic functions is also simple
let result = fun<string>("Hello World");
Or so
let result2 = fun<number>(200);
We can run the code and verify it. We can go to the official playground
Address: https://www.typescriptlang.org/play
The above is the simplest use of generics in TS, which is often used.
Let's take a look at the slightly more complex usage of generics
3. Multiple types of generics
Above, we use T to represent a type. If a function has many parameters, we can use different letters to represent the type. Like the following
function fun<T, U, V>(args1:T, args2: U, args3: V): V { return args3; }
The above function receives args1, args2 and args3, and returns args3. These parameters are not type qualified because T, U, V are used as generic types for function parameters.
Next, call this function
let result3 = fun<string, number, boolean>('Xiaoshuai', 23, false);
Then we run one to try
The function returns the third parameter, so it is false
Generics can be used not only for functions, but also for classes and interfaces. Let's continue
4. Create generic class
Similar to functions, the generic type of a class also uses the type parameters in < >, and then uses the < T > type to define methods and properties in the whole class.
Let's create a custom array class and define an arr array attribute. The type of the array is a generic type
class customArray<T> { private arr: T[] = []; }
Create a method to get the array
getItems (): T[] { return this.arr; }
Then create an addItem method to push elements into the array
addItem(item: T) { this.arr.push(item); }
The type of arr array is T [], so our array can be of any type, such as number, string, Boolean, etc.
Next, add a removeItem method to delete the specified elements of the array
removeItem(item: T) { let index = this.arr.indexOf(item); if(index > -1) { this.arr.splice(index, 1); } }
Now that the properties and methods of the class are almost written, let's test the results
let numObj = new customArray<number>(); numObj.addItem(10); let strObj = new customArray<string>(); strObj.addItem('Xiaoshuai'); console.log(numObj); console.log(strObj); console.log(numObj.getItems()); console.log(strObj.getItems());
We created a numObj object of numeric type and a strObj object of string type
Let's take a look at some binding rules on generics
5. Generic constraints
Above, we learned how to use generics as types for functions and classes, but using generics also has some disadvantages, such as the following example
function getLength<T>(args: T) : number { return args.length; }
In the above function, if the parameter passed in has the length attribute, it will work normally. If not, an error will be reported
We can see that the error is that generic T does not have a length attribute. What should we do
We can use a general constraint to create an interface named funcArgs and define the length attribute
interface funcArgs { length: number; }
Now let's revise it
function getLength<T extends funcArgs>(args:T) : number { return args.length; }
Now let's run
As you can see, TS will throw an exception when using a type without length parameter.
If the parameter has the length attribute, there will be no error messages.
summary
Today, we learned how to use generics in TypeScript, including applying generics to functions, classes, interfaces, etc.
If this article is helpful, wechat searches [Xiaoshuai's Programming Notes] for a little knowledge every day