简体   繁体   中英

How to deep flatten an interface in Typescript?

for example:

interface a {
  name: string 
  nested: {
    lastName: string 
    nested: {
      age: number
    }
  }
}

I want that to become:

interface b {
  name: string 
  lastName: string 
  age: number
}

interface values will be dynamic, so I probably need some kind of recursive solution to this

I only ended up with finite solutions

Here's a solution using mapped and conditional types: FlattenPairs constructs a union of pairs like ['name', string] | ['lastName', string] | ['age', number] ['name', string] | ['lastName', string] | ['age', number] ['name', string] | ['lastName', string] | ['age', number] , then Flatten converts this into an object type. I assumed that the nested properties are not necessarily all named nested (and do not necessarily have predictable property names), so the type Primitive is needed as the base case for the recursion.

type Primitive = string | number | boolean
type FlattenPairs<T> = {[K in keyof T]: T[K] extends Primitive ? [K, T[K]] : FlattenPairs<T[K]>}[keyof T] & [PropertyKey, Primitive]
type Flatten<T> = {[P in FlattenPairs<T> as P[0]]: P[1]}

Example:

interface TestInterface {
  name: string 
  nested: {
    lastName: string 
    nested: {
      age: number
    }
  }
}

// {age: number, lastName: string, name: string}
type Test = Flatten<TestInterface>

Playground Link

The helper type FlattenPairs can be written in a slightly simpler way if the nested property name(s) are known:

type FlattenPairs<T> = {[K in keyof T]: K extends 'nested' ? FlattenPairs<T[K]> : [K, T[K]]}[keyof T]

Playground Link

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM