【问题标题】:How to copy the structure of one generic type (nested object) to another generic in TypeScript?如何将一个泛型类型(嵌套对象)的结构复制到 TypeScript 中的另一个泛型?
【发布时间】:2021-09-08 01:31:59
【问题描述】:

这个问题和我之前做的一个很相似。

我建议先阅读我之前的问题:How to copy the structure of one generic type to another generic in TypeScript?


我希望克隆嵌套对象类型的结构,而不是克隆平面对象类型的结构。

换句话说,我正在寻找一个函数,给定......

// ...this input type

interface NestedInput {
  name: string;
  arr: [
    string,
    Date,
    {a: boolean}
  ];
  nestedObject: {
    x: number;
    y: number;
  };
}

// ...it produces this output type

type StringMethod = (val: string) => void;
type DateMethod = (val: Date) => void;
type NumMethod = (val: number) => void;
type BoolMethod = (val: boolean) => void;

interface NestedOutput {
  name: StringMethod;
  arr: [
    StringMethod,
    DateMethod,
    {
      a: BoolMethod;
    }
  ];
  nestedObject: {
    x: NumberMethod;
    y: NumberMethod;
  }
}

再次强调,它必须是完全类型安全的,这样我才能使用智能感知访问 output.nestedObject.xoutput.arr[2].a

过去 2 天我一直在绞尽脑汁想弄清楚这一点,所以任何帮助都将不胜感激!


PS:您可能已经注意到,我们遇到了定义何时遍历嵌套对象的问题。例如,不会遍历 Date 对象,但可能会遍历其他一些结构。为了防止这成为一个问题,你可以假设如果对象是一个普通的 JS 对象(见下面的函数),那么遍历是可以的。

const getClass: (object: any) => string = Function.prototype.call.bind(Object.prototype.toString);

const isVanillaObject = (obj: any) => {
    return getClass(obj) === "[object Object]";
}

【问题讨论】:

  • “例如不会遍历 Date 对象”:我的评论与问题没有直接关系,但通常(IMO)集合更适合动态键值对。其他属性与键完全分开,因此您不必担心确定是否要遍历对象,或者要遍历哪些属性。话虽如此,集合并不好用,因为它们没有方括号符号等。
  • 您的函数isVanillaObject 是运行时代码,并且(据我所知)在类型系统中不可用。此函数必须转换为等效的模板(我不知道这可能或不可能)

标签: javascript typescript typescript-generics


【解决方案1】:

您可以使用extends 来打开类型、对象情况的映射类型并使用递归来允许深度嵌套:

interface NestedInput {
  name: string;
  arr: [string, Date, { a: boolean }];
  nestedObject: {
    x: number;
    y: number;
  };
}

type StringMethod = (val: string) => void;
type DateMethod = (val: Date) => void;
type NumMethod = (val: number) => void;
type BoolMethod = (val: boolean) => void;

type Methodify<T> = T extends string
  ? StringMethod
  : T extends Date
  ? DateMethod
  : T extends number
  ? NumMethod
  : T extends boolean
  ? BoolMethod
  : {
      [K in keyof T]: Methodify<T[K]>;
    };

type Output = Methodify<NestedInput>;

//Results in:
type Output = {
    name: StringMethod;
    arr: [StringMethod, DateMethod, {
        a: BoolMethod;
    }];
    nestedObject: {
        x: NumMethod;
        y: NumMethod;
    };
}

【讨论】:

  • 这太棒了!但是是否可以修改 Methodify 以允许遍历数组?
  • 它已经适用于元组和数组。如果您想要更多控制权,只需添加 extends Array 案例。
  • 数组 case 是否会产生一个带有数值的 'length' 键?
  • 您必须手动处理。例如。仅映射数字键
猜你喜欢
  • 2021-09-07
  • 2020-11-05
  • 2021-06-09
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-02
  • 2020-12-05
相关资源
最近更新 更多