TypeScript 沙盒

一個用於與 TypeScript 和 JavaScript 程式碼互動的 DOM 庫,它是 TypeScript 演練場 (Playground)

的核心驅動力。你可以使用 TypeScript 沙盒來:

  • 構建類似 IDE 的體驗,供人們探索你的庫 API
  • 構建使用 TypeScript 的互動式 Web 工具,並免費獲得許多演練場開發者的使用體驗

例如,旁邊的沙盒已經獲取了 DangerJS 的型別定義,且無需對本程式碼示例進行任何修改。這是因為演練場的“自動型別獲取 (Automatic Type Acquisition)”功能預設處於開啟狀態。它還會查詢程式碼的相同引數,以及 URL 內部的索引選擇。

嘗試點選 此 URL 來檢視其實際效果。

該庫構建於 Monaco Editor 之上,提供了更高級別的 API,但仍允許透過單一的 sandbox 物件訪問所有底層 API。

你可以在以下倉庫中找到 TypeScript 沙盒的原始碼: microsoft/TypeScript-Website 單體倉庫 (mono-repo)。

正在下載沙盒...

用法

沙盒使用與 monaco-editor 相同的工具,這意味著該庫是以 AMD 包的形式釋出的,你可以使用 VSCode Loader require 它。

因為 TypeScript 網站需要它,你可以使用我們託管的副本 這裡。

快速開始

建立一個新檔案:index.html 並將此程式碼貼上到該檔案中。

<!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://typescript.lang.tw/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://playgroundcdn.typescriptlang.org/indexes/releases.json
      //
      require.config({
        paths: {
          vs: 'https://playgroundcdn.typescriptlang.org/cdn/4.0.5/monaco/min/vs',
          // vs: 'https://unpkg.com/@typescript-deploys/monaco-editor@4.0.5/min/vs',
          sandbox: 'https://typescript.lang.tw/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,
        sandboxFactory
      ) => {
        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 && sandboxFactory
        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 div #monaco-editor-embed
        const sandboxConfig = {
          text: initialCode,
          compilerOptions: {},
          domID: 'monaco-editor-embed',
        }

        const sandbox = sandboxFactory.createTypeScriptSandbox(sandboxConfig, main, window.ts)
        sandbox.editor.focus()
      })
    }

    document.body.appendChild(getLoaderScript)
  </script>
</html>

在 Web 瀏覽器中開啟 index.html 檔案,頁面頂部即會加載出同一個沙盒。

一些 API 示例

將使用者的 TypeScript 轉換為 JavaScript

const sandbox = createTypeScriptSandbox(sandboxConfig, main, ts)

// Async because it needs to go  
const js = await sandbox.getRunnableJS()
console.log(js)

獲取使用者編輯器中的 DTS

const sandbox = createTypeScriptSandbox(sandboxConfig, main, ts)

const dts = await sandbox.getDTSForCode()
console.log(dts)

發起一個 LSP 響應請求

const sandbox = 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)

使用幾種不同的 API 更改編譯器標誌

const sandbox = 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({})

高亮顯示編輯器中的部分程式碼

const sandbox = 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' },
  },
])

建立你自己的演練場。

const sandbox = createTypeScriptSandbox(sandboxConfig, main, ts)

// Use a script to make a JSON file like:
// { 
//   "file:///node_modules/types/keyboard/index.d.ts": "export const enterKey: string"
// }
//
// Where the keys are the paths, and the values are the source-code. The sandbox
// will use the node resolution lookup strategy by default.

const dtsFiles = {} 

Object.keys(dtsFiles).forEach(path => {
  sandbox.languageServiceDefaults.addExtraLib(dts[path], path);
});

該 API 主要是 monaco-editor API monaco-typescript API.