網站搜尋

typescript - 使用點記法為物件路徑定義型別


我正在嘗試輸入一個用點記法表示物件路徑的字串(例如:"users.1.name")。我已經非常接近擁有一個完全可行的解決方案。我的最後一個問題是遞迴類型會出現這個錯誤:

Type instantiation is excessively deep and possibly infinite.

我想解決這個問題,或者至少找到一種限制遞迴的方法,以免出現這個錯誤。

這是我的程式碼(Playground):

type PathImpl<T, K extends keyof T> =
  K extends (string | number)
  ? T[K] extends Record<string, any>
    ? T[K] extends ArrayLike<any>
      ? K | `${K}.${PathImpl<T[K], number>}`
      : K | `${K}.${PathImpl<T[K], keyof T[K]>}`
    : K
  : never;

export type ObjectPath<T> = PathImpl<T, keyof T> | keyof T;


// Test:

type User = {
  name: string,
  address: {
    lines: {
      street: string,
      streetNumber: number
    }[],
    zip: string,
  }
};

const streetNumber: ObjectPath<User> = "address.lines.2.streetNumber" // ✅
const foo: ObjectPath<User> = "address.lines.2.foo" // ❌ rejects invalid path as expected


// Recursive type (TS is fine with it)
type UserWithFriends = {
  name: string,
  friends: UserWithFriends[]
}

// TS Error: Type instantiation is excessively deep and possibly infinite.
const f: ObjectPath<UserWithFriends> = 'name'

(這段程式碼的靈感來自這則推文)