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