Reactjs 从typescript中的API响应正确地转换日期

Reactjs 从typescript中的API响应正确地转换日期,reactjs,typescript,axios,Reactjs,Typescript,Axios,我有一个REST API,它以以下格式提供数据:- {“id”:1,“name”:“New event”,“date”:“2020-11-14T18:02:00”} 我的前端React应用程序中的界面如下:- export interface MyEvent { id: number; name: string; date: Date; } 我使用axios从API获取响应 const response = await axios.get<MyEvent>("

我有一个REST API,它以以下格式提供数据:-

{“id”:1,“name”:“New event”,“date”:“2020-11-14T18:02:00”}

我的前端React应用程序中的界面如下:-

export interface MyEvent {
  id: number;
  name: string;
  date: Date;
}
我使用axios从API获取响应

const response = await axios.get<MyEvent>("/event/1");
const data = response.data;
const response=wait axios.get(“/event/1”);
const data=response.data;
但是,由于typescript的限制,
data.date
仍然是一个字符串

这可能会导致代码中出现问题,我希望所有此类日期字段都是实际的日期对象

const client = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_BASE_URL });

client.interceptors.response.use(originalResponse => {
  handleDates(originalResponse.data);
  return originalResponse;
});

export default client;
我可能会这样做:
data.date=newdate(data.date)。但由于很多原因,这将是不可行的方法


在typescript中有更好的处理日期的方法吗?一般来说,如何处理来自API的响应日期?

我个人使用的一个选项是创建一个实用函数,将输入从
any
解析到
MyEvent
。你可以这样做:

function createMyEvent(data: any): MyEvent {
    return {
        id: data.id,
        name: data.name,
        date: new Date(data.date)
    };
}
// Same as before, but without a type specified.
const response = await axios.get("/event/1");
// Type is still "MyEvent", but this time its valid.
const data = createMyEvent(response.data);
然后像这样使用它:

function createMyEvent(data: any): MyEvent {
    return {
        id: data.id,
        name: data.name,
        date: new Date(data.date)
    };
}
// Same as before, but without a type specified.
const response = await axios.get("/event/1");
// Type is still "MyEvent", but this time its valid.
const data = createMyEvent(response.data);
为了使此类型完全安全,函数还应验证输入对象,以验证其具有正确格式的正确字段。如果您担心API可能会更改
MyEvent
的模式,而无需对客户端进行匹配更改,则这一点尤为重要


如果在启用了
noExplicitAny
的代码库中工作,您还可以根据需要使用
Record
而不是
any
。这两种方法都需要在
createMyEvent
中附加类型断言,但基本思想保持不变。

因此最适合我的用例的解决方案类似于@Amy在原始问题评论中提到的解决方案

因此,我使用Axios拦截器将日期转换为日期对象

const client = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_BASE_URL });

client.interceptors.response.use(originalResponse => {
  handleDates(originalResponse.data);
  return originalResponse;
});

export default client;
为了标识日期,我使用了一个正则表达式,为了转换为日期对象,我使用了Date fns包

const isoDateFormat = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d*)?$/;

function isIsoDateString(value: any): boolean {
  return value && typeof value === "string" && isoDateFormat.test(value);
}

export function handleDates(body: any) {
  if (body === null || body === undefined || typeof body !== "object")
    return body;

  for (const key of Object.keys(body)) {
    const value = body[key];
    if (isIsoDateString(value)) body[key] = parseISO(value);
    else if (typeof value === "object") handleDates(value);
  }
}

日期是字符串,因为JSON中的限制,而不是TypeScript。可以使用字符串来表示JSON中的日期,也可以使用数字(从一个历元开始的记号)。无论哪种方式,您都必须将JSON表示转换为实际的日期对象。我知道这一点。我提到的限制是,typescript在运行时从不验证类型或正确转换类型。我基本上是在寻找一种方法来以干净的方式处理这个问题,而不将分散在我的服务层中的字符串逻辑转换为日期逻辑。您是否尝试过moment.js?看看“axios响应拦截器”。我没有使用axios的经验,但拦截器是标准的设计模式,快速谷歌搜索表明axios使用相同的模式。在发出请求之前注册拦截器,然后拦截器在响应JSON中查找与日期匹配的字符串。我为Restangular做了类似的事情,但很抱歉,我不能共享代码(无论如何,它是为另一个库编写的)。@Babri我的解决方案与之非常相似。查看
角度Http拦截器
部分。它递归地遍历对象结构,查找与ISO-8601日期格式匹配的字符串值,并用日期对象替换匹配项。这需要适应Axios,但我希望这会有所帮助。干杯。我找到了一个更好的正则表达式:
^(\d{4})-(d{2})-(d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)((\d{2}):(\d{2})| Z)$