encore
encore copied to clipboard
Issue with TypeScript union types causing error in `encore run`
The run command does not accept union types or anything that is not an interface as the return type of any API call.
Here is the error
error: expected named interface type, found Union(Union { types: [Named(Named { obj: Object { name: Some("LoginSuccessfulResponse") }, type_arguments: [] }), Named(Named { obj: Object { name: Some("MFARequiredResponse") }, type_arguments: [] })] })
--> [...]\api\src\auth\login.ts:57:34
|
57 | async (params: LoginParams): Promise<LoginResponse> => {
| ^^^^^^^^^^^^^^^^^^^^^^
Sample code to reproduce
interface LoginParams {
coin: bool
}
export interface LoginSuccessfulResponse {
ok: true;
param1: string
}
interface MFARequiredResponse {
ok: false;
param2: string
}
type LoginResponse = LoginSuccessfulResponse | MFARequiredResponse;
export const login = api(
{
method: [ "POST" ],
expose: true,
path: "/auth/login",
},
async (params: LoginParams): Promise<LoginResponse> => {
if (params.coin) {
return { ok: true, param1: "true" }
}
return { ok: false, param2: "false" }
}
);
Union types in the root definition for the response is not supported but as a workaround I think both fields could fit as null values in a single interface.
yes, they can, the point here is that using that kind of type union allows to disambiguate the calling result based on the ok value, so that
// in client
response = call_ep();
if(response.ok) {
// here response has access to param1 only, other fields are considered non existent
return;
}
// here response instead can access param2 without other checks
a syntax like the one before avoids the necessity to bloat the code with something like const test = response.param1 || response.param2 || ""
You can use unions, just not on the root level, so you could do something like:
export type LoginSuccess = {
ok: true;
param1: string;
};
export type LoginFailure = {
ok: false;
param2: string;
};
export interface LoginResponse {
status: LoginSuccess | LoginFailure;
};