从接口属性中删除 null

Chr*_*ris 7 typescript

我有一些描述深层对象结构的接口。就像是:

interface IBar {
  a: string | null;
  b: number | null;
}

interface IBaz {
  c: string | null;
  d: boolean | null;
}

interface IFoo {
  bar: IBar;
  baz: IBaz;
}
Run Code Online (Sandbox Code Playgroud)

目前,对于每个属性,我使用非空断言运算符,例如obj.bar.a!. 为了避免在需要访问属性的任何地方都这样做,我想要一种方法来创建一个新接口,null从“叶”接口中“删除”。

换句话说,我想做:

const obj: DoMagic<IFoo> = getObj();
Run Code Online (Sandbox Code Playgroud)

这样类型就变成:

{
  bar: {
    a: string;
    b: number;
  },
  baz: {
    c: string;
    d: boolean;
  }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我只找到了与DeepPartial我需要的完全相反的解决方案。NonNullable似乎相关,但我想将其应用于根接口,而不是每个叶子。这可以吗?

Mac*_*ora 10

通过使用映射类型NonNullable类型实用程序可以实现这一点。

一级深版本:

type NoNullFields<Ob> = { [K in keyof Ob]: NonNullable<Ob[K]> };
type NoNullIBar = NoNullFields<IBar>;
Run Code Online (Sandbox Code Playgroud)

NoNullFields类型构造函数正在创建一种类型,该类型具有与给定类型相同的键,[K in keyof Ob]但值具有排除null可能性的类型NonNullable<Ob[K]>


递归版本(适用于嵌套结构):

type NoNullFields<Ob> = { [K in keyof Ob]: Ob[K] extends object 
? NoNullFields<Ob[K]> : NonNullable<Ob[K]> };
type NoNullIBar = NoNullFields<IBar>;
Run Code Online (Sandbox Code Playgroud)

最重要的是这一部分—— Ob[K] extends object ? NoNullFields<Ob[K]> : NonNullable<Ob[K]>。这意味着如果该字段是一个对象,那么我们将递归地使用它的类型构造函数,如果不是,我们将字段设置为 NonNullable。