# @ec-ts/vfs 中文文档

规范地址：https://npmcn.com/package/%40ec-ts/vfs/

版本：1\.0\.0
npm 元数据更新时间：2026-03-03T01:51:41.467Z
中文译文更新时间：2026-11-13T04:47:34.541Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40ec-ts/vfs
原文对照：https://npmcn.com/package/%40ec-ts/vfs/?lang=original
项目主页：https://github.com/withstudiocms/expressive-code-twoslash
源码仓库：https://github.com/withstudiocms/expressive-code-twoslash

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：78.9 kB，7 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：typescript ^5\.5\.0
- 首次发布：2026-02-23T16:09:57.348Z
- 最新版本发布：2026-03-03T01:51:41.148Z
- 近 30 天下载量：21537（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：2（近 12 个月 2 个）

## 中文简介

> 这是一个仅限无害环境管理的FFS类型 [表达式代码 二斜线](https://github.com/withstudiocms/expressive-code-twoslash)

## 安装

```sh
npm install @ec-ts/vfs
```

也可以使用：`pnpm add @ec-ts/vfs`、`yarn add @ec-ts/vfs`、`bun add @ec-ts/vfs`

## README

### 类型脚本 VFS

> 这是一个仅限无害环境管理的FFS类型 [表达式代码 二斜线](https://github.com/withstudiocms/expressive-code-twoslash)

基于地图的 TypeScript 虚拟文件系统.

需要时有用:

-   在浏览器中运行类型脚本
-   运行虚拟类型脚本环境, 磁盘上的文件不是真伪的来源

### 使用量

您首先创建一张代表虚拟中所有文件的地图 `ts.System`数字 :

```ts
import { createSystem } from "@ec-ts/vfs"

const fsMap = new Map<string, string>()
fsMap.set("index.ts", 'const a = "Hello World"')

const system = createSystem(fsMap)
```

然后可以创建虚拟类型脚本环境 :

```ts
import { createSystem, createVirtualTypeScriptEnvironment } from "@ec-ts/vfs"
import ts from "typescript"

const fsMap = new Map<string, string>()
const system = createSystem(fsMap)

const compilerOpts = {}
const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts)

// You can then interact with the languageService to introspect the code
env.languageService.getDocumentHighlights("index.ts", 0, ["index.ts"])
```

在测试中工作时,或在有文件系统访问的环境下,您可以切换您的虚拟系统 `ts.sys` 以虚拟环境使用真实文件系统.

## API 密码

你对API最感兴趣 `env.languageService`,此处为3.7.4:

```ts
interface LanguageService {
    cleanupSemanticCache(): void;
    getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
    getSemanticDiagnostics(fileName: string): Diagnostic[];
    getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[];
    getCompilerOptionsDiagnostics(): Diagnostic[];
    getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications;
    getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications;
    getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined): WithMetadata<CompletionInfo> | undefined;
    getCompletionEntryDetails(fileName: string, position: number, name: string, formatOptions: FormatCodeOptions | FormatCodeSettings | undefined, source: string | undefined, preferences: UserPreferences | undefined): CompletionEntryDetails | undefined;
    getCompletionEntrySymbol(fileName: string, position: number, name: string, source: string | undefined): Symbol | undefined;
    getQuickInfoAtPosition(fileName: string, position: number): QuickInfo | undefined;
    getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan | undefined;
    getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan | undefined;
    getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
    getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo;
    findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): readonly RenameLocation[] | undefined;
    getSmartSelectionRange(fileName: string, position: number): SelectionRange;
    getDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined;
    getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined;
    getTypeDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined;
    getImplementationAtPosition(fileName: string, position: number): readonly ImplementationLocation[] | undefined;
    getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined;
    findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined;
    getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined;
    getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[];
    getNavigationBarItems(fileName: string): NavigationBarItem[];
    getNavigationTree(fileName: string): NavigationTree;
    getOutliningSpans(fileName: string): OutliningSpan[];
    getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[];
    getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[];
    getIndentationAtPosition(fileName: string, position: number, options: EditorOptions | EditorSettings): number;
    getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[];
    getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[];
    getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[];
    getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion | undefined;
    isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean;
    getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
    getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
    toLineColumnOffset(fileName: string, position: number): LineAndCharacter;
    getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
    getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
    applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
    applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
    applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
    getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined): ApplicableRefactorInfo[];
    getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined;
    organizeImports(scope: OrganizeImportsScope, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
    getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
    getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean): EmitOutput;
    getProgram(): Program | undefined;
}
```

## 使用量

#### 与 Web 合作时

这是 **非常喜欢** 可能你需要设置你的自由 `*.d.ts` 要使用此文件的文件.

如果你是在一个环境中运行,你可以进入 `node_modules` 文件夹,然后您可以写一些这样的代码 :

```ts
const getLib = (name: string) => {
  const lib = dirname(require.resolve("typescript"))
  return readFileSync(join(lib, name), "utf8")
}

const addLib = (name: string, map: Map<string, string>) => {
  map.set("/" + name, getLib(name))
}

const createDefaultMap2015 = () => {
  const fsMap = new Map<string, string>()
  addLib("lib.es2015.d.ts", fsMap)
  addLib("lib.es2015.collection.d.ts", fsMap)
  addLib("lib.es2015.core.d.ts", fsMap)
  addLib("lib.es2015.generator.d.ts", fsMap)
  addLib("lib.es2015.iterable.d.ts", fsMap)
  addLib("lib.es2015.promise.d.ts", fsMap)
  addLib("lib.es2015.proxy.d.ts", fsMap)
  addLib("lib.es2015.reflect.d.ts", fsMap)
  addLib("lib.es2015.symbol.d.ts", fsMap)
  addLib("lib.es2015.symbol.wellknown.d.ts", fsMap)
  addLib("lib.es5.d.ts", fsMap)
  return fsMap
}
```

此列表是一组默认定义( 需要注意的是 `target` 或者说 `lib` 将会影响此列表的外观 。 您正在从 TypeScript 的本地依赖中获取库的内容 .

保持这个列表的顶部是相当多的工作,所以这个库船功能是用从磁盘上可用的版本TypeScript中预填的来生成一个地图.

注:此列表有可能随时间推移而与TypeScript脱离同步. 它最后一次与TypeScript 3.8.0-rc同步.

```ts
import { createDefaultMapFromNodeModules } from "@ec-ts/vfs"
import ts from "typescript"

const fsMap = createDefaultMapFromNodeModules({ target: ts.ScriptTarget.ES2015 })
fsMap.set("index.ts", "const hello = 'hi'")
// ...
```

如果你无法进入 `node_modules`,然后可以使用 TypeScript CDN 或 unpkg 来获取 lib 文件。 这最多可达1.5MB,你也许应该将数值存储在 `localStorage` 这样用户只需抓取一次.

这是通过 `createDefaultMapFromCDN`。 。 。 .

```ts
import { createDefaultMapFromCDN } from "@ec-ts/vfs"
import ts from "typescript"
import lzstring from "lz-string"

const start = async () => {
  const shouldCache = true
  // This caches the lib files in the site's localStorage
  const fsMap = await createDefaultMapFromCDN({ target: ts.ScriptTarget.ES2015 }, "3.7.3", shouldCache, ts)

  // This stores the lib files as a zipped string to save space in the cache
  const otherMap = await createDefaultMapFromCDN({ target: ts.ScriptTarget.ES2015 }, "3.7.3", shouldCache, ts, lzstring)

  fsMap.set("index.ts", "const hello = 'hi'")
  // ...
}

start()
```

CDN 缓存 :

-   自动清除使用不同版本 TypeScript 保存空间的项目
-   可以使用 lz- string 模块复制来压缩/解压缩 lib 文件

#### 在节点工作时

如果你能够可靠地访问文件系统,那么你就可以有更简单的时间:

```ts
const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true }
const fsMap = new Map<string, string>()

// If using imports where the types don't directly match up to their FS representation (like the
// imports for node) then use triple-slash directives to make sure globals are set up first.
const content = `/// <reference types="node" />\nimport * as path from 'path';\npath.`
fsMap.set("index.ts", content)

// By providing a project root, then the system knows how to resolve node_modules correctly
const projectRoot = path.join(__dirname, "..")
const system = createFSBackedSystem(fsMap, projectRoot)
const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts)

// Requests auto-completions at `path.|`
const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {})
```

`createFSBackedSystem` 将会让您在文件系统上方的某个特定路径上徘徊一个虚拟环境.

### 一个完整的例子

完整的例子是什么样子的? 这基本上来自TypeScript Sandbox 代码库:

```ts
import ts from "typescript"
import tsvfs from "@ec-ts/vfs"
import lzstring from "lz-string"

const fsMap = await tsvfs.createDefaultMapFromCDN(compilerOptions, ts.version, true, ts, lzstring)
fsMap.set("index.ts", "// main TypeScript file content")

const system = tsvfs.createSystem(fsMap)
const host = tsvfs.createVirtualCompilerHost(system, compilerOptions, ts)

const program = ts.createProgram({
  rootNames: [...fsMap.keys()],
  options: compilerOptions,
  host: host.compilerHost,
})

// This will update the fsMap with new files
// for the .d.ts and .js files
program.emit()

// Now I can look at the AST for the .ts file too
const index = program.getSourceFile("index.ts")
```

## 常见问题

### @ec-ts/vfs 是什么？

这是一个仅限无害环境管理的FFS类型 表达式代码 二斜线

### 如何安装 @ec-ts/vfs？

在项目目录运行 npm install @ec-ts/vfs，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：typescript（^5\.5\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @ec-ts/vfs 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @ec-ts/vfs 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @ec-ts/vfs 可以商用吗？

@ec-ts/vfs 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @ec-ts/vfs 的下载量有多少？

根据 npm 官方下载统计，@ec-ts/vfs 在 2026/10/13 – 2026/11/11 这 30 天内被下载 21,537 次，日均约 718 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @ec-ts/vfs 还在维护吗？

最新版本 1\.0\.0 发布于 2026/03/03（8 个月前）；至今共发布 2 个版本，其中过去 12 个月发布了 2 个；首次发布于 2026/02/24。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

