#Overload matching on union type

12 messages · Page 1 of 1 (latest)

chrome flame
#

I'm running into an issue that I know how to resolve but I don't know how to understand / explain. Let's say I have a ReadableStream that I can read off of in chunks of string | Buffer<ArrayBufferLike>

I am unable to call Buffer.from on the union of the two but I can run Buffer.from on each variant. How come?

I'll share a playground link in the thread

fallow rampartBOT
#
tinydatail3521#0

Preview:```ts
import * as fs from "fs"; // for type acquisition

// works fine
declare const bufferChunk: Buffer<ArrayBufferLike>
Buffer.from(bufferChunk)

// works fine
declare const stringChunk: string
Buffer.from(stringChunk)

// No overload matches this call.
// The last overload gave the following error.
...```

harsh dawn
#

@chrome flame This is just an aspect of how overloads work:

fallow rampartBOT
#
declare function foo(x: string): string;
declare function foo(x: number): number;

declare const x: string | number;
foo(x)
//  ^
// No overload matches this call.
//   Overload 1 of 2, '(x: string): string', gave the following error.
//     Argument of type 'string | number' is not assignable to parameter of type 'string'.
//       Type 'number' is not assignable to type 'string'.
//   Overload 2 of 2, '(x: number): number', gave the following error.
//     Argument of type 'string | number' is not assignable to parameter of type 'number'.
//       Type 'string' is not assignable to type 'number'.
chrome flame
#

Thanks for the reply! I expect something like your example to error because the return type of each overload is different, so I imagine (correct me if I'm wrong) that typescript can't confidently provide the return type even if the implementation would theoretically succeed against the union right?

But in the example I shared, the return type of Buffer.from is always Buffer which I thought might be possible and I was curious why that was not the case.

Appreciate the response though!

harsh dawn
#

@chrome flame Yeah, in theory, TS could try to support 'combination' signatures that are unions of the other signatures, but I think the TS team looked and it was complex/expensive.

#

Like if you've got 10 signatures, in theory there's at least 10*9 potential 'union signatures' (and more if you consider combinations of more than two signatures)

#

If you want to modify the Buffer typings to add a union signature you probably can, otherwise probably easy enough to just have the 'unnecessary' ternary.

chrome flame
#

Got it, thanks so much for the discussion!

dry jewel
#

Isn't this exactly the use case for generics, or am I missing something?

declare function foo<T>(x: T): T;
harsh dawn
#

The foo case is a simplified example that illustrates the issue, where you could use generics.

#

And in general you can often rewrite overloads into generics that use conditional types, but they can have their own problem.