如何使用点符号排除对象的某些关键点?

我想编写一个ValueOrStringExcludeNestedKeys<T, K>类型,将string类型递归地添加到任何基元类型属性或子属性中,excludingK中指定的路径并集处的任何属性递归地添加到应该不受影响的位置.

例如:

type Values = {
  a: {
    b: {
      c: string;
      d: number;
    };
    e: string;
  };
  f: number;
  g: number;
  h: {
    i: number;
  }
};

type Result = ValueOrStringExcludeNestedKeys<Values, 'a.b.c' | 'f'>;
/* type Result = {
    a: {
        b: {
            c: string; // <-- unchanged
            d: number | string;
        };
        e: string; // <-- (string | string is just string)
    };
    f: number; // unchanged
    g: number | string;
    h: {
        i: number | string;
    };
} */

在上面的代码中,a.b.da.ea.gh.i属性都使用| string进行了转换,而a.b.cf属性没有变化.

如何才能做到这一点?

推荐答案

以下是编写递归ValueOrStringExcludeNestedKeys<T, K>的一种方法:

type ValueOrStringExcludeNestedKeys<T, K extends string> =
    T extends object ? { [P in keyof T]:
        P extends K ? T[P] : ValueOrStringExcludeNestedKeys<T[P],
            K extends `${Exclude<P, symbol>}.${infer R}` ? R : never
        > } : T | string;

一种基本情况是,原始(非object)类型T应该成为其自身的unionstring,T | string.

对象类型Tmapped.如果对象键P直接是K的成员,则这是另一种基本情况:我们保留对象属性T[P],并且不对其进行修改.

否则,我们递归并写ValueOrStringExcludeNested<T[P], ⋯>,这里可能很棘手的部分是找出中的内容.我们希望将K的每个以P和一个点开头的联合成员转换为字符串的其余部分.否则,我们想要解雇unions 成员.由于K年的运营率应该是distribute比unions ,我们希望是distributive conditional type.因为我们正在解析字符串,所以我们可以使用template literal types.从概念上讲,它是K extends ${P}.${INFER R} ? R : never.我们知道P可以扩展string | number | symbol,而symbol不能通过模板文字类型进行序列化.所以我们可以用the Exclude utility type而不是P来写Exclude<P, symbol>.


让我们来测试一下:

type Values = {
    a: {
        b: {
            c: string;
            d: number;
        };
        e: string;
    };
    f: number;
    g: number;
    h: {
        i: number;
    }
};

type Result = ValueOrStringExcludeNestedKeys<Values, 'a.b.c' | 'f'>;
/* type Result = {
    a: {
        b: {
            c: string;
            d: string | number;
        };
        e: string;
    };
    f: number;
    g: string | number;
    h: {
        i: string | number;
    };
} */

看上go 不错.除了a.b.cf处的属性外,基元类型的域中添加了string个.

Playground link to code

Typescript相关问答推荐

"@ clerker/nextjs/server没有名为clerkMiddleware的导入成员'

Angular 17 -如何使用新的@if语法在对象中使用Deliverc值

angular 17独立使用多个组件(例如两个组件)

找不到带名称的管道''

从typescript中的对象数组中获取对象的值作为类型'

异步动态生成Playwright测试,显示未找到测试

如何在单击停止录制按钮后停用摄像机?(使用React.js和Reaction-Media-Recorder)

如何推断计算逻辑的类型

向NextAuth会话添加除名称、图像和ID之外的更多详细信息

STypescript 件的标引签名与功能签名的区别

如何在TypeScrip中正确键入元素和事件目标?

用于验证字符串变量的接口成员

基于泛型的条件接口键

TypeScrip:使用Union ToInterval辅助对象,但保留子表达式

缩小对象具有某一类型的任意字段的范围

如何将类似数组的对象(字符串::匹配结果)转换为类型脚本中的数组?

编剧- Select 下拉框

如何创建一个将嵌套类属性的点表示法生成为字符串文字的类型?

组件使用forwardRef类型脚本时传递props

是否可以使用元组中对象的键来映射类型