Home > Software engineering >  Select a function overload based upon the first argument in TypeScript
Select a function overload based upon the first argument in TypeScript

Time:02-16

I would like to create a function f that accepts a Box<T> as its first argument, and a second argument of type T that is optional if (and only if!) T extends null.

Here is how one would call f:

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

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

And here is how I have (attempted to) define 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) {}

This seems to work at first glance. But there's a problem! The error for f(o) reports the following:

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

When the error I want users of f to actually see is:

Expected 2 arguments, but got 1.

It seems that TypeScript is preferentially selecting the overload where the second argument is optional. How do I make it select the other overload when T does not extend null? Or otherwise achieve my goal?

CodePudding user response:

You can get the error you want if you use a conditional type in a rest parameter to basically change the optionality of the last argument based on V:

function f<V>(b: Box<V>, ...a: V extends null ? [v?: V]: [v:V]): void
function f(b: Box, v?: any) {}

Playground Link

  • Related