【问题标题】:Typescript interface with never typed fields从未输入字段的打字稿界面
【发布时间】:2020-07-14 18:47:39
【问题描述】:

给定以下接口,什么是有效的可分配值?

interface A {
  x: number,
  y: never
}

我的预期是 const a: A = { x: 1 } 会起作用,但它错误地说字段 y 是必需的。只要我把y 放在那里,它就会说该值不能分配给never

我的实际用例是这样的:

interface Context<T extends MyRequest> {
  id: string;
  token: T extends AuthenticateRequest ? string : never;
}

interface AuthenticatedRequest extends MyRequest { ... }

这里我无法为Context&lt;MyRequest&gt; 创建一个值,因为它说缺少token

我目前的解决方法是:

type Context<T extends MyRequest> = {
  id: string;
} & (T extends AuthenticatedRequest ? {
  token: string;
} : {})

但由于显而易见的原因,这看起来很丑......

任何想法我如何正确地做到这一点?

【问题讨论】:

  • 我想你可能想用undefined 代替never
  • 具有 never 成员的接口与 never 本身一样好,因为该接口的任何值都不可能存在。您可以改用undefined,但它不会使该属性成为可选的。我认为您当前的解决方法很好,您为什么对此不满意?有什么具体的原因,还是我宁愿它是一个界面?
  • 这个想法是在定义类型的值时不必设置该字段,同时也使界面看起来非常简单(我将添加更多条件字段,因此它会开始看起来很乱)。虽然据我所知,作为解决方法提到的方法是正确的方法,我没有其他选择......

标签: typescript typescript3.8


【解决方案1】:

Type never 是空类型的表示。这是什么意思 - 没有属于这种类型的值,这意味着如果你使用它总是会出现编译错误。

您需要的是更高级别的条件类型,请考虑:

type Context<T extends MyRequest> = T extends AuthenticateRequest ? {
  id: string;
  token: string;
} : { id: string };

这种方法消除了为token 设置undefined 的负担。如果token是必需的,那么T extends AuthenticateRequest是一个字符串,如果不是,则token字段不存在。

【讨论】:

  • 是的,这似乎是有道理的。我将添加更多具有不同 T extends AnotherInterface 条件的字段,因此它会变得混乱,但看起来“解决方法”实际上是正确的方法
  • 我不认为明确设置 undefined 是正确的方法,在 T extends AuthenticateRequest 的情况下不应该考虑这种状态。如果我们进入 - 使不可能的状态成为不可能,那么我所写的是正确的方法。
  • 我不确定你的意思,因为我没有使用 undefined。我已经把我的最终版本作为一个单独的答案。
【解决方案2】:

您需要将类型设置为字符串或未定义。当变量永远不会被赋值时使用never 类型,更多关于here

我认为这种方法应该可以解决您的问题。

interface A {
  x: number,
  y: string | undefined
}

【讨论】:

    【解决方案3】:

    根据@Titian Cernicova-Dragomir 和@Maciej Sikora 提到的几点,解决方法是我需要的类型定义的正确方法。 interface 不能有 never 类型的字段,因为它不能被分配一个有效的值,从而使接口无用。

    这是我最终用于我的代码的内容:

    type Context<T extends MyRequest> = Readonly<
      {
        logger: MyLogger;
        timestamp?: number;
      } & (T extends AuthenticatedRequest
        ? {
            token: Token;
            user: string;
          }
        : {}) &
        (T extends GameRequest
          ? {
              gameId: string;
            }
          : {}) &
        (T extends ETagRequest
          ? {
              etag: string;
            }
          : {}) &
        (T extends UnParameterizedRequest
          ? {}
          : {
              params: Record<string, string | undefined>;
            })
    >;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-21
      • 1970-01-01
      • 2018-02-04
      • 2021-12-04
      • 1970-01-01
      • 2017-03-24
      • 1970-01-01
      相关资源
      最近更新 更多