如何在 TypeScript 中处理 ISO 日期字符串?

Che*_*het 12 typescript

我是打字稿的新手,所以我正在努力掌握它。

网络请求将返回一个带有 ISO 日期字符串格式字段的 JSON 对象。

data : Data = {when: "2016-07-13T18:46:01.933Z"}
Run Code Online (Sandbox Code Playgroud)

当我为这个接口创建类型签名时,有什么方法可以指定这实际上是一个 ISO 时间戳还是我只需要使用字符串?

interface Data {
  when: string
}
Run Code Online (Sandbox Code Playgroud)

我发现我可以使用一个在精神上有帮助的类型别名,但并没有真正验证 ISO 字符串。

type iso = string
interface Data {
  when: iso
}
Run Code Online (Sandbox Code Playgroud)

同样,我很好奇是否有办法从这些打字稿注释生成 js 验证,以便我可以验证端点接收到的信息,否则我键入的应用程序的其余部分毫无价值。

如果这是可能的,那么如果可以将此 iso 字符串强制转换为实际的 Date 对象,那就太酷了。

正如我所说,我是打字稿的新手,所以我不确定这是否超出了打字稿应该做的范围。

小智 10

尝试这个:

// In TS, interfaces are "open" and can be extended
interface Date {
  /**
   * Give a more precise return type to the method `toISOString()`:
   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
   */
  toISOString(): TDateISO;
}

type TYear         = `${number}${number}${number}${number}`;
type TMonth        = `${number}${number}`;
type TDay          = `${number}${number}`;
type THours        = `${number}${number}`;
type TMinutes      = `${number}${number}`;
type TSeconds      = `${number}${number}`;
type TMilliseconds = `${number}${number}${number}`;

/**
 * Represent a string like `2021-01-08`
 */
type TDateISODate = `${TYear}-${TMonth}-${TDay}`;

/**
 * Represent a string like `14:42:34.678`
 */
type TDateISOTime = `${THours}:${TMinutes}:${TSeconds}.${TMilliseconds}`;

/**
 * Represent a string like `2021-01-08T14:42:34.678Z` (format: ISO 8601).
 *
 * It is not possible to type more precisely (list every possible values for months, hours etc) as
 * it would result in a warning from TypeScript:
 *   "Expression produces a union type that is too complex to represent. ts(2590)
 */
type TDateISO = `${TDateISODate}T${TDateISOTime}Z`;
Run Code Online (Sandbox Code Playgroud)

来源

  • 这个答案具有误导性,因为“${number}”并不限于整数,正如人们在阅读这个答案时可能会假设的那样。科学计数法和小数可分配给 `${number}`,并且此代码编译:`const date: TDateISODate = '2000.3e+3-3.223232e2-123456789.12321312e12'` 另外,模板文字仅在编译时、用户输入时应用根本不会被守护。您无法避免运行时检查来验证日期字符串。 (3认同)

Ale*_* L. 6

不,这是不可能的。对于 javascript,与 typescript 的接口无关。(JS 根本不会为接口生成)。此外,所有类型检查都是在“编译”或“编译”时完成的,而不是在运行时完成。

可以做的是reviver在解析json时使用函数。例如:

const datePattern = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
const json = '{"when": "2016-07-13T18:46:01.933Z"}';

const result = JSON.parse(json, (key: any, value: any) => {
    const isDate = typeof value === 'string' && datePattern.exec(value);
    return isDate? new Date(value) : value;
});
Run Code Online (Sandbox Code Playgroud)

您也可以Date通过键来识别属性,如果它与日期模式不匹配,您可以抛出错误或做任何您想做的事情。


Ric*_*ter 6

您可以使用类型保护

import moment from 'moment'

export const isISO = (input: any): input is tISO =>
  moment(input, moment.ISO_8601, true).isValid()
Run Code Online (Sandbox Code Playgroud)

然后你可以使用任何你想要处理任何错误日期的自定义逻辑,例如:

const maybeISO = fetch('Maybe ISO')

if (isISO(maybeISO)) {
  // proceed
} else {
  // check other format?
  // log error?
}
Run Code Online (Sandbox Code Playgroud)

干杯。