Skip to content

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

@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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions