--- title: Two Slash icon: material-symbols:experiment-outline createTime: 2025/10/08 11:46:49 permalink: /en/guide/markdown/twoslash/ outline: [2, 4] --- ## Overview Adds support for [TypeScript TwoSlash](https://www.typescriptlang.org/dev/twoslash/) in code blocks. Provides inline type hints within code blocks. This feature is powered by [shiki](https://shiki.style/) and [@shikijs/twoslash](https://shiki.style/packages/twoslash), and integrated in [@vuepress-plume/plugin-shikiji](https://github.com/pengzhanbo/vuepress-theme-plume/tree/main/plugins/plugin-shikiji). ::: important __twoslash__ is an advanced feature that requires proficiency in [TypeScript](https://www.typescriptlang.org/) and understanding of [twoslash syntax](https://twoslash.netlify.app/). ::: ::: warning `twoslash` is a relatively time-consuming feature. Since it requires type compilation of code, if the code imports large packages, it can take considerable time. Specifically, since VuePress pre-compiles all markdown files on startup, this directly affects VuePress startup time. If you include many `twoslash` code blocks, this may significantly increase VuePress startup time. For example, without `twoslash`, VuePress startup time typically ranges from `300ms ~ 1000ms`. With `twoslash`, compiling a single `twoslash` code block may require an additional `500ms` or more. However, don't worry about compilation time during markdown file hot updates. The theme optimizes code highlighting compilation time - even if a single markdown file contains multiple code blocks, the theme only compiles __modified code blocks__, so hot updates remain fast. ::: [twoslash](https://twoslash.netlify.app/) is a `JavaScript` and `TypeScript` markup language. You can write code examples that describe entire `JavaScript` projects. `twoslash` treats __double-slash comments__ (`//`) as preprocessor directives for code examples. `twoslash` uses the same compiler APIs as text editors to provide type-driven hover information, accurate errors, and type annotations. ## Feature Preview Hover over __variables__ or __functions__ to see the effect: ```ts twoslash import { createHighlighter } from 'shiki' const highlighter = await createHighlighter({ themes: ['nord'], langs: ['javascript'] }) // ^? // // @log: Custom log message const a = 1 // @error: Custom error message const b = 1 // @warn: Custom warning message const c = 1 // @annotate: Custom annotation message ``` ## Configuration ### Enabling the Feature Before enabling this feature, you need to install the `@vuepress/shiki-twoslash` package: ::: npm-to ```sh npm i @vuepress/shiki-twoslash ``` ::: Enable the `twoslash` option in the theme configuration. ```ts title=".vuepress/config.ts" export default defineUserConfig({ theme: plumeTheme({ codeHighlighter: { twoslash: true, }, }), }) ``` ::: important For most users, `twoslash` is not a necessary feature, and `twoslash`-related dependencies have large package sizes. Therefore, all `twoslash` implementations have been moved to `@vuepress/shiki-twoslash`, which effectively reduces the initial installation size of the theme. You only need to install `@vuepress/shiki-twoslash` when you require the `twoslash` feature. ::: ### Importing Type Files from `node_modules` The main feature of __twoslash__ is type compilation of code blocks, which natively supports importing type files from your project's `node_modules`. For example, if you need type hints for `express`, you need to install the `@types/express` dependency in your project: ::: npm-to ```sh npm i -D @types/express ``` ::: Then, you can use `express` types in code blocks as follows: ```` md ```ts twoslash import express from 'express' const app = express() ``` ```` ### Importing Local Type Files For importing local type files, since it's difficult to determine the real path of code in code blocks during compilation, it's not intuitive to import type files via __relative paths__ in code blocks. #### Reading Path Mappings from `tsconfig.json` The theme supports reading path mappings from `compilerOptions.paths` in `tsconfig.json` at the project root to solve this issue. Assume your project's `tsconfig.json` is configured as follows: ```json title="tsconfig.json" { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] } } } ``` You can directly use paths starting with `@/` in code blocks to import type files from the `src` directory: ````md ```ts twoslash import type { Foo } from '@/foo' const foo: Foo = 1 ``` ```` #### Reading Path Mappings from `shiki.twoslash` You can configure `compilerOptions` in `shiki.twoslash` to solve this issue: ```ts title=".vuepress/config.ts" import path from 'node:path' export default defineUserConfig({ theme: plumeTheme({ codeHighlighter: { twoslash: { compilerOptions: { // [!code hl:8] paths: { // Relative to working directory `process.cwd()` '@/*': ['./src/*'], // Using absolute paths '@@/*': [path.resolve(process.cwd(), './src/*')], } } } }, }), }) ``` You can directly use paths starting with `@/` in code blocks to import type files from the `src` directory: ````md ```ts twoslash import type { Foo } from '@/foo' const foo: Foo = 1 ``` ```` ::: important Using `plugins.shiki.twoslash.compilerOptions` allows more flexible configuration of type compilation. You can modify `baseUrl` and other configuration options here. [Refer to CompilerOptions](https://www.typescriptlang.org/tsconfig/#compilerOptions) Usually you only need to configure the `paths` option, keeping other options default unless you understand what you're configuring. ::: ## Usage ::: warning `twoslash` only supports `typescript` and `vue` code blocks. ::: After enabling this feature, simply add the `twoslash` keyword after the code language declaration in your existing markdown code block syntax: ````md{1} ```ts twoslash const a = 1 ``` ```` The theme only processes code blocks with the `twoslash` keyword. ## Syntax Reference Complete syntax reference: [ts-twoslasher](https://github.com/microsoft/TypeScript-Website/tree/v2/packages/ts-twoslasher) and [shikijs-twoslash](https://twoslash.netlify.app/) `twoslash` treats __double slashes__ as preprocessor directives for code examples. Therefore, all annotations are added after `//`. ### Symbol Annotations Common `twoslash` annotations: #### `^?` {#extract-type} Use `^?` to extract type information for specific identifiers on the code line above it. __Input:__ ````md ```ts twoslash const hi = 'Hello' const msg = `${hi}, world` // ^? ``` ```` __Output:__ ```ts twoslash const hi = 'Hello' const msg = `${hi}, world` // ^? // ``` ::: important The symbol `^` must correctly point to the variable whose type you want to highlight. ::: #### `^|` {#completions} Use `^|` to extract autocompletion information at a specific position. __Input:__ ````md ```ts twoslash // @noErrors console.e // ^| ``` ```` __Output:__ ```ts twoslash // @noErrors console.e // ^| // ``` ::: important The symbol `^` must correctly point to the position where you want content prediction. ::: Twoslash requests TypeScript for autocompletion suggestions at the `^` position, then filters possible outputs based on letters after the `.`. Up to 5 inline results are displayed, and if a completion item is marked as deprecated, the output reflects this. In this case, Twoslash requests completion suggestions for `console` from TypeScript, then filters for items starting with `e`. Note the `// @noErrors` compiler flag is set because `console.e` is a failing TypeScript code example, but we don't care about that. #### `^^^` {#highlighting} Use `^^^` to highlight specific ranges on the line above it. __Input:__ ````md ```ts twoslash function add(a: number, b: number) { // ^^^ return a + b } ``` ```` __Output:__ ```ts twoslash function add(a: number, b: number) { // ^^^ return a + b } ``` ::: important Use consecutive `^` symbols to correctly point to the range you want to highlight. ::: ### `@filename` {#import-files} `@filename: ` declares which file subsequent code will come from. You can import this file via `import` in other parts of the code. __Input:__ ````md ```ts twoslash // @filename: sum.ts export function sum(a: number, b: number): number { return a + b } // @filename: ok.ts import { sum } from './sum' sum(1, 2) // @filename: error.ts // @errors: 2345 import { sum } from './sum' sum(4, 'woops') ``` ```` __Output:__ ```ts twoslash // @filename: sum.ts export function sum(a: number, b: number): number { return a + b } // @filename: ok.ts import { sum } from './sum' sum(1, 2) // @filename: error.ts // @errors: 2345 import { sum } from './sum' sum(4, 'woops') ``` ### Code Cutting #### `---cut-before---` {#cut-before} After TypeScript generates the project and extracts all editor information (like identifiers, queries, highlights, etc.), cutting operations adjust all offsets and line numbers to fit the smaller output. Users see content below `// ---cut-before---`. The shorthand `// ---cut---` is also supported. __Input:__ ````md ```ts twoslash const level: string = 'Danger' // ---cut--- console.log(level) ```` __Output:__ ```ts twoslash const level: string = 'Danger' // ---cut--- console.log(level) ``` Show only a single file: __Input:__ ````md ```ts twoslash // @filename: a.ts export const helloWorld: string = 'Hi' // ---cut--- // @filename: b.ts import { helloWorld } from './a' console.log(helloWorld) ``` ```` __Output:__ ```ts twoslash // @filename: a.ts export const helloWorld: string = 'Hi' // ---cut--- // @filename: b.ts import { helloWorld } from './a' console.log(helloWorld) ``` Only the last two lines are displayed, but to TypeScript, this is a program with two files, and all IDE information is correctly connected between files. This is why `// @filename: [file]` is the only Twoslash command not removed, as it can be `---cut---` if irrelevant. #### `---cut-after---` {#cut-after} The sibling of `---cut-before---`, used to trim everything after the symbol: __Input:__ ````md ```ts twoslash const level: string = 'Danger' // ---cut-before--- console.log(level) // ---cut-after--- console.log('This is not shown') ``` ```` __Output:__ ```ts twoslash const level: string = 'Danger' // ---cut-before--- console.log(level) // ---cut-after--- console.log('This is not shown') ``` #### `---cut-start---` and `---cut-end---` {#cut-start-end} You can also use the `---cut-start---` and `---cut-end---` pair to cut code segments between two symbols. __Input:__ ````md ```ts twoslash const level: string = 'Danger' // ---cut-start--- console.log(level) // This part is cut // ---cut-end--- console.log('This is shown') ``` ```` __Output:__ ```ts twoslash const level: string = 'Danger' // ---cut-start--- console.log(level) // This part is cut // ---cut-end--- console.log('This is shown') ``` Multiple instances are supported to cut multiple sections, but symbols must appear in pairs. ### Custom Output Messages {id=twoslash-custom-message} `@log`, `@error`, `@warn`, and `@annotate` output custom messages at different levels to users. ````md ```ts twoslash // @log: Custom log message const a = 1 // @error: Custom error message const b = 1 // @warn: Custom warning message const c = 1 // @annotate: Custom annotation message ``` ```` ```ts twoslash // @log: Custom log message const a = 1 // @error: Custom error message const b = 1 // @warn: Custom warning message const c = 1 // @annotate: Custom annotation message ``` ### Output Compiled Files Running Twoslash code examples triggers full TypeScript compilation runs that create files in a virtual file system. You can replace code example content with results from running TypeScript on the project. #### `@showEmit` `// @showEmit` is the primary command to tell Twoslash you want to replace the code example output with the equivalent `.js` file. __Input:__ ````md ```ts twoslash // @showEmit const level: string = 'Danger' ``` ```` __Output:__ ```ts twoslash // @showEmit const level: string = 'Danger' ``` The result shows the `.js` file corresponding to this `.ts` file. You can see TypeScript output removes `: string` and adds `export {}`. #### `@showEmittedFile: [file]` While `.js` files may be the most useful out of the box, TypeScript does emit other files (`.d.ts` and `.map`) when proper flags are enabled, and with multi-file code examples, you may need to tell Twoslash which file to display. For all these cases, you can also add `@showEmittedFile: [file]` to tell Twoslash which file you want to display. __Display `.d.ts` file for TypeScript code example:__ __Input:__ ````md ```ts twoslash // @declaration // @showEmit // @showEmittedFile: index.d.ts export const hello = 'world' ``` ```` __Output:__ ```ts twoslash // @declaration // @showEmit // @showEmittedFile: index.d.ts export const hello = 'world' ``` __Display `.map` file from JavaScript to TypeScript:__ __Input:__ ````md ```ts twoslash // @sourceMap // @showEmit // @showEmittedFile: index.js.map export const hello = 'world' ``` ```` __Output:__ ```ts twoslash // @sourceMap // @showEmit // @showEmittedFile: index.js.map export const hello = 'world' ``` __Display `.map` for `.d.ts` files (mainly for project references):__ __Input:__ ````md ```ts twoslash // @declaration // @declarationMap // @showEmit // @showEmittedFile: index.d.ts.map export const hello: string = 'world' ``` ```` __Output:__ ```ts twoslash // @declaration // @declarationMap // @showEmit // @showEmittedFile: index.d.ts.map export const hello: string = 'world' ``` __Generate `.js` file for `b.ts`:__ __Input:__ ````md ```ts twoslash // @showEmit // @showEmittedFile: b.js // @filename: a.ts export const helloWorld: string = 'Hi' // @filename: b.ts import { helloWorld } from './a' console.log(helloWorld) ``` ```` __Output:__ ```ts twoslash // @showEmit // @showEmittedFile: b.js // @filename: a.ts export const helloWorld: string = 'Hi' // @filename: b.ts import { helloWorld } from './a' console.log(helloWorld) ``` ### `@errors` `@errors: ` shows how code produces errors: __Input:__ ````md ```ts twoslash // @errors: 2322 2588 const str: string = 1 str = 'Hello' ```` __Output:__ ```ts twoslash // @errors: 2322 2588 const str: string = 1 str = 'Hello' ``` You need to declare corresponding TypeScript error codes after `@errors`. Separate multiple error codes with spaces. ::: note If you don't know which error code to add, try writing the code first and wait for compilation to fail. You should see relevant error information in the console, then find the corresponding error code in the error message's `description`. Then add the error code to `@errors`. Don't worry about compilation failures terminating the process - the theme displays error information when compilation fails while outputting uncompiled code in the code block. ::: ### `@noErrors` Suppresses all errors in code. You can also provide error codes to suppress specific errors. __Input:__ ````md ```ts twoslash // @noErrors const str: string = 1 str = 'Hello' ``` ```` __Output:__ ```ts twoslash // @noErrors const str: string = 1 str = 'Hello' ``` ### `@noErrorsCutted` Ignores errors occurring in cut code. __Input:__ ````md ```ts twoslash // @noErrorsCutted const hello = 'world' // ---cut-after--- hello = 'hi' // Should be an error but ignored because it's cut. ``` ```` __Output:__ ```ts twoslash // @noErrorsCutted const hello = 'world' // ---cut-after--- hello = 'hi' // Should be an error but ignored because it's cut. ``` ### `@noErrorValidation` Disables error validation. Error messages will still render, but Twoslash won't throw errors from compile-time code. __Input:__ ````md ```ts twoslash // @noErrorValidation const str: string = 1 ``` ```` __Output:__ ```ts twoslash // @noErrorValidation const str: string = 1 ``` ### `@keepNotations` Tells Twoslash not to remove any comments and keep original code unchanged. Nodes will contain position information of original code. __Input:__ ````md ```ts twoslash // @keepNotations // @module: esnext // @errors: 2322 const str: string = 1 ``` ```` __Output:__ ```ts twoslash // @keepNotations // @module: esnext // @errors: 2322 const str: string = 1 ``` ### Overriding Compiler Options Use `// @name` and `// @name: value` comments to override TypeScript's [compiler options](https://www.typescriptlang.org/tsconfig#compilerOptions). These comments will be removed from output. __Input:__ ````md ```ts twoslash // @noImplicitAny: false // @target: esnext // @lib: esnext // This should throw an error, // but since we disabled noImplicitAny, it won't. const fn = a => a + 1 ``` ```` __Output:__ ```ts twoslash // @noImplicitAny: false // @target: esnext // @lib: esnext // This should throw an error, // but since we disabled noImplicitAny, it won't. const fn = a => a + 1 ```