某些API希望接收必须与this
进行交互的函数,因此箭头函数无法在其中工作,例如一个knex子查询。
是否可以向Typescript暗示期望具有未绑定this
的函数?
答案 0 :(得分:2)
长话短说:不幸的是,没有很多额外的手动输入类方法的方法,就无法执行此操作。
TypeScript具有this
parameters,其中函数的调用签名具有名为this
的初始函数参数,该参数指定对调用函数时所需的this
上下文类型的约束。 this
参数是“ fake”,因为在调用函数时实际上并没有将其作为第一个参数传递。例如:
function sayMyName(this: { name: string }) {
console.log("Hi, my name is " + this.name + ".");
}
sayMyName()
函数不带任何参数,但是只有绑定到类型为{name: string}
的对象时才能调用它。这会在编译时捕获以下错误:
try {
sayMyName(); // error, won't work unless bound
} catch (e) {
console.log(e); // TypeError: this is undefined
}
并允许这样的事情:
sayMyName.bind({ name: "Harry Potter" })(); // okay
// Hi, my name is Harry Potter.
const hermione = {
name: "Hermione Granger",
speak: sayMyName
}
hermione.speak(); // okay
// Hi, my name is Hermione Granger.
因此,解决此问题的显而易见的尝试是让您传入的函数指定其this
上下文应为void
,如下所示:
function callbackCaller(cb: (this: void) => void): void {
cb(); // okay
}
这确实可以通过箭头/未绑定函数以及sayMyName
来表现您想要的方式:
const arrow = () => console.log("I am an arrow function");
callbackCaller(arrow); // okay
// I am an arrow function
const anonymous = function () { console.log("I am an anonymous function"); }
callbackCaller(anonymous); // okay
// I am an anonymous function
try {
callbackCaller(sayMyName); // error, 'this' types are incompatible
} catch (e) {
console.log(e); // TypeError: this is undefined
}
但是,当您使用类方法尝试时会遇到问题:
class Weasley {
constructor(private givenName: string) { }
greet() {
console.log("Hi, my name is " + this.givenName + " Weasley.");
}
}
const ron = new Weasley("Ron");
ron.greet(); // Hi, my name is Ron Weasley.
try {
callbackCaller(ron.greet); // oops, no compile error!!!
} catch (e) {
console.log(e); // TypeError: this is undefined
}
TypeScript完全无法捕获ron.greet
具有this
类型的Weasley
上下文,而是将其视为this
上下文属于{{1}的类型}。最初,在实现any
参数时,将有一个this
编译器标志来处理此问题,但该标志已被删除。建议添加open issue in Github,但目前此功能不是该语言的一部分。 (如果您希望看到它添加的内容,则可能要解决该问题,并给它一个?或描述它的用例,如果它比现有的方法更具吸引力。)
解决方法是采用您关心的任何类方法,并明确地为其指定--strictThis
参数。可以使用的合理类型是polymorphic this
type,其最终结果如下:
this
解决了这个问题:
class Malfoy {
constructor(private givenName: string) { }
greet(this: this) { // <-- this parameter of type this
console.log("It is I, " + this.givenName + " Malfoy.");
}
}
以要求人们使用const draco = new Malfoy("Draco");
draco.greet(); // It is I, Draco Malfoy.
try {
callbackCaller(draco.greet); // error, won't work unless bound
} catch (e) {
console.log(e); // TypeError: this is undefined
}
修饰类方法的代价为代价。这对您来说可能是一个破坏交易的事情,因为您根本无法要求其他人这样做。我不知道。
您可能可以使用一些奇特的类型处理来强制TypeScript向类的所有方法中添加this: this
参数,例如:
this
但是同样,在别人的方法传递给您的type Thisify<T> = {
[K in keyof T]: T[K] extends (...args: infer A) => infer R
? (this: Thisify<T>, ...args: A) => R : T[K]
}
const thisify = <T>(instance: T) => instance as Thisify<T>;
const reformedRon = thisify(ron);
reformedRon.greet(); // Hi, my name is Ron Weasley.
try {
callbackCaller(reformedRon.greet); // error, won't work unless bound
} catch (e) {
console.log(e); // TypeError: this is undefined
}
函数之前,您可能没有机会{@ {1}}。我认为,如果没有thisify()
,我们就会陷入困境。
好的,希望仍然有帮助。祝你好运!