In software engineering, we not only need to create well-defined apis, but we also need to think about reuse, and generics give us that flexibility but elegance
Generic Hello World
Start by defining a function that returns any value passed to it.
function getValue(a: number) :number {
return a;
}
Copy the code
The function argument we defined above is of a numeric type, and the return value is of a numeric type.
If we need to pass a string argument and return it, we must define another function
function getValue(a: number) :number {
return a;
}
function getValue1(a: string) :string {
return a;
}
Copy the code
However, both functions have the same function, except that the types of arguments are different.
And if you want to extend other data types, do you have to write them again?
Alternatively, we use any to define functions:
function getValue(a: any) :any {
return a;
}
Copy the code
But using any loses some information: the value passed in must be of the same type as the value returned. Because any doesn’t show this relationship.
But ** generics ** can define a consistent interface, with code reuse in mind
Here we use a type variable, which is a special type of variable that represents only the type, not the value
Just keep the same letters, usually T for Type.
function getValue<T> (a: T) :T {
return a;
}
getValue<number>(3);
getValue<string>("qzy");
Copy the code
We call this version of the function generic because it can be applied to multiple types
Once we have defined a generic function, we can use it in two ways.
The first is to pass in all the arguments, including the type arguments:
getValue<string>("abc");
Copy the code
The second method is more common. Makes use of type corollaries — that is, the compiler automatically helps us determine the type of T based on the arguments passed in:
getValue(1);
Copy the code
Use generic variables
When creating a function using generics, you must use the type correctly inside the function body
function getValue<T> (a: T) :T {
console.log(a.length);
return a;
}
Copy the code
In the example above, we want to access the length attribute of the passed parameter.
But T might be a number type, and number types don’t have length attributes. So the compiler gives an error.
function getValue<T> (a: T) :T {
// Attribute "length" does not exist on type "T"
console.log(a.length);
return a;
}
Copy the code
To do this, we define an interface to describe conditions.
interface LengthProps {
length: number;
}
function getValue<T extends LengthProps> (a: T) :T {
console.log(a.length);
return a;
}
getValue([1.2]);
getValue(1); // Parameters of type "number" cannot be assigned to parameters of type "LengthProps"
Copy the code
A generic interface
Generic interfaces come in two ways
The first:
interface config {
<T>(val: T): T;
}
// fn: config
// function must follow the interface definition
let fn: config = function <T> (val: T) :T {
return val;
};
fn(5);
Copy the code
The second:
interface config<T> {
(val: T): T;
}
function configFn<T> (val: T) :T {
return val;
}
// config<string>
// = configFn
let fn: config<string> = configFn;
fn("qzy");
Copy the code
Generic constraints – Type parameters
You can declare one type parameter and it is bound by another type parameter.
For example, now we want to get the property from the object using the property name, and we want to make sure that the property exists on object obj, so we need to use constraints between the two types.
function getProperty<T.K> (obj: T, key: K) {
// Type "K" cannot be used for index type "T"
return obj[key];
}
let x = { a: 1.b: 2.c: 3.d: 4 };
getProperty(x,'e');
Copy the code
The intent of our code is to find the key property under obj by passing in a generic object, or some other variable, and then passing in another generic variable.
If we pass in a generic key variable, it’s not necessarily an attribute that exists in the generic obj.
To solve this problem, we can use keyof
function getProperty<T.K extends keyof T> (obj: T, key: K) {
// Type "K" cannot be used for index type "T"
return obj[key];
}
let x = { a: 1.b: 2.c: 3.d: 4 };
getProperty(x, "b");
getProperty(x,'e'); / / type "" e" "cannot be assigned to the parameter type" b "" |" a "| |" c "" d" "parameter
Copy the code
K extends Keyof T relates two variables of type