TypeScript Sandbox
A DOM library for interacting with TypeScript and JavaScript code, which powers the heart of the TypeScript playground
You can use the TypeScript sandbox for:
- Building IDE-like experiences for people to explore your library's API
- Building interactive web tools which use TypeScript, with a lot of the Playgrounds developer experience for free
For example, the sandbox to the side has grabbed the Types for DangerJS with no modifications for this code sample. This is because the Playground's Automatic Type Acquisition is enabled by default. It will also look for the same parameters for code, and selection indexes inside the URL.
Try clicking this URL to see that in action.
This library builds on top of the Monaco Editor, providing a higher level API but offering access to all the lower-level APIs via a single sandbox
object.
You can find the code for the TypeScript Sandbox inside the microsoft/TypeScript-Website mono-repo.
Downloading Sandbox...
Usage
A sandbox uses the same tools as monaco-editor, meaning this library is shipped as an AMD bundle which you can use the VSCode Loader to require
.
Because we need it for the TypeScript website, you can use our hosted copy here. (note, we will eventually deprecate the /v2/ in all routes)
Get Started
Create a new file: index.html
and paste this code into that file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<div id="loader">Loading...</div>
<div id="monaco-editor-embed" style="height: 800px;" />
<script>
// First set up the VSCode loader in a script tag
const getLoaderScript = document.createElement('script')
getLoaderScript.src = 'https://www.typescriptlang.org/v2/js/vs.loader.js'
getLoaderScript.async = true
getLoaderScript.onload = () => {
// Now the loader is ready, tell require where it can get the version of monaco, and the sandbox
// This version uses the latest version of the sandbox, which is used on the TypeScript website
// For the monaco version you can use unpkg or the TypeSCript web infra CDN
// You can see the available releases for TypeScript here:
// https://typescript.azureedge.net/indexes/releases.json
//
require.config({
paths: {
vs: 'https://typescript.azureedge.net/cdn/3.7.3/monaco/min/vs',
// vs: 'https://unpkg.com/@typescript-deploys/monaco-editor@3.7.3/min/vs',
sandbox: 'https://www.typescriptlang.org/v2/js/sandbox',
},
// This is something you need for monaco to work
ignoreDuplicateModules: ['vs/editor/editor.main'],
})
// Grab a copy of monaco, TypeScript and the sandbox
require(['vs/editor/editor.main', 'vs/language/typescript/tsWorker', 'sandbox/index'], (
main,
_tsWorker,
tsSandbox
) => {
const initialCode = `import {markdown, danger} from "danger"
export default async function () {
// Check for new @types in devDependencies
const packageJSONDiff = await danger.git.JSONDiffForFile("package.json")
const newDeps = packageJSONDiff.devDependencies.added
const newTypesDeps = newDeps?.filter(d => d.includes("@types")) ?? []
if (newTypesDeps.length){
markdown("Added new types packages " + newTypesDeps.join(", "))
}
}
`
const isOK = main && window.ts && sandbox
if (isOK) {
document.getElementById('loader').parentNode.removeChild(document.getElementById('loader'))
} else {
console.error('Could not get all the dependencies of sandbox set up!')
console.error('main', !!main, 'ts', !!window.ts, 'sandbox', !!sandbox)
return
}
// Create a sandbox and embed it into the the div #monaco-editor-embed
const sandboxConfig = {
text: initialCode,
compilerOptions: {},
domID: 'monaco-editor-embed',
}
tsSandbox.createTypeScriptSandbox(sandboxConfig, main, window.ts).then(sandbox => {
sandbox.editor.focus()
})
})
}
document.body.appendChild(getLoaderScript)
</script>
</html>
Opening the file index.html
in a web browser will load up the same sandbox up at the top of the page.
Some examples of the API
Converting the user's TypeScript into JavaScript
const sandbox = await createTypeScriptSandbox(sandboxConfig, main, ts)
// Async because it needs to go
const js = await sandbox.getRunnableJS()
console.log(js)
Get the DTS for the user's editor
const sandbox = await createTypeScriptSandbox(sandboxConfig, main, ts)
const dts = await sandbox.getDTSForCode()
console.log(dts)
Make a request for an LSP response
const sandbox = await createTypeScriptSandbox(sandboxConfig, main, ts)
// A worker here is a web-worker, set up by monaco-typescript
// which does the computation in the background
const worker = await sandbox.getWorkerProcess()
const definitions = await client.getDefinitionAtPosition(model.uri.toString(), 6)
Change compiler flags using a few different APIs
const sandbox = await createTypeScriptSandbox(sandboxConfig, main, ts)
// Hook in to all changes to the compiler
sandbox.setDidUpdateCompilerSettings((newOptions) => {
console.log("Compiler settings changed: ", newOptions)
})
// Update via key value
sandbox.updateCompilerSetting("allowJs", true)
// Update via an object
sandbox.updateCompilerSettings({ jsx: 0 })
// Replace the compiler settings
sandbox.setCompilerSettings({})
Highlight some code in the editor
const sandbox = await createTypeScriptSandbox(sandboxConfig, main, ts)
const start = {
lineNumber: 0,
column: 0
}
const end = {
lineNumber: 0,
column: 4
}
const decorations = sandbox.editor.deltaDecorations([], [
{
range: new sandbox.monaco.Range(start.lineNumber, start.column, end.lineNumber, end.column),
options: { inlineClassName: 'error-highlight' },
},
])
The API is mainly a light shim over the monaco-editor API with the monaco-typescript API.