1

How to convert array of objects type to flat object type? For example:

type T1 = [{
    base: string;
}, {
    hover: any;
}]

type T2 = ConvertToFlat<T1>

and T2 is:

{
    base: string;
    hover: any;
}

What inside ConvertToFlat?

Typescript Playground

jeshio
  • 605
  • 5
  • 7
  • `Object.assign()` takes a variable number of sources so you can splat in an array: `Object.assign({}, ...t1value)` – ccarton Sep 10 '20 at 11:33
  • @ccarton this question is about Types only. If we would talk about JS, I've used Array.reduce function to merge multiple objects – jeshio Sep 10 '20 at 13:33

3 Answers3

2

This does it, but not very pretty:

type ConvertToUnion<U> = U extends Array<infer X> ? {[K in keyof X]:X[K]} : never
type ConvertToIntersection<U extends {[K:string]: any}> = (U extends any ? (x:U)=>void : never) extends (x:infer X)=>void ? X : never
type ConvertToFlat<T> = ConvertToIntersection<ConvertToUnion<T>>

The second type is based on this post

Playground

sam256
  • 1,291
  • 5
  • 29
1

Heres what I have come up with:

type T1 = [
  {
    base: string
  },
  {
    hover: any
  }
]

type ConvertToFlat<T extends any[]> = T['length'] extends 0
  ? {}
  : ((...b: T) => void) extends (a, ...b: infer I) => void
  ? { [P in keyof T[0]]: T[0][P] } & ConvertToFlat<I>
  : []

type T2 = ConvertToFlat<T1>

// inferred type of T2 = { base: string } & { hover: any }

Following code should do what you exactly want but I think because of this open issue, it does not infer correctly.

// Names of properties in T with types that include undefined
type OptionalPropertyNames<T> = { [K in keyof T]: undefined extends T[K] ? K : never }[keyof T]

// Common properties from L and R with undefined in R[K] replaced by type in L[K]
type SpreadProperties<L, R, K extends keyof L & keyof R> = {
  [P in K]: L[P] | Exclude<R[P], undefined>
}

type Id<T> = { [K in keyof T]: T[K] } // see note at bottom*

// Type of { ...L, ...R }
type Spread<L, R> = Id<
  // Properties in L that don't exist in R
  Pick<L, Exclude<keyof L, keyof R>> &
    // Properties in R with types that exclude undefined
    Pick<R, Exclude<keyof R, OptionalPropertyNames<R>>> &
    // Properties in R, with types that include undefined, that don't exist in L
    Pick<R, Exclude<OptionalPropertyNames<R>, keyof L>> &
    // Properties in R, with types that include undefined, that exist in L
    SpreadProperties<L, R, OptionalPropertyNames<R> & keyof L>
>


type ConvertToFlat1<T extends any[]> = T['length'] extends 0
  ? {}
  : ((...b: T) => void) extends (a, ...b: infer I) => void
  ? Spread<{ [P in keyof T[0]]: T[0][P] }, ConvertToFlat1<I>>
  : []

type T22 = ConvertToFlat1<T1>

Note I have copied some of these snippets from here:

  1. Typescript: Remove entries from tuple type
  2. Typescript, merge object types?
Pritam Kadam
  • 2,388
  • 8
  • 16
0

This is also a solution:

UnionToIntersection<T> is based on the jcalz answer to a similar question.

type UnionToIntersection<U> = (U extends any
  ? (k: U) => void
  : never) extends ((k: infer I) => void)
  ? I
  : never;

type KeysOf<T extends any[]> = Exclude<keyof T, keyof []>
type ValuesOf<T> = T[keyof T];
type Flatten<T extends any[]>  = UnionToIntersection<ValuesOf<Pick<T, KeysOf<T>>>>;

Link to playground

leonat
  • 127
  • 8