使用GraphQL Code Generator处理TypeScript中的日期

此文章的目的是什么?

在使用TypeScript和GraphQL Code Generator时,我发现很少有关于如何处理与日期相关的类型的文章,因此花费了一些时间才解决了这个问题。
一旦理解了,就觉得并不困难,但由于之前找不到相关资料,所以我将此作为备忘录。

环境

"graphql": "^16.6.0",
"graphql-scalars": "^1.20.1",
"graphql-yoga": "^3.1.1",
"@graphql-codegen/cli": "2.16.1",

最终版本的代码仓库

 

GraphQL 代码生成器

 

GraphQL Code Generator可以根据GraphQL的SDL生成相关的代码。
由于本次的主要目的是生成后端代码,因此需要在GraphQL Code Generator的配置文件codegen.ts中的plugins中指定’typescript-resolvers’。


const config: CodegenConfig = {
  schema: 'schema.graphql',
    generates: {
      './src/resolvers-types.ts': {    
        plugins: ['typescript', 'typescript-resolvers'],
      },
    },
    ...
  }
}

设置如此后,使用yarn graphql-codegen可以根据下面展示的GraphQL的SDL生成包含解析器的类型定义文件。

type Task {
  id: ID
  content: String!
  hasDone: Boolean!
}
type Query {
  drafts: [Task!]
}
...
export type Query = {
  __typename?: "Query";
  drafts: Maybe<Array<Task>>;
};

export type Task = {
  __typename?: "Task";
  content: Scalars["String"];
  hasDone: Scalars["Boolean"];
  id: Maybe<Scalars["ID"]>;
};

...
export type TaskResolvers<
  ContextType = any,
  ParentType extends ResolversParentTypes["Task"] = ResolversParentTypes["Task"]
> = {
  content?: Resolver<ResolversTypes["String"], ParentType, ContextType>;
  hasDone?: Resolver<ResolversTypes["Boolean"], ParentType, ContextType>;
  id?: Resolver<Maybe<ResolversTypes["ID"]>, ParentType, ContextType>;
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
...

在这种情况下,如果在Resolver中指定如下,就可以根据生成的类型来实现Resolver。

export const TaskResolever: QueryResolvers['drafts'] = () => {
   /// Taskを返す処理
}

image.png

用GraphQL的SDL来定义与日期相关的属性。

GraphQL的默认标量值只准备了以下选项。

    • Int

 

    • Float

 

    • String

 

    • Boolean

 

    ID

因此,當需要處理Date或DateTime等時,需要作為自定義標量進行添加。
自定義標量的定義如下所示。

scalar DateTime # この部分
scalar Date     # この部分

type Task {
  id: ID
  content: String!
  hasDone: Boolean!
  createdAt: DateTime! # Custom Scalarを参照
  createdOn: Date!     # Custom Scalarを参照
}
type Query {
 drafts: [Task!]
}

image.png

要将TypeScript类型设置为CutomScalar,在codegen.ts中需要指定Date和DateTime的类型。需要注意的是,这里的定义方式不是使用对象的类型,而是使用字符串的形式。也就是说,需要指定的是’Date’而不是Date。

...
const config: CodegenConfig = {
    ...
    scalars: {
      DateTime: 'Date',
      Date: 'Date'
    }
  }
};
...
image.png

如果想要防止Custom Scalar成为any类型的情况,可以将strictScalars选项设置为true,在代码生成时,当Custom Scalar的类型为any时,会抛出错误。

...
const config: CodegenConfig = {
    ...
    strictScalars: true, // この部分を追加
    scalars: {} // Date, DateTimeの定義がない場合
  }
};
...
image.png

 

GraphQL标量

在TypeScript中,经常使用的自定义标量是GraphQL Scalars包,它提供了Date和DateTime的定义,您可以利用它们。

 

在上述的schema.graphql中,answeredAt被指定为DateTime类型,而answeredOn被指定为Date类型。但在TypeScript的代码中,它们都以Date类型返回。

image.png

似乎两者都返回了new Date().toString()的值。为了返回期望的值,需要添加GraphQL Scalars的类型定义和解析器。

image.png
image.png

结束

如果在GraphQL Code Generator中处理日期和时间类型时,使用GraphQL Scalars,就不需要自己定义格式,非常方便。
但是,理解如何使用这些类型在官方文档中确实有一定困难,如果能帮助到其他遇到同样问题的人,我会很高兴。

附言

出于以下原因,我暂时不会处理GraphQL Code Generator。