Describe the bug
When an operationId starts with a digit, hey-api names the SDK function and its Data type differently:
// sdk.gen.ts
export const _123NumericLead = <ThrowOnError extends boolean = false>(
options?: Options<NumericLeadData, ThrowOnError>
) => ...
The function is _123NumericLead (prefixed, because an identifier cannot start with a digit) but the type is NumericLeadData (the digits are dropped). This codegen derives the Data type name from the method name — ${capitalizeFirstLetter(methodName)}Data → _123NumericLeadData — which does not exist, so the lookup misses.
Two symptoms follow, and the first is the more damaging one:
1. Pagination is silently disabled. getPaginatableMethods in src/parseOperations.mts keys its map by a name derived from the Data type, so paginatableMethods.get(methodName) misses and isPaginatable stays false. The operation gets no infinite hooks at all even though it has a valid page parameter. There is no error — the feature just isn't there.
2. The generated code does not typecheck. getDataTypeName falls back to unknown, emitting Options<unknown, true>. hey-api's Options<TData extends TDataShape> rejects unknown, producing 6 × TS2344 across common.ts, queries.ts, suspense.ts, prefetch.ts, ensureQueryData.ts and queryOptions.ts.
To Reproduce
- Generate from the spec below
- Observe
openapi/queries/infiniteQueries.ts contains no hook for the /d operation, despite its page query parameter
- Run
tsc --noEmit over the generated output
OpenAPI spec file
openapi: "3.0.0"
info: { version: 1.0.0, title: probe }
paths:
/d:
get:
operationId: 123numericLead
parameters:
- name: page
in: query
schema: { type: integer }
responses:
'200':
description: ok
content:
application/json:
schema: { type: array, items: { type: string } }
Actual tsc output:
openapi/queries/common.ts(29,64): error TS2344: Type 'unknown' does not satisfy the constraint 'TDataShape'.
openapi/queries/ensureQueryData.ts(11,95): error TS2344: ...
openapi/queries/prefetch.ts(11,93): error TS2344: ...
openapi/queries/queries.ts(11,170): error TS2344: ...
openapi/queries/queryOptions.ts(11,63): error TS2344: ...
openapi/queries/suspense.ts(11,191): error TS2344: ...
Other awkward operationId shapes were checked and are not affected — spaces (find pet by id), a leading underscore, and SCREAMING_CASE all round-trip correctly. The digit-leading case is the one where the two names diverge.
Expected behavior
The operation should get its infinite hooks, and the generated output should compile.
Environment
- OS: macOS
- Version: v3.0.1
@hey-api/openapi-ts 0.99.0
Additional context
The fix is to stop deriving the Data type from the method name and instead read it from the SDK function's own signature — the type argument of Options<…> in sdk.gen.ts is already the authoritative answer and is right there in the AST that parseOperations.mts walks. That resolves both symptoms at once.
Substituting Options<TDataShape, true> for the unknown fallback would only paper over symptom 2, and would drag in an import from ../requests/client whose path varies by client — not recommended.
Note for whoever picks this up: the four Options<unknown, true> assertions in tests/tsmorph/buildQueryHooks.test.ts currently pin this broken output, so they document a bug rather than a contract and should be rewritten alongside the fix. #209 added a guard test (should expose a Data type in modelNames for every paginatable operation) that pins the invariant the infinite-query builders depend on; any change to how Data types are resolved must keep it green.
Found while investigating #209, which removed a genuinely unreachable variant of this fallback on the paginatable path. This issue is the reachable, non-paginatable half that remains.
Describe the bug
When an
operationIdstarts with a digit, hey-api names the SDK function and itsDatatype differently:The function is
_123NumericLead(prefixed, because an identifier cannot start with a digit) but the type isNumericLeadData(the digits are dropped). This codegen derives theDatatype name from the method name —${capitalizeFirstLetter(methodName)}Data→_123NumericLeadData— which does not exist, so the lookup misses.Two symptoms follow, and the first is the more damaging one:
1. Pagination is silently disabled.
getPaginatableMethodsinsrc/parseOperations.mtskeys its map by a name derived from theDatatype, sopaginatableMethods.get(methodName)misses andisPaginatablestaysfalse. The operation gets no infinite hooks at all even though it has a valid page parameter. There is no error — the feature just isn't there.2. The generated code does not typecheck.
getDataTypeNamefalls back tounknown, emittingOptions<unknown, true>. hey-api'sOptions<TData extends TDataShape>rejectsunknown, producing 6 ×TS2344acrosscommon.ts,queries.ts,suspense.ts,prefetch.ts,ensureQueryData.tsandqueryOptions.ts.To Reproduce
openapi/queries/infiniteQueries.tscontains no hook for the/doperation, despite itspagequery parametertsc --noEmitover the generated outputOpenAPI spec file
Actual
tscoutput:Other awkward operationId shapes were checked and are not affected — spaces (
find pet by id), a leading underscore, andSCREAMING_CASEall round-trip correctly. The digit-leading case is the one where the two names diverge.Expected behavior
The operation should get its infinite hooks, and the generated output should compile.
Environment
@hey-api/openapi-ts0.99.0Additional context
The fix is to stop deriving the
Datatype from the method name and instead read it from the SDK function's own signature — the type argument ofOptions<…>insdk.gen.tsis already the authoritative answer and is right there in the AST thatparseOperations.mtswalks. That resolves both symptoms at once.Substituting
Options<TDataShape, true>for theunknownfallback would only paper over symptom 2, and would drag in an import from../requests/clientwhose path varies by client — not recommended.Note for whoever picks this up: the four
Options<unknown, true>assertions intests/tsmorph/buildQueryHooks.test.tscurrently pin this broken output, so they document a bug rather than a contract and should be rewritten alongside the fix. #209 added a guard test (should expose a Data type in modelNames for every paginatable operation) that pins the invariant the infinite-query builders depend on; any change to howDatatypes are resolved must keep it green.Found while investigating #209, which removed a genuinely unreachable variant of this fallback on the paginatable path. This issue is the reachable, non-paginatable half that remains.