Last active
February 22, 2023 01:42
-
-
Save ygkn/1b44051e8413355a91d2bdd765ae9b70 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { LowerHttpMethod, AspidaResponse } from "aspida"; | |
import { | |
rest, | |
ResponseResolver, | |
RestContext, | |
RestRequest, | |
DefaultBodyType, | |
} from "msw"; | |
/** | |
* aspida クライアントから型安全にハンドラを作成する | |
* 存在しないパスやメソッドを指定した場合や、レスポンスの型が合わない場合はコンパイルエラーになる | |
* | |
* レスポンスの型がつく(間違った型がエラーになる)のは正常系のレスポンスボディのみ | |
* ステータスコードや異常系のレスポンスボディは型がつかない(なんでも通る)ので注意 | |
* (これは openapi2aspida が異常系を見ないこと、msw の ctx.status の引数が number なことが原因) | |
* | |
* @example | |
* ```ts | |
* import aspida from "@aspida/fetch"; | |
* import { aspidaHandler } from "../aspidaHandler"; | |
* import api from "@/api/$api"; | |
* | |
* const hander = aspidaHandler( | |
* api(aspida()).users.login, | |
* "post", | |
* (req, res, ctx) => { | |
* return res( | |
* ctx.status(200), | |
* ctx.json({ | |
* token: "eyJ....", | |
* }) | |
* ); | |
* } | |
* ); | |
* ``` | |
* | |
*/ | |
export const aspidaHandler = < | |
// { $path: (option) => "/users", post: ... } のような型 | |
Api extends Partial<Record<LowerHttpMethod, unknown>> & { | |
$path: (option?: unknown) => string; | |
}, | |
// Api のプロパティのうち、LowerHttpMethod に含まれるもの ($path などを除く) | |
Method extends keyof Api & LowerHttpMethod | |
>( | |
api: Api, | |
method: Method, | |
// Api[Method] から RequestBody と ResponseBody を推論する | |
resolver: Api[Method] extends (options: { | |
body: infer ReqestBody extends DefaultBodyType; | |
}) => Promise<AspidaResponse<infer ResponseBody extends DefaultBodyType>> | |
? // RequestBody と ResponseBody を使って resolver の型を作成する | |
ResponseResolver<RestRequest<ReqestBody>, RestContext, ResponseBody> | |
: // 推論できない場合 (= パスやメソッドが存在しない場合) は never となり、コンパイルエラーになる | |
never | |
) => rest[method](api.$path(), resolver); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment