Skip to content

Optional Types Don't Play Well with httpRoute and httpRequest #139

Open
@timmyhartke2

Description

@timmyhartke2

Attempting to use optionalized, or a combination of type, partial, and intersection as shown here results in an error from httpRequest. For example, if we define exampleRequestBody as

export const exampleRequestBody = optionalized({
  exampleId: t.number,
  date: t.string,
  optionalParameter: optional(t.number),
});

export type ExampleRequestBody = t.TypeOf<typeof ExampleRequestBody>;

And we define our example httpRoute as ExampleHttpRoute:

export const ExampleHttpRoute = httpRoute({
  path: 'example/api/path',
  method: 'POST',
  request: httpRequest({
    body: exampleRequestBody,
    headers: {
      'apikey': NonEmptyString,
    },
  }),
  response: {
    200: ExampleResponseBody,
  },
});

Then we get this error back:

TS2322: Type 'Type<never, { params: {} & {}; query: {} & {}; headers: { 'apikey': string; } & {}; body: {} & { readonly _A?: unknown; 
readonly _O?: unknown; readonly types?: unknown; readonly _tag?: unknown; readonly name?: unknown; readonly is?: unknown; readonly validate?: unknown; ... 5 more ...; decode?: unknown; }; }, unk...' is not assignable to type 'HttpRequestCodec<any>'. 
Types of property 'encode' are incompatible. Type 'Encode<never, { params: {} & {}; query: {} & {}; headers: { 'apikey': string; } & {};
body: {} & { readonly _A?: unknown; readonly _O?: unknown; readonly types?: unknown; readonly _tag?: unknown; readonly name?:
unknown; readonly is?: unknown; readonly validate?: unknown; ... 5 more ...; decode?: unknown; }; }>' is not assignable to type 
'Encode<any, { params: { [x: string]: string; }; query: { [x: string]: string | string[]; }; } & { headers?: { [x: string]: string; } | undefined;
body?: Json | undefined; }>'.       Type 'any' is not assignable to type 'never'.

There is a workaround for certain situations, but not all. If your schema does not have optional attributes at the top level, for example, then you can do this:

export const exampleRequestBody = {
  exampleId: t.number,
  date: t.string,
  optional_data: optionalized({
    optionalParameter: optional(t.number)
  })
};

However, if you need to define an optional attribute at the top level of your schema (such as in the first example), this does not work. This is a problem when, for example, you are writing a schema for external API's request/response body. If that API has optional attributes at the top level of the request/response body, there is not currently a clean way to deal with that using this library.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions