网站搜索

javascript - 仅接受对象类型的函数的 TypeScript 类型


有没有一种方法可以定义一个 TypeScript 类型,使得只有接受单个 对象 参数的函数可以赋值给它?例如:

type RestrictToObjectParam = any; // TODO

let fun: RestrictToObjectParam;
fun = (arg: object) => {};                 // OK
fun = (arg: {}) => {};                     // OK
fun = (arg: {str: string}) => {};          // OK
fun = (arg: {obj: {}, num: number}) => {}; // OK
fun = (arg: number) => {};                 // ERROR

类似 (arg: object) => any 的东西行不通,因为第三个例子不能赋值给它。我尝试过其他的东西,比如:

  • <T extends object>(arg: T) => any 用于约束参数类型
  • `T extends object ? (arg: T) => void : never` 用于分发参数类型

但那些似乎只是归结为 (arg: object) => any。

这可能吗?我可能对 TypeScript 中函数类型的工作方式理解有误。

答案#1

这是由在比较函数类型时函数参数双变性引起的。在 strict 模式下,编译器选项 strictFunctionTypes 默认为 true,但是你可以将其设置为 false 以实现所需的兼容性行为——但是,请注意文档中的警告:

函数参数双变性

在比较函数参数类型时,如果源参数可以分配给目标参数,或者反之,则赋值成功。这是不安全的,因为调用者可能最终得到一个接受更专化类型的函数,但却用较不专化的类型调用该函数。实际上,这种错误很少发生,而允许这样做可以实现许多常见的 JavaScript 模式。

TS 游乐场

type RestrictToObjectParam = (arg: object) => any;

let fun: RestrictToObjectParam;
fun = (arg: object) => {}; // Ok
fun = (arg: {}) => {}; // Ok
fun = (arg: { str: string }) => {}; // Ok
fun = (arg: { obj: {}; num: number }) => {}; // Ok
fun = (arg: number) => {}; /* Error
~~~
Type '(arg: number) => void' is not assignable to type 'RestrictToObjectParam'.
  Types of parameters 'arg' and 'arg' are incompatible.
    Type 'object' is not assignable to type 'number'.(2322) */