1

Is it possible to take a tuple of different objects, and get a type of all of these objects combined? For example if i have a tuple like this:

const t = tuple({current: 1}, {old: 2}, {new: 3}); //this should be interpreted as [{current: number;}, {old: number;}, {new: number;}]

and then i combine those objects into a single one:

let newob = {};
for(let ob of t) {
  Object.assign(newob, ob);
}

can I somehow make typescript treat this new object as a

typeof t[0] & typeof t[1] & typeof t[2]

which in this case would be

{current: number; old: number; new: number;}

without manually typing that all?

I'd like it to work with any tuple and any objects inside tuple

2 Answers 2

0

You can capture the parameters in a tuple type using a generic type parameter with a constraint of any[] for a rest parameter. You can the use UnionToIntersection described here to merge all tuple item types into a single intersection type

type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
function tuple<T extends any[]>(...t: T) {
  let newob = {} ;
  for (let ob of t) {
    Object.assign(newob, ob);
  }
  return newob as UnionToIntersection<T[number]>;
}

Playground Link

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, this does work. However I noticed a strange behavior, it isn't really a big problem, but if you try to put into tuple two class instance objects, and both of them have a private method of the same name, the whole thing return type of 'never'. Doesn't happen if methods are public or protected. Here's demo
There is a No overload matches this call error.
@LinDu fixed the build error. Some type compatibility changed since posted this 4 years ago
0

Following snippet types better your arguments and return types:

type Cast<From, To> = From extends To ? From : never;
type FoldIntoIntersection<T extends readonly {}[], Acc extends {} = {}> = T extends readonly [infer H, ...infer HS] 
    ? FoldIntoIntersection<Cast<HS, readonly {}[]>, Acc & H> 
    : Acc;

function tuple<const T extends readonly {}[]>(...t: T) {
  let newob: FoldIntoIntersection<T> = {} as any;
  for (let ob of t) {
    Object.assign(newob, ob);
  }
  return newob;
}

1 Comment

A good answer, I'd still choose UnionToIntersection. The behavior is built into the compiler and is probably faster than a recursive conditional type (even a tail recursive one)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.