【问题标题】:Typescript conditionally make certain properties optional打字稿有条件地使某些属性可选
【发布时间】:2022-12-18 04:50:30
【问题描述】:

我目前正在尝试创建一个实用程序类型来解包 sniptt monads 选项。到目前为止,这是我的代码:

export interface Option<T> {
  type: symbol;
  isSome(): boolean;
  isNone(): boolean;
  match<U>(fn: Match<T, U>): U;
  map<U>(fn: (val: T) => U): Option<U>;
  andThen<U>(fn: (val: T) => Option<U>): Option<U>;
  or<U>(optb: Option<U>): Option<T | U>;
  and<U>(optb: Option<U>): Option<U>;
  unwrapOr(def: T): T;
  unwrap(): T | never;
}

export type UnwrappedOptionsType<T> = T extends (infer U)[]
  ? UnwrappedOptionsType<U>[]
  : T extends object
  ? {
      [P in keyof T]: T[P] extends Option<infer R>
        ? UnwrappedOptionsType<R> | undefined
        : UnwrappedOptionsType<T[P]>;
    }
  : T;

我期望发生的是类型被推断出来并且选项属性是可选的。假设我有以下类型:

type SignUpRequest = {
    username: string;
    password: string;
    email: Option<string>;
}

当我使用 UnwrappedOptionsType&lt;SignUpRequest&gt; 时,我希望得到以下类型:

{
    username: string;
    password: string;
    email?: string | undefined;
}

我得到的是:

{
    username: string;
    password: string;
    email: string;
}

它能够成功地推断出选项的类型,但它从来没有做到这一点,所以它也接受undefined。如何使选项可选?

编辑:更改代码以使示例可重现。此外,我特别希望属性是可选的,而不仅仅是可能未定义。

【问题讨论】:

  • 什么是“sniptt monads 选项”?您能否edit 代码使其成为不依赖于任何第三方代码的独立minimal reproducible example?这样我们就可以将它粘贴到一个独立的 IDE 中,查看问题,并希望修复它。另请注意,在{x: string | undefined}中,x不是可选的,它是必需的,但允许为undefined。你关心可选的(比如{x?: string})吗?或者是 required-but-could-be-undefined 对你来说足够好了吗?
  • @jcalz 我更新了问题。
  • 大概您关心嵌套属性;你能更新你的例子来展示你想在那里发生什么吗?另外,工会呢? {x: string | Option&lt;number&gt;}应该变成{x: string | number | undefined}{x?: string | number}{x: string} | {x?: number}还是其他什么?
  • 我的意思是,this approach 是我在这里的倾向,但我不知道它是否像您希望的那样处理边缘情况。我们应该如何着手?
  • @jcalz 这对我来说非常有用。如果您发布它,我会接受它作为答案。

标签: typescript


【解决方案1】:

您将需要向您的 UnwrappedOptionsType 类型添加一个额外的类型保护以使该选项可选:

type UnwrappedOptionsType<T> = T extends (infer U)[]
  ? UnwrappedOptionsType<U>[]
  : T extends object
  ? {
      [P in keyof T]: T[P] extends Option<infer R>
        ? (UnwrappedOptionsType<R> | undefined) | undefined
        : UnwrappedOptionsType<T[P]>;
    }
  : T;

添加类型保护后,SignUpRequest 类型的 UnwrappedOptionsType 将是:

type UnwrappedOptionsType<SignUpRequest> = {
    username: string;
    password: string;
    email?: (string | undefined) | undefined;
}

输出将如下所示:

{
    username: string;
    password: string;
    email?: string | undefined;
}

那是你要追求的吗?

【讨论】:

    猜你喜欢
    • 2016-11-01
    • 2019-04-18
    • 2018-06-05
    • 2019-12-22
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    相关资源
    最近更新 更多