javascript - 为什么流无法在这个函数式 Either 示例中更准确地确定类型?

标签 javascript flowtype

我有一些代码可以处理一些功能性的 javascript 概念,例如 Brian Lonsdorf 在 this series 中提出的 Eithers。 .

我一直在尝试输入 Either 表达式。这是我的尝试:

type RightApi<X> = {
  map: <C: *>(f: X => C) => RightApi<C>,
  fold: <C: *>(f: Function, g: X => C) => C
};

const Right = <X: *>(x: X): RightApi<X> => ({
  map: f => Right(f(x)),
  fold: (f, g) => g(x),
})

type LeftApi<X> = {
  map: (f: Function) => LeftApi<X>,
  fold: <C: *>(f: X => C, g: Function) => C,
};

const Left = <X: *>(x: X): LeftApi<X> => ({
  map: f => Left(x),
  fold: (f, g) => f(x),
});

const fromMayBeNullOrUndefined = <X: *>(x: X) =>
  ((x === null || x === undefined) ? Left(x) : Right(x));

const test = fromMayBeNullOrUndefined(3).fold(x => null, x => x);
// null | number

link

不幸的是,这并没有让我达到我想要的程度。在最后一行,我尝试测试打字。从逻辑上讲,我很清楚 test 将是一个 number。因为提供给fromMayBeNullOrUndefined的值是3,即不为null或undefined,所以调用fold时,应该调用右边的函数.

我是不是弄错了?还是flow无法更精确地推断出结果?

最佳答案

您提到的问题可以通过为 fromMaybeOrUndefined 函数定义不同的类型签名来解决,如下所示:

declare function fromMayBeNullOrUndefined(x: null | void): LeftApi<null | void>;
declare function fromMayBeNullOrUndefined<X>(x: X): RightApi<X>;
function fromMayBeNullOrUndefined<X>(x: X) {
  if (x === null || x === undefined) {
    return Left(x);
  }
  return Right(x);
}

现在测试正确的类型检查:

const test: null = fromMayBeNullOrUndefined(null).fold(x => null, x => x);

const test: number = fromMayBeNullOrUndefined(3).fold(x => null, x => x);

但是虽然这是一个有趣的练习,但它完全忽略了Either类型的要点:

Either 的要点是 LeftRight 具有相同的 API,因此在运行时底层值(或通常称为数据)可以是它们的之一。值是 Left 还是 Right 是透明的。这很重要,因为当存在某种可能产生两个结果的外部影响时,您将使用 Either 类型(或任何类型的 Monad)。例如,您想要连接到数据库 - 连接可能被创建或失败。或者在您的情况下,某些 API 的用户可能会提供一个数字或一个空值。

/* @flow */
type Either<L, R> = {
  map: <T>(f: R => T) => Either<L, T>,
  fold: <T>(f: L => T, g: R => T) => T
};

const Right = <R>(x: R): Either<any, R> => ({
  map: <T>(f: R => T): Either<any, T> => Right(f(x)),
  fold: <T>(f: any => T, g: R => T): T => g(x),
})

const Left = <L>(x: L): Either<L, any> => ({
  map: <T>(f: any => T): Either<any, T> => Left(x),
  fold: <T>(f: L => T, g: any => T): T => f(x),
});

const fromMayBeNullOrUndefined = <X>(x: X): Either<null | void, X> =>
  ((x === null || x === undefined) ? Left(x) : Right(x));

const test = fromMayBeNullOrUndefined(3).fold(x => null, x => x);
(test: null | number)

使用 Either,您可以继续在“快乐路径”(右侧)中编码,直到您想要将执行路径折叠起来。示例:

function getAccountBalance(name: string): string {
  const account: Either<Error, Account> = getAccountByCustomerName(name);

  return account
    .map(account => account.balance)
    .fold(
      () => "Seems like you don't have an account at our service",
      balance => `Your balance is ${balance}`,
    );
}

如下一个视频讲座中所述,当发生多个操作时,此示例将变得更加有趣。

关于javascript - 为什么流无法在这个函数式 Either 示例中更准确地确定类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52191899/

相关文章:

javascript - 流动。调用方法 `append` 。对象字面量错误

javascript - 自定义流类型定义显然没有被读取

flowtype - 如何将 flowtype 与 spacemacs 集成

javascript - 如何使用testace作为框架在小 cucumber cucumber 中截屏?

javascript - Html Canvas 调整大小和坐标空间

JavaScript 函数被触发?

javascript - 单击 li 项时 Jquery 更改 div 文本值

javascript - 具有多个固定行和列的 HTML 表格

javascript - 如何使用 Flow 定义用于 react 导航的 Prop

javascript - 使用 FlowType 进行 native react : Exporting and importing js interfaces