我有以下(人为的)TypeScript代码:
interface hasSpecialField {
specialField: string;
}
interface hasStringFn {
fn: (this: hasSpecialField) => string;
}
function whatIsMyContext(this: hasSpecialField): string {
return this.specialField;
}
function getObj(): hasStringFn {
let toBeBound: hasSpecialField = {
specialField: 'Can whatIsMyContext() access me?'
};
let obj: hasStringFn = {
fn: whatIsMyContext.bind(toBeBound)
};
return obj;
}
let parentObj = getObj();
let result = parentObj.fn();
console.log(result);
如果我写出并执行此代码的JavaScript等价物,没有任何类型的注释,我会看到以下内容:
Can whatIsMyContext() access me?
undefined
这是有道理的,因为whatIsMyContext
显式绑定到toBeBound
,this.specialField
具有console.log
引用的字段。此外,最后一行是undefined
,它不返回值,因此let result = parentObj.fn();
。
但是,TypeScript会为此代码抛出错误:
' this'类型的上下文有hasStringFn'不能分配方法'这个'类型' hasSpecialField'。物业' specialField'缺少类型' hasStringFn'。
错误消息指向行whatIsMyContext
。从fn
调用时,TypeScript似乎认为this
(parentObj
别名)具有错误的{{1}}上下文。为什么会这么想?我应该如何编写代码以保留类型信息,同时向TypeScript发出上下文绑定正确的信号?
答案 0 :(得分:2)
就类型检查而言,接口hasStringFn
正如您声明的那样,它本身无法使用。您的声明说fn
只能在具有specialField
的对象上调用:
let a: hasStringFn;
let b: hasSpecialField;
a.fn(); // error
a.fn.call(b) // ok
一种可能的方法是声明一个带有函数属性fn
的接口,它甚至没有this
参数,就像独立函数一样:
interface hasBoundStringFn {
fn: () => string;
}
然后这段代码编译:
function getObj(): hasBoundStringFn {
let toBeBound: hasSpecialField = {
specialField: 'Can whatIsMyContext() access me?'
};
let obj: hasStringFn = {
fn: whatIsMyContext.bind(toBeBound)
};
return obj;
}
let parentObj = getObj();
let result = parentObj.fn();
下一个问题:
所以我的结论是TypeScript正在查看 接口,而不是实现,当它抛出该错误?其他 单词,代码是有效的,但TypeScript看起来没有比 解析它的界面?
是的,如果您明确声明变量或函数类型,编译器会相信您(只要它与代码中的用法不矛盾)并且不会再看。
您可以通过删除尽可能多的类型注释来检查编译器将从实现中获得什么:
interface hasSpecialField {
specialField: string;
}
function whatIsMyContext(this: hasSpecialField): string {
return this.specialField;
}
function getObj() {
let toBeBound = {
specialField: 'Can whatIsMyContext() access me?'
};
let obj = {
fn: whatIsMyContext.bind(toBeBound)
};
return obj;
}
let parentObj = getObj();
let result = parentObj.fn();
console.log(result);
在您的情况下,代码会编译,但这不是因为TypeScript确定实现是有效的。这是因为getObj
的推断类型是
function getObj(): { fn: any; }
你看,bind
是内置的,编译器无法访问它的实现,它必须相信TypeScript标准库中给出的bind
的类型声明。
现在,bind
,call
和apply
为effectively untyped。
因此,在这种特殊情况下,您必须提供自己的显式类型和接口,以使编译器检查您的代码。