【问题标题】:Validating ISO-8061 dates with the Decoder approach使用解码器方法验证 ISO-8061 日期
【发布时间】:2021-09-08 13:02:11
【问题描述】:

为了简单的使用,使用io-ts的解码器方法一直运行良好:

import { isRight } from 'fp-ts/Either';
import * as D from 'io-ts/Decoder';

const thing = D.struct({
  id: D.number,
  createdAt: D.string,
});

export const isValidThing = (candidate: unknown): boolean =>
  isRight(thing.decode(candidate));

但是,现在我想更彻底地验证日期。我中途希望能够做这样的事情:

import { DateFromISOString } from 'io-ts-types/lib/DateFromISOString';

const thing = D.struct({
  id: D.number,
  createdAt: DateFromISOString
});

当然,这并不容易:

ERROR: src/middleware/validators/event.ts:7:3 - error TS2322: Type 'DateFromISOStringC' is not assignable to type 'Decoder<unknown, Date>'.
  The types returned by 'decode(...)' are incompatible between these types.
    Type 'Validation<Date>' is not assignable to type 'Either<DecodeError, Date>'.
      Type 'Left<Errors>' is not assignable to type 'Either<DecodeError, Date>'.
        Type 'Left<Errors>' is not assignable to type 'Left<DecodeError>'.
          Type 'Errors' is not assignable to type 'DecodeError'.
            Type 'ValidationError[]' is missing the following properties from type 'Concat<DecodeError<string>>': _tag, left, right

    createdAt: DateFromISOString

显然,我误解了。是否有使用解码器和struct 进行日期验证的简单路径?

编辑:值得注意的是,这确实适用于较旧的非实验方法:

import * as t from 'io-ts';
import { DateFromISOString } from 'io-ts-types';

const thing = t.type({
  id: t.number,
  createdAt: DateFromISOString
});

【问题讨论】:

    标签: typescript fp-ts


    【解决方案1】:

    我会回答这个记录,如果有人有更好的方法(也许使用.asDecoder(),我一直无法完全正确),那么我很乐意接受那个代替。

    定义一个新的Decoder 似乎大致符合我的预期:

    const ISODateTime: D.Decoder<unknown, Date> = pipe(
      D.string,
      D.parse((s) => {
        const d = new Date(s);
        return isNaN(d.getTime())
          ? D.failure(s, 'not a valid date format')
          : D.success(d);
      })
    );
    
    const thing = D.struct({
      id: D.number,
      createdAt: ISODateTime
    });
    
    assert(
      isRight(
        thing.decode({
          id: 1,
          createdAt: '2021-06-26T01:39:06.693Z'
        })
      )
    ); // true
    assert(
      isRight(
        thing.decode({
          id: 1,
          createdAt: 'x1'
        })
      )
    ); // false
    

    当然,它并不能明确证明传入的字符串是 ISO-8061 格式,因为 Date.parse 是相当宽松的。

    【讨论】:

    • 对您的解决方案的一个改进是结合现有的解码器(如D.string)来构建您的日期解码器,而不是自己重新实现字符串解码逻辑。这可以通过pipe(D.string, D.parse(str =&gt; ...)) 完成。请参阅此处的示例 - github.com/gcanti/io-ts/blob/master/…
    • 我知道一定有办法做到这一点!我会编辑的,你。
    • 虽然,如何提供具体的错误信息?我假设withMessage 可以以某种方式被利用......
    • 您可以将解码器名称传递给D.failure,它将出现在 io-ts 产生的错误中(例如,ISODateTime 在您的情况下)。不幸的是,将.decode() 中的错误格式化为特定格式是一项相当棘手的工作。您可以使用内置的错误报告器D.draw 来获取格式良好的字符串:github.com/gcanti/io-ts/blob/master/…
    • 是的,我玩过draw 有点...但我认为在某些时候我需要研究编写一个自定义报告器,该报告器生成一个每个元素有一个错误的数组.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2021-10-09
    • 1970-01-01
    • 1970-01-01
    • 2018-06-26
    • 1970-01-01
    • 2011-12-21
    相关资源
    最近更新 更多