Select 基于 TypeScript 中第一个参数的函数重载

Select a function overload based upon the first argument in TypeScript

我想创建一个函数 f,它接受 Box<T> 作为它的第一个参数,第二个类型为 T 的参数是可选的,如果(且仅当! ) T extends null.

下面是 f 的调用方式:

let _ = new Box(null)
let o = new Box({})

f(_, null) // ✅
f(o, {})   // ✅
f(_)       // ✅
f(o)       // ❌ (should not compile)

这是我(试图)定义 f:

class Box<V = any> {
  constructor(public v: V) {}
}

type _ = null
type O = object

function f<V extends _>(b: Box<V>, v?: V): void
function f<V extends O>(b: Box<V>, v: V): void
function f(b: Box, v?: any) {}

乍一看似乎可行。但是有一个问题! f(o) 的错误报告如下:

Argument of type 'Box<{}>' is not assignable to parameter of type 'Box<null>'.

当我希望 f 的用户实际看到的错误是:

Expected 2 arguments, but got 1.

似乎 TypeScript 优先 select 重载第二个参数是可选的。当 T 不扩展 null 时,如何使它成为 select 另一个重载?或者以其他方式实现我的目标?

如果您在剩余参数中使用条件类型来基本上更改基于 V:

的最后一个参数的可选性,您会得到想要的错误
function f<V>(b: Box<V>, ...a: V extends null ? [v?: V]: [v:V]): void
function f(b: Box, v?: any) {}

Playground Link