1

为了简单使用,解码器方法一直在使用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
});
4

1 回答 1

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是相当宽松的。

于 2021-06-26T02:14:24.300 回答