typescript - İç içe nesnenin tüm anahtarları nasıl özyinelemeli olarak alınır?


type NestedObject = {
 amount: number,
 error: string | null,
 data: {
  rows: [],
  messages: {
   goodNews: string | null,
   badNews: string | null
  }
 }
}

//trying recursively get all keys 
type AllKeys<T, K extends keyof T> = 
 T extends object ?
  T extends infer O ? 
   {keys: K | AllKeys<O, keyof O> : never
 : K

type Test = AllKeys<NestedObject, keyof NestedObject>

sonuç olarak sahip olduğum:

type Test = { keys: 'amount' | 'error' | 'data' | ... }

ama almam gerekiyor:

type Test = { keys: 'amount' | 'error' | 'data' | 'rows' | 'messages' | 'goodNews' | 'badNews'}

Cevap #1

Görünüşe göre sen bunun gibi bir şey istiyorsun:

type RecursiveKeyof<T> = T extends object ? (
    T extends readonly any[] ? RecursiveKeyof<T[number]> : (
        keyof T | RecursiveKeyof<T[keyof T]>
    )
) : never

Bu, nesne türlerine kadar yineleme yapar ve size tüm alt özelliklerin ve alt-alt özelliklerin vb. anahtarlarını verir. İlkel türleri yok sayar (bu yüzden keyof string yoktur) ve dizileri özel durum olarak ele alır; böylece yalnızca dizinin elemanlarının anahtarlarını alırsınız, dizinin kendisini değil (dizinin number ve "push", "pop" vb. gibi anahtarları vardır).

AllKeys görünüyor ki bir keys özelliği istiyor, böylece bunu şu şekilde yazabiliriz:

type AllKeys<T> = { keys: RecursiveKeyof<T> }

İşleyip işlemediğine bakalım:

type Test = AllKeys<NestedObject>
// type Test = {keys: "amount" | "error" | "data" | "rows" | "messages" | "goodNews" | "badNews" }

Güzel görünüyor.

Koda yönelik oyun alanı bağlantısı

Cevap #2

Bu işe yarıyor:

type NestedObject = {
 a: number,
 b: {
  bb: string[],
  cc: string,
  dd: {
    foo: string
    bar: {
      baz: 'qqq'
    }
  }
 }
}

type AllKeys<O extends object, K = O[keyof O]> =
  keyof O
  | (
    K extends any[]
      ? never
      : K extends object
        ? AllKeys<K>
        : never
  )

type Test = AllKeys<NestedObject>

İşte benim oyun alanım.