【问题标题】:How does one write the return type for a TypeScript method which either returns a given input or a member contained in the input?如何为返回给定输入或输入中包含的成员的 TypeScript 方法编写返回类型?
【发布时间】:2020-08-25 07:31:36
【问题描述】:

如果我有一个函数将返回提供的值(如果它不是容器)或容器内的值(如果提供的值容器),我该如何正确声明该函数的返回类型?例如:

interface Container<TValue> {
  value: TValue;
}

declare function isContainer<TContained>(
  object: unknown
): object is Container<TContained>;

type ContainedTypeOrItself<T> = T extends Container<infer U> ? U : T

function getContainedValueOrSelf<T>(
  input: T,
): ContainedTypeOrItself<T> {
  if (isContainer<ContainedTypeOrItself<T>>(input)) {
    return input.value
  }

  return input
}

这种方法似乎不起作用,因为 TypeScript 编译器为 return input 语句引发了错误:

Type 'T' is not assignable to type 'ContainedTypeOrItself<T>'.

由于我相信if 子句过滤了所有Container 类型的对象,我认为当代码到达return input 语句时,T 不是Container,所以ContainedTypeOrItself&lt;T&gt; 应该只需输入自己,T。显然,鉴于编译器错误,我对这应该如何工作的理解是不正确的。

在我的另一个 related question 中,我了解到为什么使用三元运算符和不小心使用 any 会导致与使用 if-else 语句时不同的行为。但是,我仍然认为我太密集了,无法理解代码实际上有什么问题,而且我已经阅读了 cmets 并多次回答。他们确实准确地回答了那里提出的问题:为什么三元运算符和if-else 之间存在不同的行为,对此我很感激——这正是我所寻找的。但是,在这个问题中,我使用了一个更简单的示例(谢谢!),并试图在打字时尽可能具体。即使尝试应用有关 any 用法、三元运算符和使用该答案中的简化代码的经验教训,我仍然无法弄清楚它为什么不起作用。

感谢您抽出宝贵时间阅读本文并提供帮助!

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    我认为这是一个过度设计的案例。如果我没有正确理解,请注意我,我将删除我的答案。

    为什么我认为您的代码比它试图解决的问题复杂得多?
    如果您的意图是扁平化包含的对象,扁平化函数的返回类型应始终为 raw 类型,T
    使用infer 关键字会使您的解决方案复杂化,因此如果要实现的目标是获取平面对象T,请不要尝试返回T 以外的任何其他类型。

    您的类型 ContainedTypeOrItself&lt;T&gt; 将被描述为 union like

    type ContainedTypeOrItself<T> = Container<T> | T;
    

    那么,平面函数应该是这样的

    const getContainedValueOrSelf = <T>(input: ContainedTypeOrItself<T>): T =>
      isContainer<T>(input)
      ? input.value
      : input;
    

    是的,三元运算得到了广泛的支持,编译器完全理解。

    几行显示扁平行为

    const container: Container<number> = { value: 6 };
    
    const decontained: number = getContainedValueOrSelf(container);
    const raw: number = getContainedValueOrSelf(6);
    

    我想回答的内容看起来比您的代码简单得多,这让我感到怀疑。所以,如果我误解了你的问题,请警告我。

    【讨论】:

    • 这很完美,绝对可以解决问题。感谢您抽出宝贵时间阅读和回复!你的解决方案显然比我的简单。我想我仍然对为什么我的不起作用(可能过于复杂)还有剩余的好奇心——至少在我的脑海里这在理论上是正确的,但是?
    • 好吧,在您的示例中,您可以强制转换 return input as ContainedTypeOrItself&lt;T&gt;; 并实现 isContainer&lt;TContained&gt; 函数,如 return !!input.value(只要 T 没有 value 键)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-28
    • 1970-01-01
    相关资源
    最近更新 更多