const fn = () => null
type Answer = typeof fn extends Record<string, any> ? true : false
上面的代码段产生的Answer
类型为true
,表明函数被视为Record
的子类型。为什么?
如何使我的类型更严格,以使函数不是其子类型?
答案 0 :(得分:4)
因此,根据您的评论,您需要类似“不是功能的对象”之类的东西。 TypeScript当前没有negated types,因此没有简洁的方式来表示“不是函数”。根据您的用例,您可能只想耸耸肩并继续前进。
或者,您可以尝试通过变通办法迫使TypeScript屈服于您的意愿。
最简单的解决方法是找到函数始终具有的某些属性,并声明您的类型具有不兼容的同名可选属性。例如:
type NoCall = { call?: number | string | boolean | null | undefined, [k: string]: any };
const okay: NoCall = { a: 4 }; // okay
const err: NoCall = () => 2; // error
缺点是您将失去验证某些合法非功能的能力(在上述情况下,{call: ()=>0}
不是功能,但无法验证为NoCall
)。但是对于您的用例来说,可能有些误报可以吗?
无论如何,根据标准库lib.es5.d.ts
进行检查的属性名称的合理选择是apply
,call
,bind
,arguments
和{{ 1}}。
如果您不想放弃其中一个名称,则可以选择使用global augmentation向caller
界面添加幻像属性:
Function
这使得属性名称冲突的可能性较小,但会污染全局名称空间,并使此解决方法变得相当简单。
另一种解决方法是将trick与conditional types一起使用,以防止将函数作为参数传递给另一个函数:
declare global {
interface Function {
'*FunctionsHaveThis*': true
}
}
type ObjNotFunction = { '*FunctionsHaveThis*'?: never, [k: string]: any };
const okay: ObjNotFunction = { a: 4 }; // okay
const err: ObjNotFunction = () => 2; // error
function noFunctionsPlease<T extends object>(t: T & (T extends Function ? never : T)) {
// do something with t
}
noFunctionsPlease({ a: 4 }); // okay
noFunctionsPlease(() => 2); // error
的类型或多或少准确地说是“不是函数的对象”,但只能表示为函数参数。
希望其中之一对您有所帮助或为您提供有关如何(或是否)进行的想法。祝你好运!
答案 1 :(得分:3)
Record<string, any>
表示具有任何字符串键和任何值的任何对象。所有函数都是对象,并且它们具有一些属性(我们甚至可以索引到对象fn['call']
中)。根据这些定义,由于Typescript中的类型关系基于结构,因此typeof fn
确实扩展了Record<string, any>