我有一些描述深层对象结构的接口。像这样:
interface IBar {
a: string | null;
b: number | null;
}
interface IBaz {
c: string | null;
d: boolean | null;
}
interface IFoo {
bar: IBar;
baz: IBaz;
}
当前,对于每个属性,我正在使用非空断言运算符,例如obj.bar.a!
。为了避免在需要访问属性的任何地方执行此操作,我想一种方法来创建一个新界面,该界面从“叶”界面中“删除” null
。
换句话说,我想做:
const obj: DoMagic<IFoo> = getObj();
使类型变为:
{
bar: {
a: string;
b: number;
},
baz: {
c: string;
d: boolean;
}
}
到目前为止,我只找到了DeepPartial
的解决方案,我认为这与我所需要的完全相反。 NonNullable
似乎相关,但我想将其应用于根接口,而不是应用于每个叶子。这可能吗?
答案 0 :(得分:3)
可以使用mapped types和NonNullable类型的实用程序。
一个级别深版本:
type NoNullFields<Ob> = { [K in keyof Ob]: NonNullable<Ob[K]> };
type NoNullIBar = NoNullFields<IBar>;
NoNullFields 类型构造函数正在创建一种类型,该类型的键与给定的[K in keyof Ob]
具有相同的键,但是值被null
排除了NonNullable<Ob[K]>
可能性的类型< / p>
递归版本(适用于嵌套结构)
type NoNullFields<Ob> = { [K in keyof Ob]: Ob[K] extends object
? NoNullFields<Ob[K]> : NonNullable<Ob[K]> };
type NoNullIBar = NoNullFields<IBar>;
这部分最重要-Ob[K] extends object ? NoNullFields<Ob[K]> : NonNullable<Ob[K]>
。这意味着如果该字段是一个对象,那么我们将在其上递归使用类型构造函数,如果不是,则将字段设置为NonNullable。