Note
Working in progress, breaking changes are expected.
A fork and rewrite of @typescript/twoslash
, with improvements:
- Unified information interface, consistent and easier to manipulate.
createTwoslasher
to create a twoslash instance with cached language servers (🚀 5-20 times faster!)- ESM-first, dual CJS/ESM builds.
- Lighter, no longer deps on
lz-string
anddebug
. - Additional options for better custom language support (e.g.
twoslash-vue
)
Breaking changes from @typescript/twoslash
:
- The returned items have different signatures, and different types of the items (
staticQuickInfo
,queries
,errors
,tags
) are now unified into a single arraynodes
. Learn more at the Information Nodes section. - Main entry point
import "twoslashes"
bundlestypescript
, while a new sub-entryimport "twoslashes/core"
is dependency-free and requires providing your own typescript instance. defaultOptions
is renamed tohandbookOptions
defaultCompilerOptions
is renamed tocompilerOptions
TwoSlash runs a TypeScript language server to get the information, which could be a heavy operation to load and parse all the files it needs. In repetitive usages, you may not want to initialize the language server every simple time. TwoSlashes provides a createTwoSlasher
factory function allows you to cache the language servers and reuse the already initialized files.
import { createTwoSlasher } from 'twoslashes'
const twoslasher = createTwoSlasher({
// you can have some default options here
})
const result1 = twoslasher('import { ref } from "vue"', 'ts')
// the second time will be much faster as the types from `vue` is already
const result2 = twoslasher('import { computed } from "vue"', 'ts')
This would result in a 5-20 times faster performance in repetitive usage.
To avoid getting interference across runs, it will reuse the language server with the same compilerOptions
. Internally it holds a map of hashed compilerOptions
to the language server instances.
You can retrieve the cached map and clear it when necessary, to avoid memory leaks:
import { createTwoSlasher } from 'twoslashes'
const twoslasher = createTwoSlasher()
// do something
// Clear the cached language servers, free the memory
twoslasher.getCacheMap()?.clear()
TwoSlashes returns all types of information in the nodes
array.
With some common properties:
type
: the type of the node. Can behover
,query
,error
,tag
,highlight
orcompletion
- was
kind
in@typescript/twoslash
for some entries
- was
start
: the 0-indexed start position of the node in the output codeline
: a 0-indexed line number of the node in the output codecharacter
: a 0-indexed character number of the node in the output code- was
offset
in@typescript/twoslash
for some entries
- was
length
: length of the node
For different types of nodes, they have some extra properties:
text
: the text of the hover, usually the type information of the given nodedocs
: the jsdoc of the given node, can beundefined
Same as hover
text
: the extra annotation text of the highlight, can beundefined
completion
: the completion entriescompletionPrefix
: the prefix of the completion
text
: the error message- was
renderedMessage
in@typescript/twoslash
- was
level
: the error level- was
category
in@typescript/twoslash
- was
code
: TypeScript error codeid
: a generated based on the code and position of the error
text
: the text of the tag- was
annotation
in@typescript/twoslash
- was
To make it easier to access, we also provide some getters shortcuts to each type of the nodes:
export interface TwoSlashReturn {
/** The output code */
code: string
/**
* Nodes containing various bits of information about the code
*/
nodes: TwoSlashNode[]
/** Getters */
get hovers(): NodeHover[] // was `staticQuickInfos`
get queries(): NodeQuery[] // was `queries` with `kind: 'query'`
get completions(): NodeCompletion[] // was `queries` with `kind: 'completion'`
get errors(): NodeError[]
get highlights(): NodeHighlight[]
get tags(): NodeTag[]
/**
* The meta information
*/
meta: TwoSlashReturnMeta
}
To make it easier to migrate from @typescript/twoslash
, TwoSlashes provides a backward compatibility layer that allows you to use the old interface with the new implementation.
import { twoslasherLegacy } from 'twoslashes'
const result = twoslasherLegacy('import { ref } from "vue"', 'ts')
console.log(result.staticQuickInfos) // the old interface
You can also compose it your own by only converting the return value:
import { convertLegacyReturn, twoslasher } from 'twoslashes'
const result = twoslasher('import { ref } from "vue"', 'ts') // new interface
const legacy = convertLegacyReturn(result) // <--
console.log(legacy.staticQuickInfos) // the old interface
In addition to the options provided by @typescript/twoslash
, TwoSlashes provides some additional options:
Tell TwoSlash to not remove any notations, and keep the original code untouched. The nodes
will have the position information of the original code. Useful for better source mapping combing with meta.removals
.
Default: false
Ignore errors that occurred in the cutted code.
Default: false
An additional meta
property is returned providing additional information about the result.
The list of options flag notation that is detected from the code.
A list of the index ranges of the code removed by TwoSlash from the original code, useful for better source mapping.
The final resolved compilerOptions
The final resolved handbookOptions
Benchmark generated at 2024-01-11
twoslashes - bench/compare.bench.ts > compiler_errors.ts
18.28x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > compiler_flags.ts
20.41x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > completions.ts
11.08x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > cuts_out_unnecessary_code.ts
9.72x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > errorsWithGenerics.ts
11.08x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > highlighting.ts
10.90x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > import_files.ts
6.62x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > importsModules.ts
6.06x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > multiFileErrors.ts
4.35x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > query.ts
13.15x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > arbitraryCommands.ts
10.98x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > crossExports.ts
6.16x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > cut_file_errors.ts
10.34x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > cut_files.ts
13.73x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > handlesJSON.ts
4.16x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > inlineHighlights.ts
13.28x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > large-cut.ts
10.23x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > lib.ts
12.57x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > multiLookups.ts
11.82x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > queriesWithSpaceBefore.ts
12.51x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > queryHandlesNoToken.ts
10.36x faster than @typescript/twoslash
twoslashes - bench/compare.bench.ts > twoliner.ts
6.58x faster than @typescript/twoslash
MIT License © Microsoft Corporation
MIT License © 2023-PRESENT Anthony Fu