打字稿深省略点符号

Typescript deep omit with dot notation

由于 TypeScript 现在支持模板字面量类型,是否可以使用类似下面的内容?

interface Data {
  a: number;
  b: {
    c: number;
    d: number;
  }
}

type OmitDeep<T, K> = ...

type WithoutC = OmitDeep<Data, 'b.c'>

其中 WithoutC 将被推断为:

interface WithoutC {
  a: number;
  b: {
   d: number
  }
}

您可以使用此类型将点路径映射到数组路径:

type UnDot<T extends string> =
    T extends `${infer A}.${infer B}` ? [A, B] : ''

type ProperyArray = UnDot<'a.b'>; // ["a", "b"]

然后使用此答案删除嵌套属性:

编辑任意数量的嵌套级别:

type UnDot<T extends string> =
    T extends `${infer A}.${infer B}`
    ? [A, ...UnDot<B>]
    : [T];

除了 Roberto 的精彩回答外,完整的解决方案如下所示:

type Tail<T extends any[]> = ((...t: T) => void) extends ((
    h: any,
    ...r: infer R
) => void)
    ? R
    : never;

type DeepOmit<T, Path extends string[]> = T extends object ?
    Path['length'] extends 1 ? Omit<T, Path[0]> : {
        [K in keyof T]: K extends Path[0] ? DeepOmit<T[K], Tail<Path>> : T[K];
    } : T;

type UnDot<T extends string> =
    T extends `${infer A}.${infer B}`
    ? [A, ...UnDot<B>]
    : [T];

type Nested = {
    a: number;
    b: {
        c: number;
        d: number;
    }
};

type Omitted =  DeepOmit<Nested, UnDot<'b.c'>>

const foo: Omitted = {a: 1, b: { c: 1, d: 2 } }; // error
                                 ~~~~

Typescript playground