ThisType的作用和运用

1,529 阅读1分钟

ThisType是ts中内置了一种类型,查看源码发现只能知道它的作用,定义方法中啥都没有

/**
 * Marker for contextual 'this' type
 */
interface ThisType<T> { }

下面说明一下它怎么用,啥时候用

ThisType

ThisTypethis参数都是指定函数的运行时this指向的类型,它们的使用不同

  • this参数是作为函数的参数定义的,它可以定义在任何函数上
  • ThisType定义一个对象中的所有函数的this指向类型,它只能在对象的类型声明时使用

initEnvPropertiesB调用了自己的initABC方法给自己添加了三个符合Env规范的属性

abstract class Env {
    a!: number;
    b!: string;
    c!: boolean;
}

interface InitEnvPropertiesB {
    e: string;
    initABC: () => void;
}

const initEnvPropertiesB: InitEnvPropertiesB & ThisType<Env> = {
    e: "e",
    initABC() {
        this.a = 2;
        this.b = "B";
        this.c = false;
        // this.e = "E"; // error this中没有e属性
    },
};

initEnvPropertiesB.initABC();
console.log(initEnvPropertiesB); // 有abce四个属性

实际使用

这个类型在高级函数的封装中非常有用,如下是对Pinia的模仿,它通过使用ThisType提供了非常友好的代码提示,这也是typeChallenges中的一题,←详细题目见左边链接,推荐先思考下题目再来看下面的答案


type GetterFunc = Record<string, () => any>;

type ReturnTypes<T extends GetterFunc> = {
    [K in keyof T]: ReturnType<T[K]>;
};

declare function defineStore<State, Getters extends GetterFunc, Actions>(store: {
    id: string;
    state: () => State;
    getters?: Getters & ThisType<Readonly<State> & ReturnTypes<Getters>>;
    actions?: Actions & ThisType<State & Actions>;
}): State & Readonly<ReturnTypes<Getters> & Actions>;

const store = defineStore({
    id: "",
    state: () => ({
        num: 0,
        str: "",
    }),
    getters: {
        stringifiedNum() {
            // @ts-expect-error
            this.num += 1;

            return this.num.toString();
        },
        parsedNum() {
            return parseInt(this.stringifiedNum);
        },
    },
    actions: {
        init() {
            this.reset();
            this.increment();
        },
        increment(step = 1) {
            this.num += step;
        },
        reset() {
            this.num = 0;

            // @ts-expect-error
            this.parsedNum = 0;

            return true;
        },
        setNum(value: number) {
            this.num = value;
        },
    },
});