Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

typescript union types from spread operator

I have a function with the following signature:

test<T>(...args: T[]): T

if I call the function like this:

const a = test(1, 2, 3)

everything works as expected (and a is of type number), but if I call it that way:

const a = test(1, 2, "asd")

I get any error: [EDIT] The 2 is red underlined: Argument of type '2' is not assignable to parameter of type '1'., witch might be a bit misleading because the arguments are constants, but if I call it that way:

let arg1 = 1;
let arg2 = "asd";
const a = test(arg1, arg2);

I get the error: Argument of type 'string' is not assignable to parameter of type 'number'.

How can I make it so that the function would (in the second case) has a return type of number | string without explicitly specifying it in the generic parameter.

like image 491
Hexception Avatar asked Apr 02 '26 21:04

Hexception


2 Answers

It is intentional that T is not inferred as a union; see Why isn't the type argument inferred as a union type?, as well as microsoft/TypeScript#19596 and microsoft/TypeScript#26746 for reasons why.

Probably the easiest way around this is to allow args to be any array type T whatsoever, and then get its element type by indexing into it with the key type number:

declare function test<T extends any[]>(...args: T): T[number];
const a = test(1, 2, 3) // number
const b = test(1, 2, "asd") // number | string

Playground link to code

like image 175
jcalz Avatar answered Apr 10 '26 02:04

jcalz


I think this is the call signature you are looking for:

<T extends Array<unknown>>(...args: T): T[number]

TypeScript Playground

like image 42
evelynhathaway Avatar answered Apr 10 '26 04:04

evelynhathaway