Skip to content

Strict faker mocks (required+nonNullable): enum *Mock types, nested spreads, and Blob/ArrayBuffer mismatch #3590

Description

@Hypenate

Summary

With Orval 8.17.0, enabling both override.mock.required and override.mock.nonNullable (strict mock feature from #3525 / PR #3529) causes compile-time TypeScript errors in generated schemas/index.faker.ts when mock.generators includes { type: 'faker', schemas: true }.

Runtime mock values look correct; the failures are type mismatches in generated code.

Workaround: remove required: true and nonNullable: true — all errors disappear, but we lose strict mock return types needed for Cypress e2e (getXMock({ tag: null }) narrowing per #3525).

Environment

  • Orval: 8.17.0
  • TypeScript: 5.9
  • Output: tags-split, client: angular
  • Schema suffix: Dto
  • mock.generators: [{ type: 'faker', schemas: true, arrayItems: true }]

Reproduction

A sanitized minimal repro lives in this repo at:

tests/repro/strict-faker-mock-type-errors/

bun run build:release
cd tests/repro/strict-faker-mock-type-errors
bun ../../../packages/orval/dist/bin/orval.mjs --config orval.config.ts
bunx tsc --noEmit --project tsconfig.json

orval.config.ts

import { faker } from '@faker-js/faker';
import { defineConfig } from 'orval';

export default defineConfig({
  repro: {
    input: { target: './repro.yaml' },
    output: {
      mode: 'tags-split',
      target: './generated',
      schemas: './generated/schemas',
      client: 'angular',
      mock: {
        generators: [{ type: 'faker', schemas: true, arrayItems: true }],
      },
      override: {
        components: { schemas: { suffix: 'Dto' } },
        mock: {
          required: true,
          nonNullable: true,
          properties: {
            '/^([Ii]d)$/': () => faker.string.uuid(),
          },
        },
      },
    },
  },
});

Minimal OpenAPI (repro.yaml)

See tests/repro/strict-faker-mock-type-errors/repro.yaml — covers string enums, nested object arrays, nullable properties, and format: binary.

Observed errors (6 total in generated/schemas/index.faker.ts)

error TS2552: Cannot find name 'IntegrationDtoSettingsItemMock'. Did you mean 'IntegrationDtoSettingsItem'?
error TS2352: Conversion of type '{ ... channels: ChannelTypeDtoMock[] ... type: SettingValueTypeDto | SettingValueTypeDtoMock; }'
  to type 'MockWithNullableOverrides<SettingMetaDto, O, SettingMetaDtoMock>' may be a mistake ...
error TS2352: Conversion of type '{ channels: ChannelTypeDtoMock[]; settings: SettingMetaDto[]; ... }'
  to type 'MockWithNullableOverrides<ProviderMetaDto, O, ProviderMetaDtoMock>' may be a mistake ...
error TS2352: Conversion of type '{ ... activeChannels: ChannelTypeDtoMock[]; ... providerType: ProviderKindDto | ProviderKindDtoMock; }'
  to type 'MockWithNullableOverrides<IntegrationDto, O, IntegrationDtoMock>' may be a mistake ...
error TS2740: Type 'ArrayBuffer' is missing the following properties from type 'UploadFileDtoMock': size, type, arrayBuffer, bytes, and 2 more.

Bug 1: String-union enum *Mock types collapse to {}

For const-object enums like:

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

Orval generates:

export type ChannelTypeDtoMock = {
  [K in keyof Required<ChannelTypeDto>]: NonNullable<Required<ChannelTypeDto>[K]>;
};

Because ChannelTypeDto is a string-literal union, keyof Required<ChannelTypeDto> is never, so ChannelTypeDtoMock becomes {}.

Mock factory:

export const getChannelTypeDtoMock = (): ChannelTypeDtoMock =>
  faker.helpers.arrayElement(['sms', 'rcs', 'chat', 'mms'] as const);

Parent object literals then infer ChannelTypeDtoMock[] and ProviderKindDto | ProviderKindDtoMock, which fail the as MockWithNullableOverrides<...> casts on parent factories (getSettingMetaDtoMock, getProviderMetaDtoMock, getIntegrationDtoMock).

Expected fix: For string-union / const-object enum schemas, {Schema}Mock should alias the enum union itself (e.g. ChannelTypeDtoMock = ChannelTypeDto), not use the keyof Required<T> mapped type.

This also affects the existing issue-3525 fixture: StatusMock is emitted as the same broken mapped type in tests/__snapshots__/mock/issue-3525/model/index.faker.ts.


Bug 2: Nested mock spread incompatible with strict cast

Nested arrays use spread of generic mock factories:

settings: Array.from({ length: n }, () => ({
  ...getSettingMetaDtoMock(),
})),

getSettingMetaDtoMock() returns MockWithNullableOverrides<SettingMetaDto, O, SettingMetaDtoMock>, but the parent *DtoMock expects SettingMetaDto[] (plain DTO element types). The as MockWithNullableOverrides<...> cast on the parent fails.

Additionally, inline nested schemas (e.g. Integration.settings[] items) reference IntegrationDtoSettingsItemMock in factory signatures but do not emit the {Schema}Mock type alias.

Expected fix (pick one or combine):

  1. Emit nested values typed as the strict {Nested}Mock base type (not the full MockWithNullableOverrides return type), and emit missing inline-schema *Mock aliases.
  2. Call nested factories in a way TypeScript can structurally verify.
  3. Use as unknown as MockWithNullableOverrides<...> in generated output (less ideal).

Bug 3: Binary schema DTO type (Blob) vs faker mock (ArrayBuffer) mismatch

OpenAPI:

UploadFile:
  type: string
  format: binary

Generated DTO:

export type UploadFileDto = Blob;

Generated mock:

export type UploadFileDtoMock = {
  [K in keyof Required<UploadFileDto>]: NonNullable<Required<UploadFileDto>[K]>;
};
export const getUploadFileDtoMock = (): UploadFileDtoMock =>
  new ArrayBuffer(faker.number.int({ min: 1, max: 64 }));

TS error: ArrayBuffer is not assignable to UploadFileDtoMock (which resolves to Blob properties via the mapped type).

This is a generator inconsistency: DTO generator maps format: binaryBlob, faker generator maps binary → ArrayBuffer (intentional for MSW per #3065 / PR #3248). For faker-only schema mocks (no MSW handler), return type and value should align.

Expected fix: When emitting faker schema mocks for binary types, either:

  1. Generate UploadFileDtoMock = ArrayBuffer and getUploadFileDtoMock(): ArrayBuffer, or
  2. Generate new Blob([...]) to match Blob DTO type, or
  3. Use a dedicated binary mock type consistently across DTO + faker.

Related: #2934 (Blob typing).


What works without errors

Disabling strict mode avoids all errors:

// Remove:
// required: true,
// nonNullable: true,

Related

Note

Errors appear in schemas/index.faker.ts with schemas: true, not only in operation-level .faker.ts files.

Metadata

Metadata

Assignees

Labels

mockRelated to mock generation

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions