Typescript通过元组中的对象路径从对象中提取类型

kqlmhetl  于 2023-03-13  发布在  TypeScript
关注(0)|答案(3)|浏览(204)

有没有可能提取类型形式的对象提供一个路径,它在N大小的元组格式。如果是这样,如何?例子我有什么想法:

type ExtractType<O, T> = ...;
type Foo = ExtractType<{ a: { b: number } }, ['a', 'b']> // I expect Foo type to be number
p1iqtdky

p1iqtdky1#

下面的naive版本,naive表示我不限制path为对象的有效路径,如果key path无效,返回类型将是unknown

type ExtractType<O, T extends Array<any>> = {
  [K in keyof O]:
    ((...a: T) => any) extends ((a: any, ...args: infer Tail) => any)
 ? Tail['length'] extends 0 ? O[K] : ExtractType<O[K], Tail> : never
}[T[0]]

// example Foo is number
type Foo = ExtractType<{ a: { b: { c: {d: number} } }, g: string }, ['a', 'b', 'c', 'd']>

它是递归类型,所以深度不受限制。需要考虑的几件事:

  • ((...a: T) => any) extends ((a: any, ...args: infer Tail) => any)这部分用来切掉元组的头,递归地处理尾。这意味着我们遍历对象,直到带键的元组为空。每次递归调用都少处理一个元素。
  • Tail['length'] extends 0 ? O[K] : ExtractType<O[K], Tail>-仅当我们位于键元组的末尾时才采用值类型
lndjwyie

lndjwyie2#

如果你想把自己的深度限制在2,所以只用一个元组作为路径,你可以使用下面的类型定义:

type ExtractType<
  O extends { [K1 in T[0]]: { [K2 in T[1]]: any } },
  T extends [string, string]
> = O[T[0]][T[1]];

type Foo = ExtractType<{ a: { b: number } }, ['a', 'b']> // number

Playground链接

mnemlml8

mnemlml83#

Maciej Sikora的答案对我不起作用。更改字符串的数组可以更容易地在Typescript中递归遍历:

export type ExtractType<T, K extends string = string> =
  K extends `${infer KHead}.${infer KTail}`
  ? (KHead extends keyof T ? ExtractType<T[KHead], KTail> : never)
  : (K extends keyof T ? T[K] : never);

所以你可以称之为:

ExtractType<{ a: { b: number } }, 'a.b'> // = number

相关问题