What is Twoslash?
main@typescript/twoslash.repository·main·Indexed 21 days ago
https://github.com/twoslashes/twoslashA markup format for TypeScript code samples that enables the creation of self-contained, compiler-validated code snippets for documentation. It provides a low-level engine for extracting type information and includes specialized packages for CDN usage (twoslash-cdn), remote API delegation (twoslash-remote), and framework-specific support for Vue (twoslash-vue) and Svelte (twoslash-svelte). It is the community-driven successor to @typescript/twoslash.
@typescript/twoslash.twoslash-vue package provides extended Twoslash support specifically for Vue Single File Components (SFCs). This allows you to use Twoslash's code execution and type-checking capabilities within Vue templates and script blocks.twoslash-svelte package provides extended Twoslash support specifically for Svelte applications. It allows you to integrate Twoslash's code execution and type checking capabilities into Svelte components.twoslash-cdn package allows you to run Twoslash directly in browsers or web workers. It leverages Auto-Type-Acquisition from a CDN to handle type dependencies automatically. For detailed implementation details, refer to the official documentation.twoslash-protocol package defines the universal protocol for the Twoslash interface. It acts as a common layer to support various language services by describing standard editor features in a unified way. Additionally, the package provides utility functions to help developers work with this protocol.Since fetching files from a CDN is asynchronous, you cannot make the entire process synchronous. However, you can separate the asynchronous type fetching from the synchronous execution.
Use await twoslash.prepreTypes(code) to load all necessary types for a specific code snippet before performing synchronous operations (such as using a synchronous highlighter like Shiki). Once types are pre-loaded, you can use twoslash.runSync for the actual execution.
import { transformerTwoslash } from '@shikijs/twoslash'
import { createHighlighter } from 'shiki'
import { createTwoslashFromCDN } from 'twoslash-cdn'
const highlighter = await createHighlighter({})
const twoslash = createTwoslashFromCDN()
const code = `
import { ref } from 'vue'
const foo = ref(1)
// ^?
`
// Load all necessary types from CDN before hand.
await twoslash.prepreTypes(code)
// This can be done synchronously.
const highlighted = highlighter.codeToHtml(code, {
lang: 'ts',
theme: 'dark-plus',
transformers: [
transformerTwoslash({
// Use `twoslash.runSync` to replace the non-CDN `twoslasher` function.
twoslasher: twoslash.runSync
})
],
})Twoslash allows you to mechanically pull information from your code using specific query sigils placed on the line below the target code.
?^)Use ?^ to extract the type information of an identifier in the line immediately above it.
^|)Use ^| to show what auto-complete results would look like at a specific location. Twoslash requests completions from TypeScript and filters them based on the characters following the .. Up to 5 results are shown inline, respecting deprecation markers.
^^^)Use ^^^ to highlight a specific range of characters on the line above it. The exact visual style depends on your renderer (e.g., Shiki integrations often wrap these in a .twoslash-highlighted class).
const hi = 'Hello'
const msg = `${hi}, world`
// ^?
// Completions example
// @noErrors
console.e
// ^|
// Highlighting example
function add(a: number, b: number) {
// ^^^
return a + b
}To use Twoslash, wrap your TypeScript code in a code block with the ts twoslash language identifier. You can then use special comments to instruct the compiler to expect specific errors.
// @errors: <error-code> comment to specify which TypeScript error should be triggered in the block.// ---cut--- comment to separate code segments. This is useful when you want to reuse a variable declaration or setup from a previous block within the same Twoslash context, allowing the compiler to maintain state across the 'cut'.// @errors: 2322
let x: [string, number]
// Initialize it incorrectly
x = [10, 'hello']
// ---cut---
// The compiler remembers 'x' from above
console.log(x[1].substring(1))To keep code samples concise while maintaining a valid, compilable TypeScript program, you can use 'cut' sigils. Twoslash processes these after generating editor information, automatically adjusting offsets and lines so that queries and highlights still work in the trimmed output.
// ---cut-before--- or // ---cut---Removes everything above the sigil. Only the code below the sigil is displayed to the user.
// ---cut-after---Removes everything below the sigil.
// ---cut-start--- and // ---cut-end---Removes the section of code between these two sigils. You can use multiple pairs to cut out several sections.
Note: The // @filename: [file] command is specifically designed NOT to be removed by cutting, ensuring multi-file logic remains intact if needed.
const level: string = 'Danger'
// ---cut---
console.log(level)
// Cutting a middle section
const level: string = 'Danger'
// ---cut-start---
console.log(level) // This is not shown.
// ---cut-end---
console.log('This is shown')Twoslash itself is a low-level engine focused on extracting type information and does not handle syntax highlighting. To render code snippets with integrated type information (similar to the Twoslash website), use Shiki along with the @shikijs/twoslash transformer. This transformer integrates Twoslash's type information directly into your Shiki-highlighted code snippets.
import { transformerTwoslash } from '@shikijs/twoslash'
import { codeToHtml } from 'shiki'
const html = await codeToHtml(`console.log()`, {
lang: 'ts',
theme: 'vitesse-dark',
transformers: [
transformerTwoslash(),
],
})If you are migrating from the legacy @typescript/twoslash package, be aware that twoslash is a community-driven successor with improved performance and more flexible APIs. Several breaking changes exist:
staticQuickInfo, queries, errors, and tags, all information is now unified into a single nodes array. See the Information Nodes documentation for details.import { ... } from "twoslash" depends on the typescript package. If you want a dependency-free version, use the twoslash/core sub-entry point, which requires you to provide your own TypeScript instance.defaultOptions is now handbookOptions.defaultCompilerOptions is now compilerOptions.compilerOptions.target is now "esnext" (previously "es5").playgroundURL has been removed from the result object.To add support for Vue Single File Components (SFCs) to Twoslash, install the twoslash-vue package as a development dependency.
npm i -D twoslash-vue