如何编写用于返回给定输入或输入中包含的成员的TypeScript方法的返回类型?

时间:2020-05-09 17:51:29

标签: typescript typescript-generics

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

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不是{ {1}},因此Container应该只键入本身,ContainedTypeOrItself<T>。显然,鉴于编译器错误,我对这应该如何工作的理解是不正确的。

在我的另一个related question中,我了解了为什么不小心使用T而使用三元运算符会导致与使用any语句时产生不同的行为。但是,我仍然认为我太精打细算,无法理解代码的实际问题,并且已经多次阅读注释和答案。他们 did 确切地回答了那里的问题:为什么三元运算符和if-else之间存在不同的行为,对此我深表感谢-正是我所要寻找的。但是,在这个问题上,我使用的是一个简单的示例(谢谢!),并尝试在键入时尽可能具体。即使尝试应用有关if-else用法,三元运算符以及使用该答案中的简化代码的经验教训,我仍然无法解决为什么它不起作用的问题。

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

1 个答案:

答案 0 :(得分:1)

我认为这是过度工程的情况。如果我听不懂,请注意我,我将删除答案。

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

您的类型ContainedTypeOrItself<T>将被描述为像联合一样

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

然后,flat函数看起来像

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);

我想回答的问题看起来比您的代码简单得多,这使我感到怀疑。因此,如果我误解了您的问题,请警告我。