这不是一个bug。尾随参数较少的函数是
substitutable
mentioned in the TypeScript FAQ
.
理由大致是:JavaScript中的任何函数都可以用任意数量的参数来调用,让调用方向函数发送比预期更多的参数总是安全的;你只是忽视他们。就你而言,
const aCallback: CallbackWithNameParameter = {
cb: () => {}
};
有效,因为
aCallback.cb
忽略第一个参数,该参数必须是
string
aCallback.cb('hey'); // no problem
第二种情况,
aSecondCallback
,无效,因为它会错误地将第一个参数解释为
number
而不是
事实上将是这样。这不安全,很可能是一个错误。
差不多就是这样。希望这有帮助;祝你好运
@jbmilgrom公司
said
谢谢你的回答。它在第一次阅读时完全有意义,但现在遇到了以下问题:
aCallback.cb()
这是一个编译错误,因为您声明
aCallback
是
CallbackWithNameParameter
谁的
cb
一串
参数TypeScript不再知道或关心
aCallback公司
谁的
断路器
如果您这样做了:
interface CallbackWithNoParameter {
cb: () => void
}
const aCallback: CallbackWithNoParameter = {
cb: () => {}
};
aCallback.cb(); // okay
这会奏效的。
可替代性通常不是对称的:
declare let noParam: CallbackWithNoParameter;
declare let oneParam: CallbackWithNameParameter;
oneParam = noParam; // yes
noParam = oneParam; // no
您可以将窄类型(没有参数的回调)分配给更宽的类型(只有一个参数的回调),而不会出错,但通常不能执行相反的操作。
更新2
@jbmilgrom公司
said
aCallback公司
在实现时可以成功地定义为没有参数的空函数
CallbackWithNameParameter
. 然而,它不能这样称呼,因为你知道,它是一种类型
CallbackWithNameParameter
oneParam
)永远不能
所以
这是因为您通过声明更宽的类型使TypeScript忘记了。你倒了牛奶(窄型,像
CallbackWithNoParameter
)放入标有“液体”的容器(较宽的类型,如
CallbackWithNameParameter
),然后试图打开容器,将液体倒入你的茶中,但没有检查它是否是漂白剂。你可能知道容器里有牛奶,但TypeScript只知道它是液体,并试图保护你。避免这种情况的最好方法是将牛奶倒入标有“牛奶”的容器中。如果有人稍后向你要液体,你可以给他们一个牛奶容器的内容物,但如果有人向你要牛奶,你不能给他们一个液体容器的内容物,除非有办法首先检查它是否是牛奶。
function isCallbackWithNoParameter(x: any): x is CallbackWithNoParameter {
if (!('cb' in x)) return false;
try {
x.cb()
} catch (e) {
return false;
}
return true;
}
declare let noParam: CallbackWithNoParameter;
declare let oneParam: CallbackWithNameParameter;
oneParam = noParam; // yes
noParam = oneParam; // no
oneParam.cb(); // no
if (isCallbackWithNoParameter(oneParam)) {
noParam = oneParam; // okay, you checked first
oneParam.cb(); // okay, you checked first
}