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

6za6bjd0  于 2023-05-23  发布在  TypeScript
关注(0)|答案(4)|浏览(135)

我有一个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;

但是,由于类型脚本的限制,data.date仍然是字符串。
这可能会导致代码后面的问题,我希望所有此类日期字段都是一个实际的Date对象。
我可能会做这样的事情:data.date = new Date(data.date);。但是这不是可行的方法,原因很多。
有没有更好的方法处理 typescript 中的日期?一般情况下,您如何处理来自API的日期?

vlurs2pr

vlurs2pr1#

因此,最适合我的用例的解决方案类似于@Amy在原始问题的评论中提到的解决方案。
因此,我使用Axios拦截器将日期转换为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;

为了标识日期,我使用了一个正则表达式,为了转换为Date对象,我使用了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);
  }
}
lx0bsm1f

lx0bsm1f2#

这个问题值得更多的关注。对我来说,理智取决于所有json日期解析为对象在我的应用程序中出现的那一刻自动标注它们的日期。最好的方法是修改全局JSON对象。显然,这是一个广泛使用的全局API的根本性改变,但这是一个更好的改变。它与Axios一起工作,没有拦截器,如果任何天才决定使用fetch或xhr或任何其他你拥有的东西,它也会工作。
Rick Strahl has a robust .js routine for doing just this和我衷心地推荐给全世界。可惜它不是npm。(你可能不想在服务器上这样做,请看评论)

f3temu5u

f3temu5u3#

我个人使用的一个选项是创建一个效用函数,将输入从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);

为了使其完全类型安全,函数还应该验证输入对象,以验证它是否具有正确格式的正确字段。如果您担心MyEvent的模式可能会被API更改,而客户端却没有相应的更改,那么这一点尤其重要。
如果您使用启用了noExplicitAny的代码库,您还可以使用Record<string, unknown>而不是any。这两种方法都需要createMyEvent中的额外类型Assert,但基本思想保持不变。

2nc8po8w

2nc8po8w4#

我知道这可能不是所有情况下的最佳解决方案,但我最终使用数字代替,每个日期都作为数字传递,对于日期选择器,它接受unix的数字,并在内部转换为Date,反之亦然。但是为了使用数字,API也应该发送unix的数字,这对一些人来说可能不是最佳的。

相关问题