Skip to content

Add TypeScript twoslash support to docs code blocks#729

Merged
IEvangelist merged 13 commits intomicrosoft:mainfrom
slang25:slang25/ts-twoslash
Apr 21, 2026
Merged

Add TypeScript twoslash support to docs code blocks#729
IEvangelist merged 13 commits intomicrosoft:mainfrom
slang25:slang25/ts-twoslash

Conversation

@slang25
Copy link
Copy Markdown
Contributor

@slang25 slang25 commented Apr 19, 2026

Summary

This adds Twoslash to the TypeScript snippets, which provides hovers on TypeScript snippets. The type information is generated at build time with a little script.

This provides extra context for developers looking at the functions because they can more easily discover what additional parameters can be provided, or more generally "what am I looking at here".

It's also useful because it helps keep the code snippets honest, if the code snippet and actual APIs don't align, then you get an error.

image

I am playing around with my own side-project to create a similar thing for C# code, but it is far from ready. If I get to a point where I am satisfied with a 1.0 release then I can also look to integrate this for the C# code.

slang25 and others added 3 commits April 19, 2026 15:24
Wires up expressive-code-twoslash with a generated Aspire SDK .d.ts
so TS samples get hover types. Adds the `twoslash` meta to TS code
blocks across docs and the homepage AppHostBuilder component. Also
fixes nav bar / mobile TOC stacking at ≥72rem where expressive-code's
`:root .main-pane { z-index: 1 }` was trapping the TOC below content.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Inherit class baseType from src/data/pkgs/*.json so subclasses like
ViteAppResource/NodeAppResource/PythonAppResource pick up methods defined
on their parent class (publishAsDockerFile, publishAsHostedAgent). Fix
misaligned samples (withVolume args, withHostPort, publishAsExisting,
userNameParameter/passwordParameter, executionContext.isRunMode, redis
host/port accessors). Drop twoslash marker from the hypothetical
user-integration example where types don't resolve by design.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove overflow:hidden from the outer .container so the popup
(positioned by floating-ui into the expressive-code wrapper) can extend
past the bottom edge. Top-corner rounding moves to .header to preserve
the visual against the container's rounded border.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@slang25 slang25 marked this pull request as ready for review April 19, 2026 16:24
@slang25 slang25 requested a review from IEvangelist as a code owner April 19, 2026 16:24
Copilot AI review requested due to automatic review settings April 19, 2026 16:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds Twoslash-powered TypeScript hovers to the docs site by generating a virtual Aspire TypeScript SDK type bundle at build time and enabling the expressive-code-twoslash plugin, then opting TypeScript code blocks into twoslash across the docs.

Changes:

  • Add expressive-code-twoslash integration and configure it to only run on TS fences marked with twoslash, backed by a generated virtual ./.modules/aspire.js typing file.
  • Introduce a build-time script to generate .twoslash-types/aspire.d.ts from the existing src/data/ts-modules/*.json API snapshots.
  • Update many TypeScript docs code fences to opt into twoslash, plus a few snippet adjustments to match current TS API shapes and some stacking-context CSS/workarounds for hover popups.

Reviewed changes

Copilot reviewed 39 out of 41 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/frontend/src/styles/site.css Adjust stacking order at ≥72rem to keep TOC/sidebar painting correctly alongside expressive-code.
src/frontend/src/content/docs/whats-new/aspire-13-2.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/ja/get-started/what-is-aspire.mdx Enable twoslash on TypeScript snippet.
src/frontend/src/content/docs/integrations/databases/postgres/postgres-host.mdx Enable twoslash on TypeScript snippets and update PgAdmin host port call style.
src/frontend/src/content/docs/integrations/databases/postgres/postgres-get-started.mdx Enable twoslash on TypeScript snippet.
src/frontend/src/content/docs/integrations/databases/postgres/postgres-connect.mdx Enable twoslash and update Postgres env var binding to parameter properties.
src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx Enable twoslash and update publishAsExisting call shape.
src/frontend/src/content/docs/get-started/what-is-aspire.mdx Enable twoslash on TypeScript snippet.
src/frontend/src/content/docs/get-started/resource-mcp-servers.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/get-started/first-app.mdx Enable twoslash on TypeScript snippet.
src/frontend/src/content/docs/get-started/deploy-first-app.mdx Enable twoslash on TypeScript snippets with line highlighting.
src/frontend/src/content/docs/get-started/aspire-mcp-server.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx Enable twoslash on multiple TypeScript snippets (incl. showLineNumbers case).
src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx Fix a malformed closing fence and enable twoslash on a TypeScript snippet.
src/frontend/src/content/docs/deployment/overview.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/deployment/kubernetes.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/deployment/javascript-apps.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/deployment/environments.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/deployment/docker-compose.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/deployment/azure/container-apps.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/deployment/azure/azure-security-best-practices.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/deployment/azure/azure-developer-cli.mdx Enable twoslash on TypeScript snippet.
src/frontend/src/content/docs/deployment/azure/app-service.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/community/contributor-guide.mdx Enable twoslash on TypeScript snippet.
src/frontend/src/content/docs/app-host/withdockerfile.mdx Enable twoslash and adjust TS executionContext usage in snippet.
src/frontend/src/content/docs/app-host/typescript-apphost.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/app-host/persistent-containers.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx Enable twoslash and update TS volume API usage in snippet.
src/frontend/src/content/docs/app-host/executable-resources.mdx Enable twoslash and update Redis env var sample to use typed properties.
src/frontend/src/content/docs/app-host/eventing.mdx Enable twoslash on TypeScript snippet.
src/frontend/src/content/docs/app-host/container-registry.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/app-host/container-files.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/content/docs/app-host/certificate-configuration.mdx Enable twoslash on TypeScript snippets.
src/frontend/src/components/starlight/PageTitle.astro Adjust stacking context strategy for the actions dropdown without elevating above fixed nav.
src/frontend/src/components/starlight/Head.astro Add runtime workaround script for twoslash hover popup behavior/positioning.
src/frontend/src/components/AppHostBuilder.astro Opt AppHostBuilder TS samples into twoslash and adjust container styling to avoid clipping.
src/frontend/scripts/generate-twoslash-types.ts New generator that emits .twoslash-types/aspire.d.ts from API JSON snapshots.
src/frontend/pnpm-lock.yaml Add/lock new dependencies for twoslash integration and TypeScript version changes.
src/frontend/package.json Add twoslash generator script and dependencies (expressive-code-twoslash, typescript), and wire generation into dev/build.
src/frontend/ec.config.mjs Configure expressive-code to run twoslash only when explicitly triggered and provide virtual Aspire SDK types.
.gitignore Ignore .twoslash-types/ output directory.
Files not reviewed (1)
  • src/frontend/pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/frontend/src/styles/site.css
Comment thread src/frontend/src/components/starlight/Head.astro
Comment thread src/frontend/package.json Outdated
- Add fallback value to --sl-z-index-toc var in site.css so the
  right-sidebar z-index still resolves when the CSS variable is absent
- Guard the twoslash popup-fix IIFE with window.__aspireTwoslashFixInitialized
  so document-level listeners only register once across Astro view transitions
- Downgrade typescript to ^5.9.3 to stay within the peer range declared by
  expressive-code-twoslash (^5.5.0)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 39 out of 41 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • src/frontend/pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/frontend/ec.config.mjs Outdated
Comment thread src/frontend/ec.config.mjs Outdated
- postgres-host.mdx: pass port directly to withHostPort(5050); the TS SDK
  signature takes a number, not an object
- ec.config.mjs: use canonical lib name 'es2022' instead of the filename
  'lib.es2022.d.ts' so TypeScript loads the standard library correctly
  during twoslash compilation
- ec.config.mjs: point the missing-types warning at the 'pnpm twoslash-types'
  script rather than the raw tsx invocation

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@IEvangelist IEvangelist left a comment

Choose a reason for hiding this comment

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

This is awesome, thank you @slang25! It still needs a bit of work, but I do want this for sure. And I'd love it for all languages we will eventually support, C# next though for sure.

Comment thread src/frontend/scripts/generate-twoslash-types.ts
Comment thread src/frontend/ec.config.mjs Outdated
// Virtual files merged into the Twoslash VFS. The Aspire SDK types
// are declared at `.modules/aspire.ts` so docs samples that import
// `'./.modules/aspire.js'` resolve against the real API surface.
extraFiles: {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we also include other common bits, like Date? Saw this when reviewing all of the codeblocks where twoslash was added.

Image

Comment thread src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx Outdated
Comment thread src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx Outdated
Comment on lines +158 to +159
.withEnvironment("REDIS_HOST", redis.host)
.withEnvironment("REDIS_PORT", redis.port);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is wrong, but to be fair - the code that was there before was actually also wrong. 🤣 I'm happy this is surfacing some other issues as well.

Comment thread src/frontend/src/content/docs/app-host/executable-resources.mdx Outdated
slang25 and others added 3 commits April 20, 2026 18:51
…egration-authoring.mdx

Co-authored-by: David Pine <david.pine@microsoft.com>
…pose.mdx

Co-authored-by: David Pine <david.pine@microsoft.com>
…pose.mdx

Co-authored-by: David Pine <david.pine@microsoft.com>
@IEvangelist
Copy link
Copy Markdown
Member

Hey @slang25 are you on our discord? I wanted to chat about something with you and figured that might be faster, if not - no big deal?

@slang25
Copy link
Copy Markdown
Contributor Author

slang25 commented Apr 20, 2026

Hey @slang25 are you on our discord? I wanted to chat about something with you and figured that might be faster, if not - no big deal?

I sure am, ping me when you are free, I'll be off by the end of the hour

slang25 and others added 5 commits April 20, 2026 19:30
- generate-twoslash-types.ts: type the JSON.parse results so the
  @typescript-eslint/no-unsafe-* rules pass (previously failed CI)
- Add tests/unit/twoslash-types-generator.vitest.test.ts covering the
  key shape of aspire.d.ts (createBuilder, IDistributedApplicationBuilder,
  class inheritance from pkgs/, camelCasing, options-object overloads)
  and wire test:unit:twoslash-types into the test:unit pipeline
- ec.config.mjs: drop the explicit `lib` array — twoslash's VFS only
  loads the lib files literally named in `lib`, so triple-slash
  references inside lib.es2022.d.ts (es5 → Date, dom → URL, etc.) were
  silently dropped. Letting `target: ESNext` pick lib.esnext.full.d.ts
  restores the full standard library. Also remove the now-redundant
  console.d.ts shim
- multi-language-integration-authoring.mdx: drop `twoslash` flag from
  the apphost.ts sample — the article shows authoring custom exported
  APIs that aren't part of the generated .d.ts, so the sample correctly
  uses hypothetical types
- executable-resources.mdx: publishAsDockerFile() takes no args
- migrate-from-docker-compose.mdx: switch withVolume() calls to the
  options-object overload as suggested

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
execFileSync('pnpm', ...) fails on Windows with ENOENT because spawn doesn't resolve .cmd shims. Invoke tsx directly via node instead, which also sidesteps the DEP0190 warning from shell:true.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests were flaking in CI (4-5 flaky + 1 failed each run) because playwright's webServer was running astro dev, and this PR's twoslash processing makes first-request page loads expensive. Under 2 parallel workers, concurrent requests for twoslash pages pegged the dev server, causing unrelated page.goto calls (e.g. on / and /get-started/install-cli/) to exceed the 30s test timeout.

Switch CI to astro preview (dist/ already exists from the Build frontend step) so pages are served as static files. Kept astro dev for local dev so interactive work doesn't require a rebuild. Also bumped per-test timeout to 60s as a safety net against any residual slow pages.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After switching CI's playwright webServer to astro preview, the 6 cookie-consent e2e tests began failing because hideFromBots in config/cookie.config.ts is evaluated at build time (read by astro.config.mjs at static build). Previously astro dev was started by playwright with E2E_TESTS=1 set, so the flag flipped correctly; under preview, the env has to be set during the preceding build step.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@IEvangelist IEvangelist enabled auto-merge (squash) April 21, 2026 04:10
@IEvangelist IEvangelist merged commit df64bc5 into microsoft:main Apr 21, 2026
6 checks passed
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.

3 participants