DeepRequired<T> with Shift<T> 不可分配

DeepRequired<T> with Shift<T> not assignable

我正在尝试编写一个实用程序,可以根据需要设置对象的深度键。

什么有效

到目前为止,我想出了一种方法来获取对象的所有可能 Leaves,我想将其用于路径验证。它将所有键路径收集到数组中,但在可选键处停止以解决无限深度问题。

然后,我还制作了DeepRequired,它根据传递的叶子将属性设置为必需的:

type Person = {
  name: string;
  father?: Person;
  mother?: Person;
  siblings?: Person[];
  contact: {
    email: string;
  };
  created_at: Date;
};

type PersonLeaves = Leaves<Person>;
// type PersonLeaves = ["name"] | ["father"] | ["mother"] | ["siblings"] | ["contact", "email"];

type PersonWithParents = DeepRequired<Person, ["father" | "mother"]>;
// type PersonWithParents = {
//   name: string;
//   father: Person; // Note how this is now required
//   mother: Person; // Note how this is now required
//   siblings?: Person[];
//   contact: {
//     email: string;
//   };
//   created_at: Date;
// }

type PersonWithFatherSiblings = DeepRequired<DeepRequired<Person, ["father"]>, ["father", "siblings"]>;
// type PersonWithFatherSiblings = {
//   name: string;
//   father: PersonWithSiblings; // Father is required, then father's siblings is required.
//   mother?: Person;
//   siblings?: Person[];
//   contact: {
//     email: string;
//   };
//   created_at: Date;
// }

问题

这些实用程序似乎都按预期工作,但我在 DeepRequired 定义中的 Shift 确实遇到了错误,而且我在 vscode 中没有得到任何路径建议使用 DeepRequired.

编写类型时
Type 'Shift<P>' does not satisfy the constraint 'Leaves<T[K]>'.
  Type 'unknown[] | []' is not assignable to type 'Leaves<T[K]>'.
    Type 'unknown[]' is not assignable to type 'Leaves<T[K]>'.

我想弄清楚为什么会这样。有人可以帮助改进吗?

TL;DR

请参阅 playground 以查看带有错误的工作示例

谢谢!

请告诉我它是否适合你:

type Concat<T extends any, A extends any[]> = [T, ...A];

type Shift<T extends any[]> = T extends [infer _, ...infer A] ? A : [];

type OptionalKeys<T extends object> = {
  [K in keyof T]-?: T extends Record<K, T[K]> ? never : K;
}[keyof T];


type Leaves<T> = T extends (infer U)[]
  ? Leaves<U>
  : T extends object
  ? {
    [K in keyof T]-?: K extends OptionalKeys<T>
    ? [K]
    : Concat<K, Leaves<T[K]>>;
  }[keyof T]
  : [];

type DeepRequired<T, P extends Leaves<T>> = T extends object
  ? Omit<T, Extract<keyof T, P[0]>> &
  Required<
    {
                                     // Shift did not satisfied constraint, so I added condition
      [K in Extract<keyof T, P[0]>]: Shift<P> extends Leaves<T[K]> ? DeepRequired<T[K], Shift<P>> : never
    }
  >
  : T;

type Person = {
  name: string;
  father?: Person;
  mother?: Person;
  siblings?: Person[];
  contact: {
    email: string;
  };
  created_at: Date;
};

type PersonLeaves = Leaves<Person>;

type PersonWithParents = DeepRequired<Person, ["father" | "mother"]>;

type PersonWithFatherSiblings = DeepRequired<DeepRequired<Person, ["father"]>, ["father", "siblings"]>;