You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Monaco Editor中注册带独立extraLibs的自定义TypeScript语言?

在Monaco Editor中注册独立配置的TypeScript衍生语言实例

要实现多个隔离的TypeScript编辑器实例,核心是为每个实例注册独立的自定义语言,复用原生TS的全部能力,同时配置专属的语言服务宿主来隔离extraLibs等参数。

实现思路

  1. 复用原生TS基础配置:复制默认TypeScript的语法高亮、分词规则、语言服务逻辑,确保衍生语言和原生TS行为完全一致。
  2. 注册自定义语言ID:为每个隔离实例创建唯一的语言ID(如typescriptA),避免全局配置冲突。
  3. 独立语言服务宿主:为每个自定义语言实现专属的语言服务宿主,提供独立的extraLibs、文件系统模拟,实现配置隔离。

完整代码示例

// 复制并创建自定义TypeScript语言的核心函数
const createCustomTSLanguage = (languageId) => {
  const defaultTS = monaco.languages.typescript;

  // 1. 复用原生TS的语法高亮和语言配置
  monaco.languages.setMonarchTokensProvider(languageId, defaultTS.typescriptMonarchLanguage);
  monaco.languages.setLanguageConfiguration(languageId, defaultTS.typescriptLanguageConfiguration);

  // 2. 创建独立的语言服务宿主,用于隔离extraLibs
  const createIsolatedHost = (extraLibs = {}) => ({
    getCompilationSettings: () => ({
      target: monaco.languages.typescript.ScriptTarget.ESNext,
      module: monaco.languages.typescript.ModuleKind.CommonJS,
      allowJs: false,
    }),
    getScriptFileNames: () => [`${languageId}.ts`, ...Object.keys(extraLibs)],
    getScriptVersion: () => '1',
    getScriptSnapshot: (filename) => {
      if (filename === `${languageId}.ts`) return null; // 编辑器内容由model提供
      return monaco.languages.typescript.ScriptSnapshot.fromString(extraLibs[filename]);
    },
    getCurrentDirectory: () => '/',
    getDefaultLibFileName: (options) => defaultTS.getDefaultLibFilePath(options),
    fileExists: (filename) => filename === `${languageId}.ts` || !!extraLibs[filename],
    readFile: (filename) => {
      const snap = this.getScriptSnapshot(filename);
      return snap ? snap.getText(0, snap.getLength()) : '';
    },
    readDirectory: () => [],
  });

  // 3. 注册自定义语言及独立的语言服务
  monaco.languages.register({ id: languageId });
  monaco.languages.registerLanguageService({
    id: languageId,
    getLanguageService: (context) => {
      return defaultTS.createLanguageService({
        ...context,
        host: createIsolatedHost(context.configuration.extraLibs),
      });
    },
    getLanguageServiceDefaults: () => {
      const defaults = new monaco.languages.typescript.LanguageServiceDefaultsImpl(
        languageId,
        defaultTS.getDefaultCompilerOptions(),
        defaultTS.getDiagnosticsOptions()
      );
      // 扩展方法用于设置专属extraLibs
      defaults.setExtraLibs = (extraLibs) => {
        defaults.setCompilerOptions({ ...defaults.getCompilerOptions(), extraLibs });
      };
      return defaults;
    },
  });
};

// 注册两个隔离的TS衍生语言
createCustomTSLanguage('typescriptA');
createCustomTSLanguage('typescriptB');

// 实例化编辑器A,配置专属类型定义
const editorA = monaco.editor.create(document.getElementById('editorA'), {
  value: `const user: UserA = { id: 1, name: 'Alice', role: 'admin' };`,
  language: 'typescriptA',
});
monaco.languages.typescript.typescriptADefaults.setExtraLibs({
  '/customTypesA.d.ts': `
    interface UserA {
      id: number;
      name: string;
      role: 'admin' | 'user';
    }
  `
});

// 实例化编辑器B,配置另一份专属类型定义
const editorB = monaco.editor.create(document.getElementById('editorB'), {
  value: `const user: UserB = { uuid: '123', fullName: 'Bob', permissions: ['read', 'write'] };`,
  language: 'typescriptB',
});
monaco.languages.typescript.typescriptBDefaults.setExtraLibs({
  '/customTypesB.d.ts': `
    interface UserB {
      uuid: string;
      fullName: string;
      permissions: string[];
    }
  `
});

关键说明

  • 完全复刻TS行为:通过复用原生TS的typescriptMonarchLanguage和语言服务实现,确保语法高亮、智能提示、诊断功能和原生编辑器完全一致。
  • 配置隔离:每个自定义语言拥有独立的LanguageServiceDefaultsImpl实例,通过专属的语言服务宿主加载各自的extraLibs,不会和其他实例共享配置。
  • 扩展性:可以在createIsolatedHost中扩展更多自定义配置(如编译选项、诊断规则),实现更精细的实例隔离。

内容的提问来源于stack exchange,提问作者PeiSong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 20:03:18