我怎样才能使Partial <t>只针对可空字段?

时间:2019-02-15 16:21:59

标签: typescript

我需要像Partial<T>这样的映射类型,该类型允许我将可空字段设为可选。我正在输入ORM,它在可为空的字段上将undefined强制为null。

我想选择一种

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

然后

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

我尝试了

type NullablePartial<T> = { [P in keyof T]: T[P] extends null ? T[P] | undefined : T[P] }

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

我该怎么办?

3 个答案:

答案 0 :(得分:5)

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

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] }

请注意,我正在使用PickExcludeT分为可空属性和不可空属性,分别对它们进行不同的处理,然后将它们相交重新走到一起。确定可为空的属性与检查是否null extends T[K](即“我可以将null分配给该属性”)有关,而不是相反(即“我可以将此属性分配给类型为{的变量) {1}}”)。

我还使用generic parameter defaults来简化类型的操作(因此,我只需一次将可空属性键名称确定为null即可),并使最终输出类型在美学上更令人愉悦(通过在最后执行一个最终的映射类型,我得到了一种不表示为交集的类型。)

让我们尝试一下:

NP

对我来说合理...接近您想要的吗?祝你好运。

答案 1 :(得分:1)

让我们从查找哪些属性可以为空开始。

type NullablePropertyOf<T> = {
  [K in keyof T]: null extends T[K]
    ? K
    : never
}[keyof T]

我们需要修改可为空的属性,但其余部分不受影响。为了在我们的转换中忽略不可为空的变量,我们将需要著名的Omit助手。

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

我们的最终产品是通过合并整个T weak (部分)版本和应该保持不受影响的属性而创建的。

type NullablePartial<T> = Partial<T> & Omit<T, NullablePropertyOf<T>>;

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

答案 2 :(得分:0)

我想我不确定这与使用可选接口属性之间的区别。

类似的东西:

export interface foo {
   bar?: string;    // nullable
   baz: string;
   bat: boolean;
   etcd?: boolean;  // nullable
}

在您的情况下不行吗?