0

对于返回的不同值,我有两个验证函数Either。如果其中一个有值,我想抛出一个异常,left如果两者都是right. 我以前从未使用过 fp-ts 并且无法弄清楚如何正确组合左侧结果。我当前的解决方案有效,但感觉我没有正确使用它。

import { Either, left, right, isLeft, getOrElse } from 'fp-ts/lib/Either';

function validateMonth( m: Month ): Either<Error, Month> {
   return m.isInRange() ? right(m) : left(new Error('Month must be in range!'));
}

function validateYear( y: Year ): Either<Error, Year> {
   return year.isBefore(2038) ? right(y) : left(new Error('Year must be before 2038!'));
}

function throwingValidator(m: Month, y: Year): void {
 // todo: Refactor to get rid of intermediate variables,
 // combining results of validateMonth and validateYear into a type
 // of Either<Error, Unit>
 const monthResult = validateMonth( month );
 const yearResult = validateYear( year );
 const throwOnError = (e: Error) => { throw e; };
 if ( isLeft( monthResult ) ) { getOrElse(throwOnError)(monthResult); }
 if ( isLeft( yearResult ) ) { getOrElse(throwOnError)(yearResult); }
}

我已经阅读了https://dev.to/gcanti/getting-started-with-fp-ts-either-vs-validation-5eja的介绍,但该代码与我想要的完全相反:我不关心验证后的输入值,并且只想返回发生的第一个错误。

4

2 回答 2

2

忽略throwingValidator和抛出一般(哪种破坏了fp-ts首先使用的目的)并且只关注这个特定的请求:

重构去掉中间变量,将 validateMonth 和 validateYear 的结果组合成一个 Either 类型

您可能正在寻找:

const monthAndYearResult: Either<
  Error,
  { month: Month, year: Year }
> = sequenceS(either)({
  month: validateMonth(month),
  year: validateYear(year)
})

“序列”通常需要(在这种情况下Traversable为结构{ year, month })的实例和Applicativeeither在这种情况下)的实例,并且语义是将不同的独立计算聚合在一起的语义。

如果您明确想要忽略结果,通常会_提供一个 -suffix 替代方案来完成此操作,但目前在fp-tsv2 中还没有。

要获得一个Either<Error, void>,您可以求助于:

const result = pipe(
  sequenceS(E.either)({ month: validateMonth(month), year: validateYear(year) }),
  E.map(constVoid)
)

请注意,这sequenceS只是可能的选项之一,您可以使用sequenceTarray.sequence获得类似的结果,例如:

pipe(
  sequenceT(either)([validateMonth(month), validateYear(year)]),
  E.map(constVoid)
)
于 2019-09-23T09:30:41.517 回答
2

您可能正在寻找类似的东西

const toPromise = fold(e => Promise.reject(e), r => Promise.resolve(r));

Promise.all([
    toPromise(validateMonth(month)),
    toPromise(validateYear(year)),
]).then(([validMonth, validYear]) => {
    return …
});

或更实用的方式

toPromise(ap(ap(of(validMonth => validYear => {
    return …
}), validateMonth(month)), validateYear(year)))

你也可以做Promise.allwitharray.sequencetoPromiseafter。

于 2019-09-18T22:02:04.460 回答