# this
# this
采用 this 指代当前的对象类型。 在动态扩充对象方法时,利用 this 避免调用出错。
class FooC {
// 注意此处的返回值申明,要求返回的 this 同时具有泛型对象的属性
extend<T>(obj: {}): this & T {
Object.assign(this, obj);
// 类型断言避免返回类型 this 和 this & T 不匹配
return this as this & T;
}
hi() {
console.log('hi');
return this;
}
}
let fooC = new FooC();
fooC.hi();
fooC
.extend({
hello() {
console.log();
}
})
.hello(); // 报错, typescript 无法检测动态添加的方法,需要在 extend 显示申明扩充类型才可以
fooC
.extend<{ bye(): void }>({
bye() {
console.log('bye');
}
})
.hi()
.bye(); // 合法,由于返回值类型为 this & { bye():void} 的交叉类型包含所有属性
阅读 this-typing (opens new window) 进一步理解。
也可在函数中申明 this,限定函数中 this 的使用。
// 显示申明函数的 this 为空类型
function noThisHi(this: void, name: string) {
console.log(`Hi ${name}`);
}
// 注意函数调用时 this 不会被识别为参数,它只是限制 this 的使用
noThisHi('tom');
// 非法, 此处 call 的第一个参数为 this, TypeScript 识别到限制 this 修改
noThisHi.call({});
阅读 Specifying the type of this for functions (opens new window) 进一步理解。
# this 参数
在函数有时需要显示申明函数的 this 执行环境。 此时可以通过申明首个参数的 this 类型来实现。
function f1(this: void, foo: number) {
// 报错,因为已显示申明 this 为空
let b = this.a;
console.log(this, foo)
}
// 函数首个参数为 this 只是申明 this 在函数中的类型,并不代表实际参数
f1(12);
一个典型的使用是对回调标注,避免在回调函数中引用 this, 导致 js 中常见的 this 丢失问题。
type callback = (this: void, e: { type: string}) => void
function onChange(cb: callback) {
cb({ type: 'change'})
}
onChange(function(a) {
// 报错,无法在回调上使用 this.b 的属性
let foo = this.b;
console.log(a);
})
# fluent API
在 jquery 常见的链式调用方法,是通过返回对象的 this 实现的。 这种模式称为 fluent API (opens new window) 你可以通过将 返回对象声明为 this 类型实现推导和扩展。
class BasicCalculator {
public constructor(protected value: number = 0) {}
public currentValue(): number {
return this.value;
}
// 注意这里申明返回值为 this 而非 BasicCalculator, 这样可以使返回对象兼容子类的扩展提示
public add(operand: number): this {
this.value += operand;
return this;
}
public multiply(operand: number): this {
this.value *= operand;
return this;
}
}
let v1 = new BasicCalculator(2).multiply(5).add(1).currentValue();
class ScientificCalculator extends BasicCalculator {
public constructor(value = 0) {
super(value);
}
public sin() {
this.value = Math.sin(this.value);
return this;
}
}
v1 = new ScientificCalculator(2).multiply(5).sin().add(1).currentValue();# 知识点
- https://github.com/microsoft/TypeScript/pull/14141
- https://github.com/microsoft/TypeScript/pull/6739
- https://github.com/microsoft/TypeScript/issues/229