如何仅对可为空的字段制作“ Partial <T>”?

rec*_*bot 3 typescript

我需要一个Partial<T>类似的映射类型,使我可以将可空字段设为可选。我正在输入ORM,它在可为空的字段上将undefined强制为null。

我想采取一种

interface User {
  email: string
  name: string | null
}
Run Code Online (Sandbox Code Playgroud)

和做

interface User {
  email: string
  name?: string | null
}
Run Code Online (Sandbox Code Playgroud)

我试过了

type NullablePartial<T> = { [P in keyof T]: T[P] extends null ? T[P] | undefined : T[P] }
Run Code Online (Sandbox Code Playgroud)

但是extends null不适用于null和的另一种类型的联合(我理想上希望它可以与字符串一起使用)。可选字段和未定义值之间的区别很重要。

我能做什么?

Kar*_*ski 10

让我们首先查找哪些属性可为空。

type NullablePropertyOf<T> = {
  [K in keyof T]: null extends T[K]
    ? K
    : never
}[keyof T]
Run Code Online (Sandbox Code Playgroud)

我们需要修改可为 null 的属性,但保持其余属性不受影响。为了在我们的转换中忽略不可空的,我们将需要众所周知的Omit助手。

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
Run Code Online (Sandbox Code Playgroud)

我们的最终产品是通过将整体的T部分版本与应该不受影响的属性合并而创建的。

type NullablePartial<T> = Partial<T> & Omit<T, NullablePropertyOf<T>>;
Run Code Online (Sandbox Code Playgroud)

当然,有不止一种方法可以做到这一点。在此示例中,我对所有内容进行可选化要求所需内容。您可以采取相反的方法:首先选择不可为空的字段,然后选择可为空的字段,然后合并两种类型。无论你适合什么。


jca*_*alz 6

在TypeScript中,使类型函数仅将某些属性变为可选或非可选实际上是很烦人的,因为没有简单的方法来描述它。我想到的最简单的方法是使用带有交集的多个映射类型。只要您传入的类型没有索引签名(这会变得更加复杂),这应该可以工作:

type NullablePartial<
  T,
  NK extends keyof T = { [K in keyof T]: null extends T[K] ? K : never }[keyof T],
  NP = Partial<Pick<T, NK>> & Pick<T, Exclude<keyof T, NK>>
> = { [K in keyof NP]: NP[K] }
Run Code Online (Sandbox Code Playgroud)

请注意,我使用PickExclude瓜分T成空的属性和非空的属性,做不同的事情,他们每个人,然后交叉他们重新走到一起。确定可为空的属性与检查是否null extends T[K](即“我可以分配null给该属性”)有关,而不是与之相反(即“我可以将此属性分配给类型为变量的变量”)null ”)。

我还使用通用参数默认值来简化类型操作(因此,我只需确定一次可为空的属性键名称即可)NP),并使最终输出类型在美学上更为令人满意(最后通过执行一种最终的映射类型)我得到一个不表示为交集的类型。

让我们试一下:

interface User {
  email: string
  name: string | null
}

type NPUser = NullablePartial<User>;
// type NPUser = {
//  name?: string | null | undefined;
//  email: string;
// }
Run Code Online (Sandbox Code Playgroud)

在我看来合理...这接近您想要的吗?祝好运。