typescript的this所指问题

Atarsei
  • 8

按照mongoose官网的virtual例子如下:

personSchema.virtual('fullName').get(function () {
  return this.name.first + ' ' + this.name.last;
})

在ts会被报错为:
“this”隐式具有类型“any”,因为它没有类型批注。ts(2683):“this”的外部值被此容器隐藏

找了一圈在 stackoverflow 上找到了答案

personSchema.virtual("username").get(function(this: { firstName: string, lastName: string}) {
  return this.firstName + " " + this.lastName ;
}) ;

但是为什么会这样呢?

回复
阅读 851
2 个回答
✓ 已被采纳
首先声明,我对 mongoose 不熟,回答是基于 TypeScript 语法知识来进行的

抄下用例代码

personSchema.virtual('fullName').get(function () {
  return this.name.first + ' ' + this.name.last;
})

分析理解为:.get(fn) 通过注释函数的方式扩展功能,这个函数中可以使用 this 来访问目标对象(不过我不知道这个目标对象是什么),这个目标对象包含一个 name 属性,而且 name 是包括 firstlast 属性的对象,所以这个 this 可以用一个类型来表示:

interface SomeObject  {
    name: {
        first: string,
        last: string;
    }
}

现在,通过 get 注入的函数是一个独立的函数,而不是定义在某个类或者对象上的“方法”函数,所以它本身不携带 this 类型。因此,在函数中使用 this,就会被 TypeScript 推导为 any 类型(不过我认为推导为 unknown 更合理)。

就 JavaScript 来说,一个函数确实可以在使用时绑定到某个对象上,因此其内部可以使用 this。这种情况下,假设开发者已经明确了 this 的类型。只不过开发者明确,TSC 并不知道,所以需要告诉 TSC this 的类型 —— 只需要在函数的第一个参数位置声明一个特殊参数 this 的类型就好(这个参数不对应实参传入),然后这个函数可以声明为

function(this: SomeObject) {
    return `${this.name.first} ${this.name.last}`;
}

合起来就是

interface SomeObject  {
    name: {
        first: string,
        last: string;
    }
}

personSchema.virtual('fullName').get(function (this: SomeObject) {
  return this.name.first + ' ' + this.name.last;
}

到于 StackOverflow 上拿到的答案,是在认定 this 类型是如下定义的(使用时没预先定义,直接使用的匿名类型):

interface Blabla {
    firstName: string;
    lastName: string;
}

注意,这和原本出现问题的代码中 this 的类型是完全不一致的,所以到底 this 类型该如何定义,要根据实际情况来决定。


在我的 TypeScript 课程「]TypeScript从入门到实践 【2021 版】」的第五章第 5 节,1 分 28 秒开始就在讲「this 参数」:

image.png

找了一圈在 stackoverflow 上找到了答案

UserSchema.virtual("username").get(function(this: { firstName: string, lastName: string}) {
  return this.firstName + " " + this.lastName ;
}) ;

但是为什么会这样呢?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏