Skip to content

Export BaseContext interface for strongly-typed loadContext() in _.context.ts files#1822

Open
Copilot wants to merge 10 commits intomainfrom
copilot/make-applycontext-type-available
Open

Export BaseContext interface for strongly-typed loadContext() in _.context.ts files#1822
Copilot wants to merge 10 commits intomainfrom
copilot/make-applycontext-type-available

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 10, 2026

Summary

_.context.ts constructors receive { loadContext, readJson } from the module loader with no type information, making loadContext effectively untyped. This exports a BaseContext interface from the generated types/_.context.ts so users can implement it in their _.context.ts files and get the same strongly-typed loadContext overloads already present on ApplyContext — with no runtime overhead and no implementation to inherit.

Original Prompt

_.context.ts constructors receive { loadContext, readJson } from the module loader with no type information, making loadContext effectively untyped. Export a type from the generated types file so users can annotate their constructors and get strongly-typed loadContext overloads.

Manual acceptance tests

  • The generated types/_.context.ts contains export interface BaseContext with readonly loadContext typed as ApplyContext["loadContext"] and readonly readJson
  • The generated routes/_.context.ts imports BaseContext and declares export class Context implements BaseContext with a constructor that initializes loadContext and readJson
  • In a _.context.ts that implements BaseContext, TypeScript provides typed overloads for this.loadContext (e.g. this.loadContext("/pets") resolves to PetsContext when a routes/pets/_.context.ts exists)
  • Existing _.context.ts files that do not implement BaseContext continue to work unchanged
  • Scenario, ApplyContext, and existing loadContext overloads in types/_.context.ts are unaffected

Tasks

  • generate.ts — Exports a pure BaseContext interface from buildApplyContextContent; the generated file is now written to types/_.context.ts (renamed from types/scenario-context.ts):

    export interface BaseContext {
      readonly loadContext: ApplyContext["loadContext"];
      readonly readJson: (relativePath: string) => Promise<unknown>;
    }

    loadContext is typed as ApplyContext["loadContext"] so all strongly-typed overloads (generated per discovered _.context.ts files) flow through automatically. No implementation — purely a structural contract.

  • repository.ts — Updated the default _.context.ts scaffold to import type { BaseContext } from "../types/_.context.js" and declare export class Context implements BaseContext with a constructor that assigns the interface's fields.

  • generate.test.ts — Updated assertions to verify export interface BaseContext { and its members appear in the generated types/_.context.ts output.

  • context-registry.ts — Updated a code comment that referenced the old scenario-context name.

  • docs/features/repl.md — Updated import examples and prose to reference types/_.context.ts / types/_.context.js.

  • .changeset/strongly-typed-load-context.md — Minor bump changeset updated to reference the new filename.

Copilot AI linked an issue Apr 10, 2026 that may be closed by this pull request
Copy link
Copy Markdown
Collaborator

@pmcelhaney pmcelhaney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a BaseContext type and have the generated Context class extend that.

@pmcelhaney
Copy link
Copy Markdown
Collaborator

@copilot try again

@pmcelhaney
Copy link
Copy Markdown
Collaborator

@copilot try again

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 11, 2026

@copilot try again

Done in c259be8. Replaced ContextArgs type with a BaseContext class exported from scenario-context.ts. The generated Context class now extends BaseContext, which initializes protected readonly loadContext and protected readonly readJson via its constructor — no manual constructor typing needed in user files.

Copilot AI changed the title Export ContextArgs type for strongly-typed loadContext() in _.context.ts files Export BaseContext class for strongly-typed loadContext() in _.context.ts files Apr 11, 2026
@pmcelhaney
Copy link
Copy Markdown
Collaborator

@copilot BaseContext needs to be an interface, not a class. It will not have an implementation. It just needs to define the signature of the constructor.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 11, 2026

@copilot BaseContext needs to be an interface, not a class. It will not have an implementation. It just needs to define the signature of the constructor.

Done in 8579779. BaseContext is now an interface with no implementation — just readonly loadContext and readonly readJson. The scaffold uses implements BaseContext with a constructor that initializes those fields from the args.

Copilot AI changed the title Export BaseContext class for strongly-typed loadContext() in _.context.ts files Export BaseContext interface for strongly-typed loadContext() in _.context.ts files Apr 11, 2026
Copy link
Copy Markdown
Collaborator

@pmcelhaney pmcelhaney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename scenario-context.ts to _.context.ts

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 11, 2026

Rename scenario-context.ts to _.context.ts

Done in d6a7. The generated file is now types/_.context.ts and all imports reference "../types/_.context.js" — updated across generate.ts, repository.ts, the test file, docs, and changeset.

Copilot AI requested a review from pmcelhaney April 11, 2026 01:47
@pmcelhaney pmcelhaney marked this pull request as ready for review April 11, 2026 01:48
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.

loadContext() should be strongly typed

2 participants