为什么打字稿ES6无法检测到对象不是函数?
find: (collection: string, query: object, sortQuery = {}, cb?: Function) => {
socketManager.call('find', collection, query, sortQuery, cb);
}
基于此功能,您会认为这将失败:
this._services._socket.methods.find('vendors', {type: 'repair'}, (errVen, resVen) => {}
由于没有sortQuery对象,而是一个回调函数。这没有给我任何类型的错误,意味着Typescript允许将回调作为对象类型。
如何确保这会导致错误?
答案 0 :(得分:1)
使用TypeScript Conditionals(TS v2.8),我们可以使用Exclude
使用Functions
从object
类型中排除Exclude<T, Function>
:
let v = {
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function>, cb?: (a: string, b: string) => void) => {
}
}
// Invalid
v.find('vendors', { type: 'repair' }, (a, b) => { })
v.find('vendors', { type: 'repair' }, 'I am a string', (a, b) => { })
// Valid
v.find('vendors', { type: 'repair' }, { dir: -1 })
v.find('vendors', { type: 'repair' }, { dir: -1 }, (a, b) => { })
然后可以像这样设置默认参数值:
sortQuery: Exclude<T, Function> = <any>{}
如下图所示,对find
的前两个调用会引发错误,而对find
的后两个调用不会引发错误:
随后显示的错误如下:
- [ts]类型'(a,b)=> void'的参数不能分配给'never'类型的参数。 [2345]
- [ts]类型““我是字符串””的参数不能分配给类型“对象”的参数。 [2345]
答案 1 :(得分:0)
对象和函数本质上是同一件事,但是键入可以帮助我们区分它们的功能。
考虑一下:
const foo1: { (): string } = () => "";
变量foo
的类型为object
,但是该对象是可调用的……它是一个函数,确实可以调用,但是不能设置名为{ {1}}。
bar
也考虑一下:
foo1(); // This works
foo1.bar = 5; // This, not so much.
变量const foo2: { bar?: number; } = {};
上有一个名为foo
的属性。可以设置该属性,但是不能调用该对象,因为它的类型不为可调用。
bar
因此,让我们看一下您的原始键入:
foo2.bar = 5; // This works
foo2(); // This, not so much.
sortQuery = {}
是一个对象,但这就是我们所知道的全部。它没有任何属性,不能调用,只是一个对象。
我们已经看到一个函数是一个对象,因此您可以为其分配一个函数。但是,您将无法调用它,因为它没有定义为可调用。
sortQuery
如果您完全控制源代码,那么解决此问题的一种方法是将多个参数移动到具有命名属性的单个参数:
const sortQuery: {} = () => ""; // This works.
sortQuery(); // This, not so much.
sortQuery.bar = 5; // Nor this.
这通过要求名称而不是依靠函数调用中的位置来消除任何歧义。