#Define function overloads in interface or type?

19 messages · Page 1 of 1 (latest)

outer vapor
#

Is it possible to define all the overloads of a function in an interface or type, ideally with some type parameters?

I have a collection of functions that all have roughly the same set of overloaded signatures, and it feels bad to have basically the same 50 lines or so in every file. Can this be abstracted out to a type somehow?

See playground link for simplified example of what I'm talking about.

toxic jasperBOT
#
isaacs__#0

Preview:```ts
interface Options {
sync?: boolean
}
type OptionsSync = Options & { sync: true }
type OptionsAsync = Options & { sync?: false }

type Result = { result: true }

// should work like this:

function Works(): void
function Works(options: OptionsSync): Result
...```

tranquil basalt
#

You have to use a cast.

outer vapor
#

ughhhhhh ok

#

oh, what if i defined it as an interface with an overloaded method, and then create a class with that interface, and export the method from a single lone instance?

tranquil basalt
#

Don't think that works.

#

In generally there's no way to assign a non overload to an overload.

#

And well, overload also isn't safe in general so I tend to avoid it altogether.

outer vapor
#

yeah, if I were to rewrite this again, I'd ditch the overloads altogether, and just export different functions for the different options, but it's a legacy JS lib, and that was a pretty common pattern pre-TS

#

in general, I feel like "return types depend on arguments" is a smell

#

yeah, doing it with a class+interface means you still have to define the method a bunch of times or else it yells.

tranquil basalt
outer vapor
#

it's not bad when it's one flag like this example, but you have sync+file, sync+no file, async+file, async + no file, maybe sync + file, ....

#

so tedious

#

so n flags become 3^n possibilities, because each one has to be true, false, unknown

tranquil basalt
#

Personally if you are stuck with this, you can just do:

const overloaded: Overloaded = (options?: Options) => {
    // ...
} as never

If typing the arguments again is too much work, you can also do:

const overloaded = defineOverloaded((options) => {
    // ...
})

That will reduce the boilerplate and provide some type safety and easier refactoring.

outer vapor
#

ah, yeah, a factory is probably the least bad option here.

#

though, I was hoping to avoid an extra run-time call. Doing it all in types means the resulting JS just dtrt with no overhead

tranquil basalt
#

The overhead would only affect start up time and is an one time cost. I would also assume JIT can optimize const defineOverloaded = x => x very well.