fix(sdk-codegen): make run_inline_query response type generic#1730
fix(sdk-codegen): make run_inline_query response type generic#1730marc-wilson wants to merge 2 commits into
Conversation
`run_inline_query` was hardcoded to return `SDKResponse<string, ...>`, but when `result_format` is 'json' the transport layer actually deserializes the body into an object/array, forcing every JSON consumer into `as unknown as T` casts. The Looker API spec declares a single `string` response for this endpoint regardless of `result_format`, so the generator can't derive the real per-format shape automatically. `run_inline_query` is now generic (`<T = string>`), so callers can opt in to a typed result (`sdk.run_inline_query<MyType[]>(request)`) with no cast. The default type argument keeps the signature fully backward compatible: existing call sites that don't supply a generic still resolve to `string`, identical to before. Fixes looker-open-source#1703
There was a problem hiding this comment.
Code Review
This pull request introduces support for generic response types in the TypeScript SDK generator for methods whose runtime return type depends on the requested format (such as run_inline_query). This is achieved by introducing helper methods in the generator to inject generic type parameters (<T = string>) and dynamically resolve the response type name. The reviewer suggested extending this generic response type support to streaming methods as well, ensuring that their callback signatures also benefit from the generic type instead of being hardcoded to string.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const callback = `callback: (response: Response) => Promise<${mapped.name}>,`; | ||
| const generics = streamer ? '' : this.methodGenericParams(method); |
There was a problem hiding this comment.
Currently, if streamer is true, the generic type parameter is omitted (generics is set to '') and the callback return type is hardcoded to Promise<${mapped.name}> (which resolves to Promise<string>).
To ensure that streaming versions of format-dependent methods also benefit from the generic response type, we should use this.responseTypeName(method) in the callback signature and allow generics to be generated for streaming methods as well.
| const callback = `callback: (response: Response) => Promise<${mapped.name}>,`; | |
| const generics = streamer ? '' : this.methodGenericParams(method); | |
| const callback = 'callback: (response: Response) => Promise<' + this.responseTypeName(method) + '>,'; | |
| const generics = this.methodGenericParams(method); |
There was a problem hiding this comment.
Good catch, and agreed in principle — but I'd like to keep this specific to the non-streaming path for now.
The streaming variant's callback receives the raw Response/Readable (e.g. for piping a download to a file), so its return type is really "whatever the caller's callback resolves to," not the parsed response.value shape that issue #1703 is about. Hardcoding that callback's return type to string predates this PR and isn't something this change touches — I only added the generic to the non-streaming (streamer === false) branch.
That said, I think your suggestion is a reasonable extension: expose the same <T> on the streaming signature so callers of sdk.stream.run_inline_query<T>(...) aren't stuck with Promise<string> either. I'd rather do that as a deliberate follow-up (along with the other result_format-driven methods called out in the PR description — run_query, run_look, etc.) once the core generic-default pattern here is confirmed to be the right approach, rather than widen this PR's diff. Let me know if you'd prefer it bundled in now instead.
What
run_inline_queryis hardcoded to returnSDKResponse<string, ...>, but whenresult_formatis'json'the transport layer actually deserializes the body into an object/array. Sincevalueis typed asstring, callers have no valid TypeScript path to the real data and are forced intoas unknown as Tcasts, which defeats type safety entirely.Looker's OpenAPI spec declares a single
200: { schema: { type: string } }response for this endpoint with no per-result_formatbreakdown, so the generator can't derive the real shape per format automatically. This PR makesrun_inline_querygeneric instead:Callers who know their query's shape (they always do — they specify model/view/fields) can now write:
Backward compatibility — this is opt-in, no existing consumers break
<T = string>has a default type argument. Any existing call site that doesn't supply a generic (sdk.run_inline_query(request)) resolvesTtostring, exactly as before — no change in inferred type, no change in behavior.this.post(...)is identical regardless ofT. No runtime behavior changes.yarn buildtype-checks the full monorepo against the new signature with zero errors, and reverting only the implementation (leaving the generic interface) reliably produces a type error — confirming the generic threads correctly end-to-end and that plain, non-generic call sites are unaffected.Scope
This is scoped to
run_inline_queryonly, per the linked issue. The sameresult_format-driven typing problem exists on a few sibling methods (run_query,run_look,run_url_encoded_query,run_sql_query) that weren't touched here to keep this PR minimal and reviewable. Happy to circle back and apply the same generic-default pattern to those once this approach is confirmed to be the right one.Changes
packages/sdk-codegen/src/typescript.gen.ts: generator now emits<T = string>for methods special-cased as "format-dependent string" responses (currently justrun_inline_query).packages/sdk/src/4.0/methods.ts,methodsInterface.ts,funcs.ts: regenerated output forrun_inline_queryreflecting the generic.Fixes #1703
Test plan
yarn buildpasses cleanly across all 21 packagessdk/sdk-codegen/sdk-rtljest suites pass (only pre-existing, unrelated failures remain — 2 tests requiring a livelooker.ini, confirmed to fail identically onmain)sdk.run_inline_query<MyType[]>(request)and get a fully typedresponse.valuewith no cast, and that omitting the generic still defaults tostringmethods.tsimplementation and re-runningtsc— it immediately fails type-checking against the generic interface, proving the change is meaningful