Skip to content

chore: enable strict: true in root tsconfig (#4683) - #10985

Merged
eddeee888 merged 4 commits into
masterfrom
claude/eager-lovelace-zw9wiy
Oct 8, 2026
Merged

eddeee888 merged 4 commits into
masterfrom
claude/eager-lovelace-zw9wiy

Conversation

@eddeee888

@eddeee888 eddeee888 commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Description

This PR turns on strict: true in the root tsconfig.json, so types:check and pnpm build now compile every package under strictNullChecks, noImplicitAny and strictPropertyInitialization. The per-package PRs listed below fixed the strict errors on master first, ending with #11039. The only source changes here are three small fixes for graphql 15: its typings make Maybe<T> T | null | undefined, so CI's graphql 15 unit-test jobs hit strict errors that 16 and 17 don't.

  • It started as a checkpoint for Consider using strict: true compiler option #4683 that was expected to fail typechecking (351 errors at the start), and tracked the per-package fix PRs. All of them have merged, so it's now mergeable.
  • Keeping strict on in the root config stops new code from reintroducing the errors.

Changes:

  • tsconfig.json: added strict: true; removed alwaysStrict: true and noImplicitThis: true, which strict already turns on; removed noImplicitAny: false and strictNullChecks: false, which opted out of strict checks.
  • Newly enabled: noImplicitAny, strictNullChecks, and strictPropertyInitialization (which only takes effect once strictNullChecks is on). TypeScript 6 already turns the other strict flags on by default.
  • graphql 15 fixes:
    • getPossibleTypes (visitor-plugin-common) accepts null, which schema.getType() returns on graphql 15. It already returned [] for it.
    • includeIntrospectionTypesDefinitions (typescript) only calls getNamedType when the field has a type.
    • The graphql-modules preset checks schemaAst.extensions before reading sources, since it's nullable on graphql 15.
  • .changeset/strict-root-tsconfig.md: patch for the 6 packages whose published declarations or behavior change. Compiling with strictNullChecks changes some inferred types in the published declarations:
    • @graphql-codegen/cli: mkdirp returns Promise<string | undefined>; the require (-r) option's default is typed never[] instead of any[].
    • @graphql-codegen/visitor-plugin-common: SchemaDefinition()/SchemaExtension() on BaseResolversVisitor and BaseTypesVisitor return null instead of any; BaseSelectionSetProcessor.typeCache is keyed by Location | undefined; SelectionSetToObject.buildSelectionSet's typeInfo can be null; getPossibleTypes accepts null; removeDescription returns nodes with description: undefined instead of any.
    • @graphql-codegen/typescript: TsIntrospectionVisitor's constructor takes pluginConfig as TypeScriptPluginConfig | undefined, DirectiveDefinition() returns null, and ObjectTypeDefinition() returns string | null.
    • @graphql-codegen/client-preset: the babel preset accepts options as ClientBabelPresetOptions | null | undefined.
    • @graphql-codegen/testing: mockGraphQLServer returns nock.Scope | null.
    • @graphql-codegen/graphql-modules-preset: a schema without extensions (graphql 15) throws the "requires to use GraphQL SDL" error instead of a TypeError.

Related #4683

Type of change

Tooling/config, plus three small source fixes for graphql 15 typings. The published changes are the types and the one error message listed above.

How Has This Been Tested?

Run on this branch (master @ 5078faf plus this PR):

  • pnpm exec tsc --noEmit -p tsconfig.json (types:check): 0 errors (351 at the start), with graphql 17 and with graphql 15
  • Build passes with graphql 17 and with graphql 15 (switched the way CI does, with scripts/match-graphql.js 15); ESM/CJS exports integrity (bob check) passes
  • dev-test generated output is unchanged (CJS and ESM)
  • Compared the emitted .d.ts files between a master build and a strict build: 10 files in 5 packages differ, all listed above
  • Unit tests with graphql 17 and with graphql 15: everything passes except tests that can't run in my sandbox (fetching graphql.org, init snapshots of the interactive prompt's ❯ symbol, and one snapshot that embeds the checkout's folder name)
  • Examples codegen: couldn't fetch a remote schema locally (the partial output differed only in formatting); covered by the "Examples - Normal" CI job

tsconfig.spec.json (tests) is not part of this PR, and CI doesn't typecheck it. It has 182 errors on master and 406 with strict on (702 at the start).

Test Environment:

  • OS: Linux
  • @graphql-codegen/...: master @ 5078faf
  • NodeJS: 22.22.0
  • graphql: 17.0.2 and 15.10.3

Per-package checklist

All fix PRs have merged. Error counts are from the start:

Further comments

Summary of the already-merged per-package PRs

None of this is in this PR's diff. It records the choices the per-package PRs made across the series, for reference:

oldVisit() in plugin-helpers now returns OldVisitDocumentResult instead of any for a DocumentNode (#10994), so definitions.filter(d => ...) callbacks no longer need their params annotated.

Types.DocumentFile.document is optional, so documents.map(v => v.document) fails TS2345 in document-nodes, typed-document-node and presets/graphql-modules. Each package skips files without a document locally, like core does (for example flatMap(d => (d.document ? [d.document] : []))), instead of asserting v.document!.

getConfigValue(value, default) in visitor-plugin-common now types value as T | null | undefined, so the result is non-nullable when a default is given (#10993).

Typing a method's params can give it an inferred return type. A bare return; then failed noImplicitReturns while strictNullChecks was still off (TS7030), so those PRs use return undefined; (#10994). A callback whose type is already set by its context, such as a graphql visit callback, can keep the bare return; because that type allows void (#10995).

#11009 widened shared types instead of adding defaults at call sites:

  • DeclarationBlock.withComment accepts undefined, so withComment(node.description?.value) needs no ?? null.
  • Types.ComplexPluginOutput.prepend/append accept null items.
  • parseEnumValues's mapOrStr and optimizeOperations's includeFragments are optional.
  • ImportSource.namespace accepts null.

#11014 typed the shared BaseTypesVisitor methods that TsVisitor overrides, instead of patching each override:

  • ParsedTypesConfig.declarationKind is NormalizedDeclarationKindConfig (Required<DeclarationKindConfig>), since normalizing always fills every kind.
  • FieldDefinition, InputValueDefinition and UnionTypeDefinition take key: string | number and parent: any as required, since oldVisit always passes them.
  • NamedType and ListType have typed key/parent/path/ancestors params.
  • ObjectTypeDefinition, EnumTypeDefinition and DirectiveDefinition return string | null, so overrides that drop a type can return null.

#11019 typed oldVisit's visitor and changed two exported plugin-helpers types:

  • oldVisit's visitor param is the exported OldVisitor instead of any: enter/leave maps keyed by AST node kind, so callbacks get a typed node. The callbacks use method syntax, so visitor classes passed as { leave: visitor } can keep narrower params such as ancestors: ASTNode[].
  • The InputValueDefinition overrides in typescript and operations take path (ReadonlyArray<string | number>) and ancestors as required, since oldVisit always passes them.
  • ProfilerEvent.cat is optional.
  • FederationMeta's ReferenceSelectionSet is { [field: string]: true | ReferenceSelectionSet }, matching nested selections such as company { taxCode }.

#11030 changed these visitor-plugin-common types:

  • BaseResolversVisitor's constructor takes additionalConfig as Partial<TPluginConfig>, which clears its TS2783 errors.
  • ScalarTypeDefinition, DirectiveDefinition and EnumTypeDefinition return string | null.
  • getAbstractMembersType's isTypenameNonOptional is optional.
  • defaultMapperType throws when defaultMapper isn't set.

#11031 changed these visitor-plugin-common types:

  • BaseDocumentsVisitor._selectionSetToObject is optional; FragmentDefinition and OperationDefinition throw when it isn't set, and FragmentDefinition throws when its type condition isn't in the schema.
  • BaseDocumentsVisitor.FragmentDefinition and ClientSideBaseVisitor.buildOperation return string | null.
  • LinkField.alias is optional, and BaseSelectionSetProcessor.typeCache is keyed by Location | undefined.
  • getPossibleTypes takes GraphQLType | undefined, and OperationVariablesToObject.transform accepts undefined.
  • SelectionSetToObject.transformSelectionSet throws when there's no selection set, and flattenSelectionSet throws when there's no parent type.

#11037 changed these visitor-plugin-common types:

  • BaseTypesVisitor's constructor takes additionalConfig as Partial<TPluginConfig>.
  • getScalarsImports uses reduce<string[]>.
  • getDirectiveArgumentAndInputFieldMappingsImports narrows its .filter with an a is string type guard, so it returns string[].
  • Nodes without fields/types/values/description are treated as empty instead of throwing.
  • The three casts it keeps have comments saying why they're needed.

#11039 changed these visitor-plugin-common types:

  • transformComment and block accept null/undefined, and buildScalars accepts an undefined scalars mapping; each already handled these.
  • DeclarationBlock's fields are typed string | null, and withBlock accepts null, which renders the same as no block.
  • ParsedEnumValuesMap's mappedValues, sourceIdentifier, sourceFile and importIdentifier accept null, which parseEnumValues already emits.
  • OperationVariablesToObject.getName, OperationVariablesToObject.transform and BaseSelectionSetProcessor.buildSelectionSetFromStrings return string | null.
  • buildTypeImport (missing identifier or source), buildEnumValuesBlock (enum value not on the schema's enum) and optimizeOperations (document file with no parsed document) throw descriptive errors.
  • OperationVariablesToObject emits '' instead of the text undefined/null when a variable has no name or no type identifier.
  • An enum node without values, a fragment import without identifiers, a @deprecated without arguments and a DeclarationBlock without a blockTransformer are treated as empty or default instead of throwing. transformMappers defaults rawMappers to {}.
  • isOneOfInputObjectType returns false instead of undefined.
  • The one cast it keeps (isOneOf in isOneOfInputObjectType) has a comment saying why.

🤖 Generated with Claude Code

@changeset-bot

changeset-bot Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 47073b0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@graphql-codegen/cli Patch
@graphql-codegen/visitor-plugin-common Patch
@graphql-codegen/typescript Patch
@graphql-codegen/client-preset Patch
@graphql-codegen/testing Patch
@graphql-codegen/graphql-modules-preset Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch from 266a52f to 21ea63c Compare September 25, 2026 00:19
@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch from 21ea63c to 1d0201e Compare September 25, 2026 00:41
@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch from 1d0201e to 9ff658e Compare September 25, 2026 04:42
@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch 2 times, most recently from 7ba78a6 to 1d22471 Compare September 27, 2026 01:16
@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch from 1d22471 to 5109be7 Compare September 30, 2026 13:38
@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch from 5109be7 to 0823873 Compare October 1, 2026 14:44
@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch from 0823873 to b235510 Compare October 3, 2026 14:28
@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch from b235510 to c957623 Compare October 5, 2026 15:16
Replace the individual strictness flags (`alwaysStrict`, `noImplicitThis`,
`noImplicitAny: false`, `strictNullChecks: false`) with `strict: true`.
`tsc --noEmit` now reports 351 type errors across packages/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PjJDfAYR1JPdgiQRvvZZy

eddeee888:oss:issue-verify
@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch from c957623 to f5bf60b Compare October 5, 2026 22:17
@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

🚀 Snapshot Release (alpha)

The latest changes of this PR are available as alpha on npm (based on the declared changesets):

Package Version Info
@graphql-codegen/cli 7.4.6-alpha-20261008132314-47073b09d2e11862a2b11d2ea790789b5f32c7be npm ↗︎ unpkg ↗︎
@graphql-codegen/visitor-plugin-common 7.2.10-alpha-20261008132314-47073b09d2e11862a2b11d2ea790789b5f32c7be npm ↗︎ unpkg ↗︎
@graphql-codegen/typescript 6.1.2-alpha-20261008132314-47073b09d2e11862a2b11d2ea790789b5f32c7be npm ↗︎ unpkg ↗︎
@graphql-codegen/client-preset 6.2.3-alpha-20261008132314-47073b09d2e11862a2b11d2ea790789b5f32c7be npm ↗︎ unpkg ↗︎
@graphql-codegen/graphql-modules-preset 6.1.3-alpha-20261008132314-47073b09d2e11862a2b11d2ea790789b5f32c7be npm ↗︎ unpkg ↗︎
@graphql-codegen/testing 5.0.6-alpha-20261008132314-47073b09d2e11862a2b11d2ea790789b5f32c7be npm ↗︎ unpkg ↗︎

)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eddeee888
eddeee888 force-pushed the claude/eager-lovelace-zw9wiy branch from 2b2c169 to be0e44c Compare October 8, 2026 13:07
@eddeee888 eddeee888 changed the title test: enable strict: true in root tsconfig (failing) (#4683) chore: enable strict: true in root tsconfig (#4683) Oct 8, 2026
graphql 15 types Maybe<T> as T | null | undefined, so the CI matrix's
graphql 15 build hits three strict errors that 16/17 don't:
- getPossibleTypes accepts null, which schema.getType() returns on 15
- includeIntrospectionTypesDefinitions skips getNamedType when the field
  type is missing
- graphql-modules preset checks schemaAst.extensions before reading sources

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eddeee888
eddeee888 marked this pull request as ready for review October 8, 2026 13:26
@eddeee888
eddeee888 merged commit d8aa07f into master Oct 8, 2026
22 checks passed
@eddeee888
eddeee888 deleted the claude/eager-lovelace-zw9wiy branch October 8, 2026 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants