likes
comments
collection
share

TS-函数ThisType使用场景

作者站长头像
站长
· 阅读数 11

JS中的this指向

在JS代码中,对于this我们只需要关注它的指向,确保返回的是一个正确的值。this的指向由下面这几点决定:

  1. 对象调用某函数,其中的this就指向该对象
  2. 通过apply、bind、call来显示指定函数的this
  3. new一个函数,函数中的this指向返回的实例化对象
  4. 箭头函数的this指向父级作用域的this

TS中的this指向和this类型

但是在TS代码中,我们要使用this,还需要确认this的类型

下面我们看一个代码

const option = {
    x: 1,
    y: 2,
    methods: {
        getOption: function ():number[] {
            return [this.x, this.y];
        },
    },
};

你知道getOption中的this指向谁吗?答案应该是不知道,因为非箭头函数的this指向,只在调用时才能确定,静态编译期是确定不了的。

而在TS中,不仅要关心this的指向,还要关心this的类型。如果在编辑器中写上面的代码,编译器会报类型警告:

TS-函数ThisType使用场景

图中所示,TS将this推断为含有getOption属性的对象,这不是我们想要的

我们想要的是,this代表option对象,通过this可以访问x、y。这里我们需要显示地定义this的类型。

应该怎么做呢

用interface定义this的类型

可以在形参的位置定义this的类型

interface I_Option {
    x: number;
    y: number;
    getOption: () => [number, number];
}

const option = {
    x: 1,
    y: 2,
    methods: {
        getOption: function (this: I_Option) {
                return [this.x, this.y];
        },
    },
};

这里先定义了一个接口I_Option,其中的结构和option相同。之后,在getOption的形参中,对this的类型做了定义。现在不会报类型警告了

当然, 这个只是类型的推断,this的真正指向还要看代码运行阶段。

上面是解决this类型注释的一个方法。还有一种方法,我们可以用TS内置函数ThisType<Type>来实现

用ThisType实现对this类型的定义

定义一个通用的对象类型

const obj = {
      data: {},
      methods:{}
}

对象中的属性,无非就两种:数据,方法。所以上面的结构中,把数据全部放在了data里面,把方法全部放在了methods里面。

定义这样一个通用类型的对象,无非就是之后的接口类型定义能够方便一点

定义通用对象的接口类型

interface I_configObject<D,M>{
	data: D;
	methods: M
}

接口接收两个泛型,第一个泛型作为data的类型,第二个泛型作为methods的类型

定义一个创建对象的函数

function createObj<D, M>(configObj: I_configObject<D, M>) {
    return {
        ...configObj.data,
        methods: ...configObj.methods,
    };
}

解释:

  1. 函数接收具有通用结构的configObj
  2. createObj也接受两个泛型,这两个泛型与data和methods的类型一致
  3. 你知道return中,为啥要这么做吗

使用createObj函数,看看效果

const option2 = createObj({
    data: {
            x: 1,
            y: 2,
    },
    methods: {
        getOption: function ():number[] {
                    return [this.x, this.y];
        },
    },
});

然后我们将符合通用类型的结构放进createObj函数中,就可以得到我们想要的option啦


作者:额,心细的你是不是发现了什么?

读者:对,没有用ThisType啊,这连影子都没有见到。

作者:哦哦哦,对不起,立马加上


如果你在编辑器中敲了上面的代码,发现还是会在this的地方报类型警告

interface I_configObject<D,M>{
    data: D;
      // 表示methods中的this是D & M类型的,
      // 所以在methods中,可以访问D中的属性(x,y)
    methods: M & ThisType<D & M>
}

现在可以了,不会报类型警告了

下图中,可以看到TS推断出的this类型:

TS-函数ThisType使用场景

这正是我们想要的

其次,也可以放在 createObj的形参中

//表示configObj中的this指向是D & M类型的
function createObj<D, M>(configObj: I_configObject<D, M> & ThisType<D & M>) {
    return {
        ...configObj.data,
        methods: configObj.methods,
    };
}

效果是一样的

ThisType仅支持在对象字面量的上下文中使用,在其他地方使用作用等同于空接口

总结:

  1. JS中的this指向
  2. TS中,不仅关心this指向,还要关注this的类型
  3. 使用interface中,在形参中对this进行类型注释
  4. 使用ThisType对this进行类型注释
  5. 用ThisType做类型注释真是磨人