【问题标题】:Can mapped types make properties optional, but only if a condition is met?映射类型可以使属性成为可选的,但前提是满足条件?
【发布时间】:2021-09-30 04:07:53
【问题描述】:

我正在尝试创建一个映射类型,它采用某种类型的所有属性并使它们成为可选,但保持所有其他属性不变。我知道在定义映射类型时可以使用可选修饰符,如:

type MyPartial<T> = {
  [key in keyof T]?: T[key]
}

但我不确定语法是否允许将其与条件结合使用。我可以非常接近以下内容:

type OptionalArrays<T> = {
  [key in keyof T]: T[key] extends Array<any> ? T[key] | undefined : T[key]
}

interface Example {
  foo: string[];
  bar: number;
};

type Example2 = OptionalArrays<Example>;

问题是这会导致显式的undefineds,而不是隐式的,所以虽然它会在这两种情况下按照我的意愿行事:

const value1: Example2 = {
  foo: [],
  bar: 3,
}

const value2: Example2 = {
  foo: undefined,
  bar: 3,
}

它会给出一个不需要的错误,foo 缺少这个:

const value3: Example2 = {
  bar: 3,
}

是否可以在映射类型中添加可选修饰符(?),但前提是满足特定条件?

Playground link

【问题讨论】:

  • 这似乎是一个经过深思熟虑的问题,但我无法理解该应用程序 - 有没有一种方法可以提供一个不太抽象的例子来说明它试图完成什么?
  • 我有一个预先存在的类型,它有一些属性是数组,有些不是。我正在将这些对象写入不能表示空数组的数据库,因此改用undefineds。因此,我用于读取和写入数据库的代码将使用数组是可选的版本。然后一些简单的代码将用空数组填充这些缺失值,因此客户端代码的其余部分不需要关心。

标签: typescript mapped-types


【解决方案1】:

可能有一种更优雅的方式,但是将两个映射类型相交并不太尴尬。一个用于可选属性,一个用于必需属性。

例如:

type OptionalArrays<T> = {
  [key in keyof T as T[key] extends Array<any> ? key : never]?: T[key]
} & {
  [key in keyof T as T[key] extends Array<any> ? never : key]: T[key]
}

注意映射类型的键部分中的as。这让您可以转换密钥类型。在这种情况下,如果我们想保留它,我们要么使用实际的密钥,要么将它转换为 never

Playground


或者也许这个版本是相似的,但可以说是稍微不那么神秘。

type ArrayKeys<T> = {
    [key in keyof T]: T[key] extends Array<any> ? key : never
}[keyof T]

type OptionalArrays<T> =
    Omit<T, ArrayKeys<T>> & // get one type without array keys
    Partial<Pick<T, ArrayKeys<T>>> // get one type with array keys as optional

Playground

【讨论】:

  • 用类似但可能更容易解析的第二个选项更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
相关资源
最近更新 更多