Skip to content

shikiji-twoslash

NPM versionNPM downloadsGitHub

A Shikiji transformer for TypeScript TwoSlash, provide inline type hover inside code blocks. Inspired by shiki-twoslash.

Install

bash
npm i -D shikiji-twoslash

Unlike shiki-twoslash that wraps around shiki, this package is a transformer addon to Shikiji. This means that for every integration that supports shikiji transformers, you can use this package.

ts
import {
  codeToHtml(alias) const codeToHtml: (code: string, options: CodeToHastOptions<BuiltinLanguage, BuiltinTheme>) => Promise<string>
import codeToHtml,
} from 'shikiji'
import {
  transformerTwoSlash(alias) const transformerTwoSlash: (options?: TransformerTwoSlashOptions) => shikiji_core.ShikijiTransformer
import transformerTwoSlash,
} from 'shikiji-twoslash'

const htmlconst html: string = await codeToHtml(alias) codeToHtml(code: string, options: CodeToHastOptions<BuiltinLanguage, BuiltinTheme>): Promise<string>
import codeToHtml(`console.log()`, {
  lang(property) lang: "ts": 'ts',
  theme(property) CodeOptionsSingleTheme<BuiltinTheme>.theme: ThemeRegistration | ThemeRegistrationRaw | StringLiteralUnion<BuiltinTheme, string>: 'vitesse-dark',
  transformers(property) transformers: ShikijiTransformer[]: [
    transformerTwoSlash(alias) transformerTwoSlash(options?: TransformerTwoSlashOptions | undefined): ShikijiTransformer
import transformerTwoSlash(), // <-- here
    // ...
  ],
})

Same as shiki-twoslash, the output is unstyled. You need to add some extra CSS to make them look good.

Renderers

Thanks to the flexibility of hast, this transformer allows customizing how each piece of information is rendered in the output HTML with ASTs.

We provide two renderers built-in, while you can also create your own:

rendererClassic

Source code

This is the default renderer that aligns with the output of shiki-twoslash.

You might need to reference shiki-twoslash's CSS to make them look good. Here we also copied the CSS from shiki-twoslash but it might need some cleanup.

rendererRich

Source code

This renderer provides a more explicit class name that is always prefixed with twoslash- for better scoping. In addition, it runs syntax highlighting on the hover information as well.

ts
import { rendererRich(alias) function rendererRich(options?: RendererRichOptions): TwoSlashRenderers
import rendererRich, transformerTwoSlash(alias) const transformerTwoSlash: (options?: TransformerTwoSlashOptions) => shikiji_core.ShikijiTransformer
import transformerTwoSlash } from 'shikiji-twoslash'

transformerTwoSlash(alias) transformerTwoSlash(options?: TransformerTwoSlashOptions | undefined): ShikijiTransformer
import transformerTwoSlash({
  renderer(property) TransformerTwoSlashOptions.renderer?: TwoSlashRenderers | undefined: rendererRich(alias) rendererRich(options?: RendererRichOptions | undefined): TwoSlashRenderers
import rendererRich() // <--
})

Here is a few examples with the built-in style-rich.css:

ts
interface Todointerface Todo {
  title(property) Todo.title: string: string
}

const todoconst todo: Readonly<Todo>: Readonlytype Readonly<T> = { readonly [P in keyof T]: T[P]; }<Todointerface Todo> = {
  title
(property) title: string
: 'Delete inactive users'.toUpperCase(method) String.toUpperCase(): string(),
} todoconst todo: Readonly<Todo>.title = 'Hello'
Cannot assign to 'title' because it is a read-only property.
Numbervar Number: NumberConstructor.p
  • parseFloat
  • parseInt
  • prototype
arseInt
('123', 10)
// //
ts
import { getHighlighterCore(alias) function getHighlighterCore(options?: HighlighterCoreOptions): Promise<HighlighterCore>
import getHighlighterCore } from 'shikiji/core'

const shikiconst shiki: HighlighterCore = await getHighlighterCore(alias) getHighlighterCore(options?: HighlighterCoreOptions | undefined): Promise<HighlighterCore>
import getHighlighterCore({})
const aconst a: 1 = 1
Custom log message
const bconst b: 1 = 1
Custom error message
const cconst c: 1 = 1
Custom warning message
Custom annotation message

Options

Explicit Trigger

When integrating with markdown-it-shikiji or rehype-shikiji, we may not want TwoSlash to run on every code block. In this case, we can set explicitTrigger to true to only run on code blocks with twoslash presented in the codeframe.

ts
import { transformerTwoSlash(alias) const transformerTwoSlash: (options?: TransformerTwoSlashOptions) => shikiji_core.ShikijiTransformer
import transformerTwoSlash } from 'shikiji-twoslash'

transformerTwoSlash(alias) transformerTwoSlash(options?: TransformerTwoSlashOptions | undefined): ShikijiTransformer
import transformerTwoSlash({
  explicitTrigger(property) TransformerTwoSlashOptions.explicitTrigger?: boolean | undefined: true // <--
})
md
In markdown, you can use the following syntax to trigger TwoSlash:

```ts
// this is a normal code block
```

```ts twoslash
// this will run TwoSlash
```

Integrations

VitePress

VitePress uses Shikiji for syntax highlighting since 1.0.0-rc.30. To use this transformer, you can add it to the markdown.codeTransformers option in your VitePress config file.

ts
// .vitepress/config.ts
import { defineConfig(alias) function defineConfig(config: UserConfig<DefaultTheme.Config>): UserConfig<DefaultTheme.Config>
import defineConfig } from 'vitepress'
import { transformerTwoSlash(alias) const transformerTwoSlash: (options?: TransformerTwoSlashOptions) => shikiji_core.ShikijiTransformer
import transformerTwoSlash } from 'shikiji-twoslash'

export default defineConfig(alias) defineConfig(config: UserConfig<DefaultTheme.Config>): UserConfig<DefaultTheme.Config>
import defineConfig({
  markdown(property) UserConfig<DefaultTheme.Config>.markdown?: MarkdownOptions | undefined: {
    codeTransformers(property) MarkdownOptions.codeTransformers?: ShikijiTransformer[] | undefined: [
      transformerTwoSlash(alias) transformerTwoSlash(options?: TransformerTwoSlashOptions | undefined): ShikijiTransformer
import transformerTwoSlash({
        explicitTrigger(property) TransformerTwoSlashOptions.explicitTrigger?: boolean | undefined: true,
      })
    ]
  },
})

Released under the MIT License.