【问题标题】:Typescript - return type conditionsTypescript - 返回类型条件
【发布时间】:2021-02-23 10:24:19
【问题描述】:

这个问题的重点是 React 中 Typescript 的使用。

我有两个 React 钩子:useStatus(): StatususeResult(): Result | null,并像这样使用它们:

const status = useStatus();
const result = useResult();

if (status !== "success") {
  return <Loading />;
}

return ... something using result ...;

我可以更改两个函数的签名(参数和返回类型)。 我无法更改 useResult 调用的位置(它必须在 if 之前) - 这是 React 的唯一限制。

从概念上讲,如果status"success",我知道result 不会是null。我想以某种方式将此信息编码为返回类型。这样一来,Typescript 就会在最后一行知道 status"success" 所以 resultResult(不是 Result | null)。

我知道我可以将两个不同的组件分开 - 这就是我已经在做的事情,但我很好奇我是否可以避免这种情况。

有没有办法做到这一点?

谢谢! :)

【问题讨论】:

  • 为什么不把两个钩子合二为一呢?
  • 在这里你可以找到一些关于在 React catchts.com/unions 中处理联合的信息
  • 只是想发表与上述相同的评论。如果您需要付出额外的努力来整理您的类型,那么代码很可能存在一些概念问题。在这种情况下,如果我理解正确的话,有两个单独的钩子从同一来源传递数据。您只需要将这些钩子合二为一。

标签: reactjs typescript react-hooks


【解决方案1】:

第一个重构可能是将这两个钩子的处理提取到具有自己返回类型的专用钩子中。

之后,您可能(如果可能)遵循 cmets 中的建议,将 useStatususeResult do 直接移动到新的钩子中。

例如:

// mock types
type Status = 'loaded' | 'loading';
type Result = unknown;

// hooks per your description
declare function useStatus(): Status;
declare function useResult(): Result | null;

// new type
// ref: https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions
type Response =
  | { status: 'loaded'; result: Result; }
  | { status: 'no-result'; }
  | { status: 'loading'; };

// new hook
const useResponse = (): Response => {
  const status = useStatus();
  const result = useResult();

  if ('loaded' === status) {
    return null === result
      ? {status: 'no-result'}
      : {status, result};
  }

  return {status: 'loading'};
};

使用这个钩子可以让你轻松访问它的返回属性:

const App: React.FC = () => {
  const response = useResponse();

  switch (response.status) {
    case 'loading':
      return <div>Loading</div>;

    case 'no-result':
      return <div>Failure...</div>;

    case 'loaded':
      return <WithResult result={response.result}/>;
  }
};

参考:https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions

【讨论】:

  • tnx!我只是好奇,有没有办法使这项工作: const { status, result } = useResponse();
  • @MatijaFolnovic 可能是的,但我认为这有点不干净。您需要将result: null | undefined(或您想要的任何其他回退类型)添加到每个没有结果的响应类型(例如| { status: 'no-result'; result: null; }。此外,在useResponse 中创建响应时,您需要确保包括此默认值(例如? {status: 'no-result'; result: null;})。另一种选择是在使用钩子时提供默认值,例如const {status, result} = {result: null, ...useResponse()};
猜你喜欢
  • 1970-01-01
  • 2021-01-03
  • 2020-10-27
  • 1970-01-01
  • 2019-04-09
  • 1970-01-01
  • 2021-10-17
  • 2018-12-28
  • 1970-01-01
相关资源
最近更新 更多