Documentation
This test case checks if @ts-expect-error comment works as expected.
// @ts-expect-error
const a: string = 42;
这段代码块的技术要点在于 `@ts-expect-error` 注释的语义(TypeScript 标准行为,Deno 的本地类型检查遵循同样规则):
1. 注释**必须紧邻错误行上方**(本例中直接位于 `const a: string = 42;` 上一行),其作用是抑制下一行代码的类型错误;
2. 如果下一行实际上没有类型错误,`@ts-expect-error` 本身会触发 `Unused '@ts-expect-error' directive` 报错——因此该注释同时是一个“双向断言”:既声明此处应当出错,又防止错误消失后无人察觉;
3. `const a: string = 42;` 是刻意的类型错误(`number` 不能赋给 `string`),有注释在时检查通过;若删除注释,`deno test --doc` 会在类型检查阶段失败。
这正是该用例的验证目标:doc 测试提取出的代码块在送入类型检查器时,`@ts-expect-error` 注释必须被原样保留并生效。若提取过程丢弃了注释(早期版本曾出现过类似问题),类型检查将直接报 `Type 'number' is not assignable to type 'string'`。
## 用例的驱动方式:`__test__.jsonc` 规格声明
同目录下的 [__test__.jsonc](https://gitcode.com/GitHub_Trending/de/deno/blob/e5575e2c0ac3c6ea5281d685bab4c33be8c8b38d/tests/specs/test/markdown_ts_expect_error/__test__.jsonc?utm_source=gitcode_repo_files) 是该规格测试的执行声明:
```jsonc
{
"args": "test --doc main.md",
"exitCode": 0,
"output": "main.out"
}
含义拆解:
args: "test --doc main.md":等价于在该目录执行deno test --doc main.md。--doc标志告诉 Deno 把目标文件当作文档处理——扫描其中所有ts /typescript 围栏代码块,将每个代码块包装成Deno.test调用,并默认对提取出的本地代码执行类型检查;exitCode: 0:类型检查通过(@ts-expect-error生效)且测试运行时无异常,进程必须以 0 退出。由于代码块本身不含Deno.test调用,--doc会为其自动生成测试包装器,代码块中的语句在测试体中执行;output: "main.out":声明期望的 stdout/stderr 对照基准,供 Deno 的 specs 集成测试框架比对输出。
Deno 的 specs 测试框架(由 tests/specs 下各目录驱动)会在真实构建出的 Deno 二进制上回放这些声明,因此这条用例同时是对 --doc 抽取器、类型检查器和测试运行器三者的端到端回归保护。
源码级原理:代码块如何被抽成独立可检查模块
Deno 的文档代码提取逻辑位于 cli/util/extract.rs。该模块的核心工作可以概括为三步:
- 扫描围栏代码块:对 Markdown(以及 JSDoc 注释块、HTML 注释等载体)识别出语言标记为
ts/typescript的代码块,并记录起止行号; - 生成带行号定位的虚拟模块:每个代码块得到一个
file:///<原路径>#起-止.ts形式的 specifier(例如file:///main.md#4-11.ts),媒体类型为 TypeScript。这个命名让类型错误信息可以精确指回源文件中的行区间; - 包装为测试:把代码块内容包进
Deno.test("<specifier>", async () => { ... })中,并按需自动导入源文件里的顶层导出(从源码结构看,抽取器会分析块内标识符与源文件导出的对应关系生成import语句,使文档示例可以直接引用同文件的函数而不必手写 import)。
extract.rs 内嵌的单元测试本身就包含与本文主题直接相关的回归用例(对应上游 issue #26728,见 extract.rs 第 1819–1845 行):
/**
* ```ts
* // @ts-expect-error: can only add numbers
* add('1', '2');
* ```
*/
export function add(first: number, second: number) {
return first + second;
}
期望生成的测试源码为:
import { add } from "file:///main.ts";
Deno.test("file:///main.ts#3-7.ts", async ()=>{
// @ts-expect-error: can only add numbers
add('1', '2');
});
可以清楚看到:@ts-expect-error 注释在“源码 → 生成模块”的转换中被逐字保留,测试包装不会剥离任何行。同一文件中针对 Markdown 输入的测试用例(extract.rs 第 1846–1871 行)则验证了 .md 文件中代码块被抽取为 file:///main.md#4-11.ts 的完整路径——这正是 markdown_ts_expect_error 规格用例所依赖的机制。
姊妹用例:JSDoc 注释中的同名验证
仓库中存在一个结构平行的用例 doc_ts_expect_error/mod.ts,它验证 JSDoc 注释块(而非 Markdown 文件)中的 @ts-expect-error:
/**
* ```ts
* import { add } from "./mod.ts";
*
* add(1, 2);
*
* // @ts-expect-error: can only add numbers
* add('1', '2');
* ```
*/
export function add(first: number, second: number) {
return first + second;
}
两者共同守住的约束是一致的:无论文档载体是 .md 还是 .ts 的 JSDoc,doc 测试抽取后代码块中的注释必须完整保留,且带 --doc 的运行默认执行类型检查,从而让 @ts-expect-error 的“此处必须出错”断言在文档语境下同样成立。
如何在本地复现与延伸
在仓库中进入用例目录即可复现(只读参考):
cd tests/specs/test/markdown_ts_expect_error
deno test --doc main.md
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00