From 392896f7708244c3e66ba9a5ed52e81775371c74 Mon Sep 17 00:00:00 2001 From: Richard Powell Date: Fri, 13 Mar 2026 12:38:04 -0400 Subject: [PATCH] fix(api-codegen-preset): generate string instead of any for custom scalars Shopify API custom scalars (DateTime, Money, URL, HTML, etc.) now resolve to `string` in generated TypeScript output rather than `any`. The JSON scalar resolves to `unknown`. Uses the typescript codegen plugin's `defaultScalarType` and `scalars` options, so any future scalars added to the Shopify API are handled automatically without code changes. Fixes #1154 Co-Authored-By: Claude Sonnet 4.6 --- .changeset/fix-codegen-scalar-types.md | 12 ++++++++++++ .../api-codegen-preset/src/api-types.ts | 10 +++++----- .../src/tests/api-project.test.ts | 19 +++++++++++++------ .../src/tests/api-types.test.ts | 14 +++++++++++--- 4 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 .changeset/fix-codegen-scalar-types.md diff --git a/.changeset/fix-codegen-scalar-types.md b/.changeset/fix-codegen-scalar-types.md new file mode 100644 index 0000000000..2af56482a0 --- /dev/null +++ b/.changeset/fix-codegen-scalar-types.md @@ -0,0 +1,12 @@ +--- +'@shopify/api-codegen-preset': patch +--- + +Fix custom GraphQL scalars generating as `any` in codegen output + +Shopify API custom scalars (e.g. `DateTime`, `Money`, `URL`, `HTML`) now +correctly generate as `string` in codegen output instead of `any`. The `JSON` +scalar generates as `unknown`. This applies automatically to all current and +future Shopify API scalars without requiring manual configuration. + +Fixes https://github.com/Shopify/shopify-app-js/issues/1154 diff --git a/packages/api-clients/api-codegen-preset/src/api-types.ts b/packages/api-clients/api-codegen-preset/src/api-types.ts index 4684720e4a..2035e7067e 100644 --- a/packages/api-clients/api-codegen-preset/src/api-types.ts +++ b/packages/api-clients/api-codegen-preset/src/api-types.ts @@ -38,11 +38,11 @@ export const shopifyApiTypes = ({ [`${outputDir}/${typesFile}`]: { schema: schemaFileExists ? schemaFile : schema, plugins: ['typescript'], - ...(enumsAsConst !== undefined && { - config: { - enumsAsConst, - }, - }), + config: { + defaultScalarType: 'string', + scalars: {JSON: 'unknown'}, + ...(enumsAsConst !== undefined && {enumsAsConst}), + }, }, [`${outputDir}/${queryTypesFile}`]: { schema: schemaFileExists ? schemaFile : schema, diff --git a/packages/api-clients/api-codegen-preset/src/tests/api-project.test.ts b/packages/api-clients/api-codegen-preset/src/tests/api-project.test.ts index 5232a4685c..35edc23cc4 100644 --- a/packages/api-clients/api-codegen-preset/src/tests/api-project.test.ts +++ b/packages/api-clients/api-codegen-preset/src/tests/api-project.test.ts @@ -140,6 +140,8 @@ describe('shopifyApiProject', () => { schema: expect.anything(), plugins: ['typescript'], config: { + defaultScalarType: 'string', + scalars: {JSON: 'unknown'}, enumsAsConst: true, }, }), @@ -165,13 +167,15 @@ describe('shopifyApiProject', () => { schema: expect.anything(), plugins: ['typescript'], config: { + defaultScalarType: 'string', + scalars: {JSON: 'unknown'}, enumsAsConst: false, }, }), ); }); - it('does not include config when enumsAsConst is not provided', () => { + it('uses default scalar config when enumsAsConst is not provided', () => { // GIVEN const config: ShopifyApiProjectOptions = { apiType, @@ -184,13 +188,16 @@ describe('shopifyApiProject', () => { // THEN expect( projectConfig.extensions.codegen.generates[`./${type}.types.d.ts`], - ).toEqual({ - schema: expect.anything(), - plugins: ['typescript'], - }); + ).toEqual( + expect.objectContaining({ + schema: expect.anything(), + plugins: ['typescript'], + config: {defaultScalarType: 'string', scalars: {JSON: 'unknown'}}, + }), + ); expect( projectConfig.extensions.codegen.generates[`./${type}.types.d.ts`], - ).not.toHaveProperty('config'); + ).not.toHaveProperty('config.enumsAsConst'); }); }, ); diff --git a/packages/api-clients/api-codegen-preset/src/tests/api-types.test.ts b/packages/api-clients/api-codegen-preset/src/tests/api-types.test.ts index 8d781d7e5f..a4280d8419 100644 --- a/packages/api-clients/api-codegen-preset/src/tests/api-types.test.ts +++ b/packages/api-clients/api-codegen-preset/src/tests/api-types.test.ts @@ -41,6 +41,7 @@ describe('shopifyApiTypes', () => { [`./testDir/${type}.types.d.ts`]: { schema: expectedSchema, plugins: ['typescript'], + config: {defaultScalarType: 'string', scalars: {JSON: 'unknown'}}, }, [`./testDir/${type}.generated.d.ts`]: { schema: expectedSchema, @@ -73,6 +74,7 @@ describe('shopifyApiTypes', () => { [`./testDir/${type}.types.d.ts`]: { schema: `./testDir/${type}-2024-10.schema.json`, plugins: ['typescript'], + config: {defaultScalarType: 'string', scalars: {JSON: 'unknown'}}, }, [`./testDir/${type}.generated.d.ts`]: { schema: `./testDir/${type}-2024-10.schema.json`, @@ -102,6 +104,7 @@ describe('shopifyApiTypes', () => { [`./${type}.types.d.ts`]: { schema: expectedSchema, plugins: ['typescript'], + config: {defaultScalarType: 'string', scalars: {JSON: 'unknown'}}, }, [`./${type}.generated.d.ts`]: { schema: expectedSchema, @@ -131,6 +134,7 @@ describe('shopifyApiTypes', () => { [`./${type}.types.ts`]: { schema: `./${type}.schema.json`, plugins: ['typescript'], + config: {defaultScalarType: 'string', scalars: {JSON: 'unknown'}}, }, [`./${type}.generated.ts`]: { schema: `./${type}.schema.json`, @@ -161,6 +165,8 @@ describe('shopifyApiTypes', () => { schema: `./${type}.schema.json`, plugins: ['typescript'], config: { + defaultScalarType: 'string', + scalars: {JSON: 'unknown'}, enumsAsConst: true, }, }), @@ -187,13 +193,15 @@ describe('shopifyApiTypes', () => { schema: `./${type}.schema.json`, plugins: ['typescript'], config: { + defaultScalarType: 'string', + scalars: {JSON: 'unknown'}, enumsAsConst: false, }, }), ); }); - it('excludes config when enumsAsConst is not provided', () => { + it('uses default scalar config when enumsAsConst is not provided', () => { // GIVEN const config: ShopifyApiProjectOptions = { apiType, @@ -210,10 +218,10 @@ describe('shopifyApiTypes', () => { expect(projectConfig[`./${type}.types.d.ts`]).toEqual({ schema: `./${type}.schema.json`, plugins: ['typescript'], - // No config property expected + config: {defaultScalarType: 'string', scalars: {JSON: 'unknown'}}, }); expect(projectConfig[`./${type}.types.d.ts`]).not.toHaveProperty( - 'config', + 'config.enumsAsConst', ); }); },