打字稿 - 返回类型条件

时间:2021-02-23 10:24:19

标签: reactjs typescript react-hooks

这个问题的重点是 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 的唯一约束。

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

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

有没有办法做到这一点?

谢谢! :)

1 个答案:

答案 0 :(得分:1)

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

之后您可能(如果可能)遵循评论中的建议,将任何 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