TypeScript:根据元组获取嵌套属性的类型

Jen*_*ens 3 typescript

在 TypeScript 中,有没有一种方法可以根据某些元组获取嵌套属性的类型?给定以下示例,假设元组是["bs", 0, "c"],那么类型应该是boolean(或者["bs", 0, "ds", 0, "f"]等等number)。

interface Foo {
  a: string;
  bs: {
    c: boolean;
    ds: {
      e: null;
      f: number;
    }[];
  }[];
}
Run Code Online (Sandbox Code Playgroud)

对于某些上下文,我想输入一个带有两个参数 apath和 a 的函数value。对于某些对象,如果给定路径的值是一个数组,它将是push参数value。这个函数的实现可以在这个 Playround中找到。我已经在寻找一些解决方案,例如在本期中,但我认为我的问题有点不同。

jca*_*alz 5

在 TS4.1 中,将支持递归条件类型,这使得这有点简单:

type Keys = readonly (string | number)[];
type DeepIndex<T, KS extends Keys, Fail = undefined> =
    KS extends [infer F, ...infer R] ? F extends keyof T ? R extends Keys ?
    DeepIndex<T[F], R, Fail> : Fail : Fail : T;
Run Code Online (Sandbox Code Playgroud)

有了DeepIndex,您可以给出add()以下类型签名:

function add<KS extends Keys>(
    pathToArray: [...KS],
    value: DeepIndex<Foo, KS> extends Array<infer T> ? T : never
) {
    const xs = path(pathToArray, foo);

    if (Array.isArray(xs)) {
        xs.push(value);
    }
}
Run Code Online (Sandbox Code Playgroud)

导致你所说的是你想要的行为:

add(["bs", 0, "ds"], { e: null, f: 1 });
/* function add<["bs", 0, "ds"]>(pathToArray: ["bs", 0, "ds"], value: {
    e: null;
    f: number;
}): void */

add(["bs"], {});
// Argument of type '{}' is not assignable to parameter of 
// type '{ c: boolean; ds: { e: null; f: number; }[]; }'.

add(["a"], {});
// Argument of type '{}' is not assignable to parameter of type 'never'.(2345)
add(["bs", 0, "c"], {});
// Argument of type '{}' is not assignable to parameter of type 'never'.(2345)
Run Code Online (Sandbox Code Playgroud)

Playground 代码链接