Skip to main content

One post tagged with "小ネタ"

View All Tags

typescript-fetch generator に enum を union で生成するオプション追加した

· 6 min read

tl;dr

  • OpenAPI Generatorと呼ばれるOpenAPI Specificationファイルからクライアントを自動生成するツールに fetch & typescript の組み合わせでクライアントを生成するオプションが有る
  • 従来、OpenAPI Specification で言う enum を typescript の enum に変換してクライアントを生成していた
  • 今回、enum ではなく typescript の Union へ変換することもできるオプションが追加されたので、enum に対して懸念がある場合はこちらも検討してみると良いよ(実際にはデフォルトで Union へ変換されるため、enum を使いたい場合はオプションを true にすると良い)

OpenAPI Generator について

OpenAPI Specification は web api のリクエスト・レスポンスの言語によらないインターフェイスを提供するための仕様で openapi-generator はそこから自動的にクライアントのコードを生成するツールです。

同様にクライアントコードを生成するツールはたくさんありますが、openapi-generator は多くの言語/FW をサポートしており、またダウンロード数などを見てもデファクトに近いような形で使われているようです。

typescript 向けのものに関しては fetch をクライアントとして利用する typescript-fetch や axios をクライアントとして利用する typescript-axios などがあります。

stringEnums オプション

OpenAPI Specification は enum をサポートしており、OpenAPI Generator はこれを各言語で対応する表現にしてコードを生成します。

オプションが実装される前に生成されたコード

typescript-fetch 向けの生成においては、今までこれを typescript の enum に変換していました。

# original.yaml
openapi: 3.0.0
# ...
paths:
# ...
/pet/findByStatus:
get:
# ...
parameters:
- name: status
in: query
# ...
schema:
type: array
items:
type: string
enum:
- available
- pending
- sold
export enum FindPetsByStatusStatusEnum {
Available = "available",
Pending = "pending",
Sold = "sold",
}

ここで利用されている typescript の enum はtree shaking との相性typescript 独自のものになってしまっていたり、型安全ではないような事があったりなどの懸念が指摘されているのもあり、利用を控えたい人も少なからず存在する状況です。実際こちらの記事などでは OpenAPI Generator によって enum が生成されてしまうという箇所が懸念として指摘されています。

個人的のもこの点はどうにかしたいと思っていたため、OpenAPI Generator 本体に Union として出力できるオプションを追加するPull Requestをマージしてもらいました。

オプション実装後に生成されるコード

オプション実装後、この動作はデフォルトで有効になり、以下のようなコードを生成するようになります。

export const FindPetsByStatusStatusEnum = {
Available: "available",
Pending: "pending",
Sold: "sold",
} as const;

export type FindPetsByStatusStatusEnum =
(typeof FindPetsByStatusStatusEnum)[keyof typeof FindPetsByStatusStatusEnum];

元の enum を生成する挙動のままとしたい場合 は stringEnums オプションを true にすると元の挙動のままになります。(ex: )

※この実装は typescript-axios に対して実装されたもの をそのまま借用している形で実装されいています。個人的には const で宣言した変数と同一の名前で宣言した type がうまく動くのが割と面白いなと思って実装していました。

今すぐ使いたい場合には

stringEnums オプションが実装されたバージョンはまだリリースがされていません(2022 年の 5 月以降になる予定ですが、現状は決まっていません)。今すぐ利用をしたい場合はdockerの latest であれば利用ができます。

# enumのままとしたい場合
docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate -i /local/spec.yaml -g typescript-fetch -o local/generated/ -p stringEnums=true
# union型を生成したい場合(デフォルトでunionを生成するので、オプションの指定は不要)
docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate -i /local/spec.yaml -g typescript-fetch -o local/generated/

現在 OpenAPI Generator は次のメジャーバージョン向けての準備中であるため、いくつかの fallback なしの breaking changes が含まれている場合があることには注意が必要です。

参考