Why generics?
Many times in typescript, the exact type of an annotation is not determined, such as the parameter type of a function.
function getVal(obj, k) {
return obj[k];
}
Copy the code
The above function, we want to achieve is to obtain an object corresponds to the specified k value, then the actual use, obj type is uncertain, the scope of natural k is uncertain, it need to be sure, when we in the specific call at this time the needs of this definition process uncertain type can be addressed by generics.
Generics – used in functions
function getVal<T> (obj: T, k: keyof T) {
return obj[k];
}
Copy the code
By generics, we define variables (parameters) for mutable (indeterminate) types, <> similar to ()
Generics – used in classes
Example: Mock components
abstract class Component<T1.T2> {
props: T1;
state: T2;
constructor(props: T1) {
this.props = props;
}
abstract render(): string;
}
interface IMyComponentProps {
val: number;
}
interface IMyComponentState {
x: number;
}
class MyComponent extends Component<IMyComponentProps.IMyComponentState> {
constructor(props: IMyComponentProps) {
super(props);
this.state = {
x: 1}}render() {
this.props.val;
this.state.x;
return '<myComponent />'; }}let myComponent = new MyComponent({ val: 1 });
myComponent.render();
Copy the code
Generics – used in interfaces
We can also use generics in our interfaces. The backend provides interfaces to return some data. The following interfaces are defined according to the returned data format:
interface IResponseData {
code: number; message? :string;
data: any;
}
Copy the code
Based on the interface, we encapsulate the corresponding methods
function getData(url: string) {
return fetch(url).then(res= > {
return res.json();
}).then((data: IResponseData) = > {
return data;
});
}
Copy the code
However, we will find that the specific format of the data item of the interface is uncertain, and different interfaces will return different data. When we want to return the specific data format according to the specific interface requested, it is more troublesome, because getData does not know what the specific interface you call is. What would the corresponding data look like.
At this point we can use generics for IResponseData
// IResponseData<T>
interface IResponseData<T> {
code: number; message? :string;
data: T;
}
// getData<U>
function getData<U> (url: string) {
return fetch(url).then(res= > {
return res.json();
}).then((data: IResponseData<U>) = > { // IResponseData
return data;
});
}
Copy the code
Define different data interfaces, including two interfaces: user/article
// User interface
interface IResponseUserData {
id: number;
username: string;
email: string;
}
// Article interface
interface IResponseArticleData {
id: number;
title: string;
author: IResponseUserData;
}
Copy the code
Calling specific code
(async function () {
let user = await getData<IResponseUserData>('./user');
if (user.code === 1) {
console.log(user.message);
} else {
console.log(user.data.username);
}
let articles = await getData<IResponseArticleData>('./artical');
if (articles.code === 1) {
console.log(articles.message);
} else {
console.log(articles.data.id);
console.log(articles.data.author.username); }});Copy the code