TypeScript中interface与type的核心区别及选型规则

这个问题在技术社区里被问到的频率,我估计仅次于闭包和事件循环。面试官喜欢问,代码评审里也经常吵:有人坚持“能用 interface 就不用 type”,有人反过来觉得 type 写起来更简洁。但多数人能列出来的区别,翻来覆去就是“interface 能合并声明,type 能定义联合类型”这两条。实际上,这两者的差异远比表面看到的深,而且理解不到位会在项目里埋下不少难排查的类型问题。这篇文章不打算做概念罗列,我从两者的设计定位说起,把真正的差异掰开,最后给出我在项目里实际沿用的选型规则。

1. 两者到底差在哪:先看本质,再看表面

1.1 出身不同:interface 是“接口”,type 是“别名”

很多人以为 interface 和 type 只是定义对象类型的两种语法,随便换着写没区别。这句话在前 80% 的场景下是成立的,但剩下的 20% 恰恰是坑最多的地方。

关键要先理解它们的本质。interface 的语义更接近传统面向对象语言里的“接口”:它描述的是一个对象应该长成什么样,强调的是“契约”。你可以把 interface 理解成一个有名字、可以被继承、可以被合并、可以被类实现的类型声明。而 type 的全称是 type alias,也就是类型别名,它的本质是“给某个类型起个名字”。它不一定非要指向对象类型,它可以指向一个字符串字面量类型、一个联合类型、一个元组、一个函数签名,甚至是一个条件类型的计算结果。

这个出身差异决定了非常多行为差异。interface 是有“实体感”的,编译器会把它当作一个新的、可追踪的具名类型;type 则在很多情况下是被“展开”的——编译器遇到 type 别名时,往往需要把它解析成底层类型再做进一步判断。这也是为什么在某些复杂类型场景下,interface 的报错信息比 type 更容易读。

1.2 一个典型的“看起来一样”的例子

先看一个最常见的写法:

interface User { id: number; name: string; } type UserType = { id: number; name: string; };

这两种写法在绝大多数普通对象场景里确实完全等价。你可以用接口的方式定义一个变量,也可以用 type 的方式定义,赋值时的结构检查行为也一致。甚至在大多数工具类型里,两者都能作为参数传入。

但也就在这个“看起来一样”的节点上,分岔开始了。我见过不少项目因为前期图省事,全部用 type 定义对象类型,等到后面需要扩展第三方库的类型声明、或者想用声明合并给全局接口追加字段时,发现 type 做不到,只能回头大规模重构。这种问题在项目初期完全看不出来,往往等到类型体系复杂到一定程度才爆发。

所以我的建议是:先吃透两者在扩展机制、声明行为、类型表达能力三个维度上的差异,再决定你的默认选择,而不是凭个人手感。

2. interface 的独家能力:extends、声明合并与实现契约

2.1 extends:一个 interface 可以继承多个类型,而 type 只能交叉

interface 的继承机制非常成熟,一个接口可以 extends 另一个接口,也可以 extends 一个 type 定义的对象类型:

type Person = { name: string; age: number; }; interface Developer extends Person { skills: string[]; }

这个例子里,Developer 会完整继承 Person 的属性,同时又增加自己的属性。extends 是真正的“继承”语义,子接口和父接口之间存在清晰的声明关系,编译器能准确知道字段来源。

type 之间当然也可以做类似的事情,但用的是交叉类型(intersection type):

type Animal = { name: string; }; type Dog = Animal & { bark(): void; };

看起来效果差不多,但交叉类型有一个非常经典的坑:当交叉的两个类型中存在同名但类型不兼容的属性时,结果字段会变成 never,而不是报错或让你覆盖。我用一个实际例子来说明:

type A = { value: string }; type B = { value: number }; type C = A & B; // C 里 value 实际是 string & number,也就是 never

你定义一个const c: C = { value: 'x' },编译器会告诉你类型不兼容。但问题在于,C这个类型本身并没有在定义时报错,它是“合法”的,只是不可用。这在联合类型和大型交叉组合中尤其隐蔽。而 interface extends 则相反,如果你试图继承一个属性类型不兼容的父接口,定义处直接报错,问题暴露得更早。

2.2 声明合并:同名声明是扩展还是报错,直接决定库的扩展方式

这是 interface 和 type 在行为上最明显的分水岭。

interface Window { title: string; } interface Window { ts: TypeScriptAPI; }

两个同名 interface 会被合并成一个,所有字段叠加。这被称为声明合并(declaration merging)。这对扩展全局类型、第三方库类型、甚至是给window对象追加自定义字段来说,几乎是不可替代的能力。

比如你在做前端项目时,想在Window上挂一个全局方法:

interface Window { mySDK: { init(config: Record<string, unknown>): void; }; }

这段代码写在任何模块里,整个项目后续访问window.mySDK都会正常拿到类型。如果用 type 重复声明同名类型,会直接报 Duplicate identifier 错误。

type 虽然可以用交叉类型模拟类似的效果,但那是“重新生成一个新类型”,没有办法把定义拆分到多个文件中,多个模块间也想不出一个优雅的方式来“增量添加”类型字段。所以凡是涉及全局类型扩展、API 类型设计的场景,interface 基本是唯一正解。我自己维护的几个工具库,对外暴露的类型入口一律用 interface,为的就是让使用方可以通过声明合并来补充自定义配置。

2.3 implements:谁更适合作为类的实现契约

interface 可以很自然地配合 implements 使用:

interface ILogger { log(message: string): void; } class ConsoleLogger implements ILogger { log(message: string) { console.log(message); } }

type 定义的“对象类型”也可以被类 implements,这一点并不被禁止。但 type 一旦涉及联合类型、原始类型别名这类非对象结构,implements 就会报错。更关键的是语义上的问题:type 本质上是一个别名,用别名去描述一台类的实现契约,表达能力有限,而且后续阅读代码的人很容易困惑——“这个 type 到底是个类形状,还是一个自定义类型工具?”

从我个人的项目经验看,凡是需要被类实现、被第三方扩展、被分层继承的类型骨架,我都会选择 interface。它不仅仅是能用,更重要的是它的“意图”清清楚楚:看到 interface,读者就知道这是一个开放的类型契约;看到 type,读者更应该期待它是一个封闭的类型计算产物。

3. type 的主场:联合、元组、映射与条件类型

3.1 联合类型与字面量类型:interface 完全无能为力

interface 只能描述“对象形状”,它的一切能力都建立在对象结构之上。而 type 没有任何这个限制,它可以表达一个值的所有可能类型。

type Status = 'idle' | 'loading' | 'success' | 'error'; type Result<T> = | { state: 'pending' } | { state: 'fulfilled'; data: T } | { state: 'rejected'; error: Error };

这种带判别字段的联合类型,是 Redux 状态、请求状态、流程状态建模里最常见又最好用的模式。interface 无论怎么抽象都无法表达“这个值可能是 A 形状,也可能是 B 形状,取决于 tag 字段”这类需求,这是 type 不可替代的核心理由之一。

有一些说法提到“接口也可以模拟联合类型”,严格来说不可能。你可以定义多个 interface,再用一个 type 去联合它们:

interface PendingState { state: 'pending' } interface FulfilledState<T> { state: 'fulfilled'; data: T } type State<T> = PendingState | FulfilledState<T>;

你看,最终仍然需要 type 来承担联合这一层。interface 可以当联合的组成部件,却无法成为联合本身。

3.2 元组、函数类型与原始类型别名:type 的轻量表达

元组类型是 type 的看家本领之一:

type Point3D = [x: number, y: number, z: number]; type HttpRequest = [method: 'GET' | 'POST', url: string, body?: unknown];

interface 拿元组这种“按位置而非按名字访问”的结构毫无办法,想表达也只能绕道。函数类型签名同理:

type Handler = (event: MouseEvent, context: Record<string, unknown>) => void; type StringTransformer = (input: string) => string;

用 interface 也可以表达函数类型,你得写成:

interface Handler { (event: MouseEvent, context: Record<string, unknown>): void; }

虽然能跑,但明显多一层包裹,读起来也比 type 版本别扭。更别说type UserId = string这种给基础类型起别名的操作,interface 从设计上就不支持——它只能描述有属性的对象。

3.3 映射与条件类型:真正拉开差距的“类型运算”场景

这一块是 interface 和 type 能力差距最大的地方。type 配合 keyof、in、extends、infer 等关键字,可以写出表现力极强的类型工具。

type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; }; type ReturnTypeOf<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : never; type PickKeys<T, K extends keyof T> = { [P in K]: T[P]; };

这些例子里的DeepPartial是递归映射类型,ReturnTypeOf用到了 infer 做类型推断,PickKeys本质上就是内置工具类型 Pick 的实现思路。它们都依赖“对类型本身做计算”的能力,interface 在这种场景下没有任何参与空间。

我给这类 type 的定义方式一个通俗的类比:如果说 interface 是在画图纸——规定一个东西长什么样,那么 type 更像是在写“类型的函数”——输入一些类型,经过计算,输出新的类型。前者关注形状,后者关注变换。

4. 编译性能、错误提示与声明文件输出的细微差异

4.1 编译器的缓存优化:interface 更“轻”

这一节聊一些不太被关注、但实际会影响开发体验的差异。TypeScript 编译器在处理 interface 时,因为它是一个具名的、稳定的对象类型,可以做缓存优化;而 type 别名在每次被引用时,往往需要被展开成底层类型再做处理。尤其是当你用 type 做了大量交叉类型的组合时,编译器可能需要反复合并、检查这些交叉结构,项目规模一大,编辑器的类型检查速度会有可感知的下降。

我之前处理过一个中后台项目的类型代码:有一整套用 type 和交叉类型拼出来的配置类型,单文件类型定义很长,每次保存后 VSCode 的红色波浪线和类型检查都要卡一两秒。后来把纯对象形状那部分改成 interface,几个层级关系用 extends 表达,体感明显改善。团队里也有同事反馈编辑器没有以前那么容易“转圈”了。这背后就是刚才说的缓存优化在起作用。

4.2 交叉类型的报错有多难啃:一个真实示例

如果你常规用 type 做交叉组合,大概率会遇到这种报错:

type Config = { timeout?: number; retry?: number; endpoint: string; }; type MockConfig = { endpoint: string; timeout: 'none'; mockData: Record<string, unknown>; }; type TestConfig = Config & MockConfig;

在这段代码里,timeout在两个源类型中分别是number | undefined和'none',交叉之后就成了一个几乎不可能满足的联合约束。当你去给一个TestConfig赋值时,编译器的报错会带着大段交叉类型的展开信息,把包含timeout的整个结构都吐出来,阅读成本非常高。

同样的问题如果换成 interface extends,编译器会直接说“这里的属性类型不兼容”,指向明确、信息集中。所以如果你特别在意类型报错的可读性——尤其当这个库会被其他人使用——优先用 interface 做对象结构之间的关系表达,只在确实需要交叉语义时才用 &。

4.3 .d.ts 输出的可读性差异

如果你写过 npm 包或者公共类型声明文件,应该能感觉到 interface 和 type 在产物可读性上的差别。interface 输出到 .d.ts 里,基本保持原来的样子,读者能直接看到继承层级。type 输出时,有时会保留别名引用,有时会被展开成一个冗长的结构,复杂交叉类型往往在声明文件里堆成一大片。

对使用方来说,interface 的体验更好:鼠标悬停到类型上时,编译器能清楚地展示它“从哪里来、到底定义了什么”;复杂 type 的展开则经常只看到一片复杂的嵌套结构,光是理解字段来源都要花时间。对公共类型层的设计来说,这一点值得重视。

5. 项目里的选型规则与混合使用禁忌

5.1 一套可复用的选型标准

我在代码评审里有一套相对强硬的建议,已经稳定用了一段时间,分享给大家:

判断维度默认选 interface默认选 type
描述对象形状、契约、API 数据模型、类的实现约束是否
需要被其他类型继承,存在明确的父子层级关系是否
需要向第三方库或全局命名空间追加字段(声明合并)是否
定义联合类型、交叉组合、元组、字面量联合、函数签名否是
使用映射类型、条件类型、infer 等类型运算否是
给基础类型或复杂结构起一个语义化别名否是
把一个类型工具的结果导出给外部使用否是

这套标准的核心逻辑是:interface 承担“公开、稳定、可扩展”的类型契约职责;type 承担“表达力、组合、计算”的职责。两者不是谁替代谁的关系,而是分工关系。

在实际项目里我会这么落地:前端业务那边,API 请求的响应体、请求参数、组件 Props 里的固定结构,用 interface;表单状态这种经常需要拆分字段并做部分更新映射的类型,用 type 配合工具类型处理。组件库的公开类型,几乎只用 interface,方便使用方扩展;内部实现里的各种联合状态、配置变换,全部用 type。

5.2 interface 和 type 混用时的三个坑

混用本身没有语法障碍,但有几个很容易踩的坑,我逐个说一下。

第一个是“type 重名即报错”带来的扩展陷阱。如果第三方类型是用 type 定义的,你没有办法在项目里“追加”这个类型的字段。唯一的办法是另外起一个名字,再用交叉类型去组合,但这就意味着使用方必须同时引用两个名字,体验很差。反过来,第三方类型如果是 interface,你可以直接在全局范围内进行声明合并,几乎是无痛的扩展方式。之前有个系统想给路由配置对象增加自定义权限字段,结果路由类型是 type 定义的,只能在调用入口处做一次 as 强转,绕来绕去才把类型补上。

第二个是交叉类型里同名属性变成 never 的坑。我上面已经举过例子。这里再强调一遍:两个 type 交叉时,同名但类型不同的属性不会报错,也不会保留一个覆盖另一个,而是会变成一个无法赋值的 never 类型。这个坑在多人协作时特别容易发生,因为只要没人实际去赋值,编译器不会主动提示这里有问题。

第三个坑是“type 过度包装”。有人喜欢给 interface 再包一层 type 别名:

interface User { ... } type UserAlias = User;

然后到处引用 UserAlias。这样做了之后,一旦 interface 的定义需要调整,所有引用处的类型提示都会经过一层展开,可读性和追踪性都下降,多包这一层并不会有任何类型安全收益。我对团队的要求是:除非需要一个“新的、经过变换的类型”,否则不要为了统一风格去包 type。

5.3 给团队规范的建议

如果团队正在起草 TypeScript 规范,我的建议是不要只写“优先使用 interface”或“全部使用 type”这种一刀切规则,而是把上面那张表的核心意思转成几条有实际判断标准的条款。另一方面,在代码评审里与其争论“这里该用 interface 还是 type”,不如先判断这个类型是“契约”还是“计算产物”。前者交给 interface,后者交给 type,大部分争议会自然消失。

关于“React 组件 Props 到底用哪种”这种争论,我觉得其实不必太较真。用 interface 的好处是方便继承和扩展基础 Props,用 type 的好处是写起来短、可以方便地和联合类型打交道。社区两种用法都不少。关键是在一个仓库内保持一致,或者干脆在 eslint 规则里固定下来,别让每段代码都有自己的风格。

我个人的默认规则会保守一点:只要类型结构是对象,且存在需要扩展的可能,第一反应就是 interface;只有当我要表达的对象确实是一个联合、一个元组、一个函数签名,或者需要通过类型运算生成新类型时,才使用 type。在这个基础之上再补充一句:永远不要和声明合并能力对着干,你在扩展第三方类型时,如果发现对方用的是 interface,那是一件值得庆幸的事。

这些年写过不少类型代码,也重构过不少同事留下的类型定义,最大的体会是:interface 和 type 不是“二选一”的关系,而是你对类型系统理解深度的试金石。知道它们各自的设计边界,分场景使用,比背下一百条差异清单都来得有用。下一回再遇到有人争论这个问题,你可以先把“这个类型要被谁使用、还需要怎样扩展”问清楚,答案往往就自己浮出来了。

相关新闻

Android 11 如何静默设置默认 Launcher?RoleManager 完整实践

Android 11 如何静默设置默认 Launcher?RoleManager 完整实践

1. 先想清楚&#xff1a;你要哪种“设置默认”&#xff0c;这决定了 API 路线 做 Android 系统定制和应用开发的朋友&#xff0c;应该都遇到过这个需求&#xff1a;设备上装了好几个桌面&#xff08;Launcher&#xff09;&#xff0c;用户一按 HOME 键就弹出一个“选择要使用的…

2026/10/20 17:23:56 阅读更多 →
VMware vCenter证书过期处理脚本:巡检到一键轮换的实战指南

VMware vCenter证书过期处理脚本:巡检到一键轮换的实战指南

简介&#xff1a;面向VMware vSphere/vCenter运维的证书过期处理脚本合集&#xff0c;针对SSL/TLS证书超期导致的管理界面不可访问、ESXi主机失联等问题&#xff0c;提供一套从诊断到修复的完整工具链。包内共4个文件&#xff0c;包含1个Python检测脚本与3个Shell修复脚本&…

2026/10/20 17:22:56 阅读更多 →
论文重复率降不下来?从查重逻辑到智能降重工具的全链路解析

论文重复率降不下来?从查重逻辑到智能降重工具的全链路解析

做了这么多年学术文本相关工作&#xff0c;我电脑里一直保留着一份很有意思的检测报告&#xff1a;某位同学交上来的初稿&#xff0c;系统标出的相似内容超过四成&#xff0c;可作者强调自己每个字都是亲手敲出来的。这不是个例。很多人对"论文重复率"的理解还停留在…

2026/10/20 17:22:56 阅读更多 →

最新新闻

智能体上线前验收:从功能验证到可信度评估

智能体上线前验收:从功能验证到可信度评估

1. 项目概述&#xff1a;验收不是走流程&#xff0c;是给智能体做“上岗体检”“智能体上线前&#xff0c;怎么验收才不是‘看起来能用’”——这句话一出来&#xff0c;我就想起上个月在某实验室帮一个团队做交付复盘时的场景。他们花三个月搭了个任务调度型智能体&#xff0c…

2026/10/21 0:50:37 阅读更多 →
VM算法平台4.3.1实战指南:从相机接入到多流程部署的避坑手册

VM算法平台4.3.1实战指南:从相机接入到多流程部署的避坑手册

简介&#xff1a;这份《海康机器人VM算法开发平台用户手册》面向机器视觉工程师、算法开发者及自动化设备集成人员&#xff0c;用于快速掌握VM平台的运行环境、相机接入与软件授权等核心操作。手册由近千个自主图像处理算子与140余个交互式模块构成&#xff0c;覆盖定位、尺寸测…

2026/10/21 0:50:37 阅读更多 →
AI黑盒如何安全用于芯片设计?验证护栏与工程实践解析

AI黑盒如何安全用于芯片设计?验证护栏与工程实践解析

部门的例行评审会上&#xff0c;三个项目组都碰到了同一个情况&#xff1a;AI工具给出的优化结果是“好的”&#xff0c;功耗降了、时序也收敛了&#xff0c;但当评审问“它为什么这么改、依据是什么、这个结论能不能写进签核报告”时&#xff0c;却只能看到一行冷冰冰的置信度…

2026/10/21 0:50:37 阅读更多 →
大模型API调用从会调到懂原理:采样策略、上下文窗口与参数调优实战

大模型API调用从会调到懂原理:采样策略、上下文窗口与参数调优实战

1. 从“会调”到“懂原理”的分水岭到底在哪我见过太多简历上写着“熟悉大模型应用开发”的人&#xff0c;面试时聊起调用接口头头是道&#xff0c;但一旦问到“为什么这个参数要设成0.7而不是0.3”“为什么流式输出有时候会丢字”“为什么同样的提示词换个模型效果差这么多”&…

2026/10/21 0:50:37 阅读更多 →
MATLAB张量分解实战:Tensor Toolbox安装、分解算法与避坑指南

MATLAB张量分解实战:Tensor Toolbox安装、分解算法与避坑指南

简介&#xff1a;一款面向MATLAB用户的高阶张量分析工具箱&#xff0c;版本3.2.1&#xff0c;专攻多维数组的建模与分解。工具箱内置CP分解、Tucker型奇异值分解、张量乘除与索引操作等核心算法&#xff0c;可支撑图像处理、社交网络挖掘和多源数据融合等典型场景&#xff0c;供…

2026/10/21 0:50:37 阅读更多 →
8种自动化控制信号全解析:从原理到现场排查实战

8种自动化控制信号全解析:从原理到现场排查实战

1. 从一次产线停机说起&#xff1a;为什么信号类型搞不清&#xff0c;排查就是盲人摸象干了十几年工控&#xff0c;最怕半夜接到电话说“产线停了&#xff0c;赶紧来看看”。到了现场&#xff0c;操作工一脸茫然&#xff1a;“刚才还好好的&#xff0c;突然就不动了。”你打开柜…

2026/10/21 0:49:36 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事&#xff1a;AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里&#xff0c;按宣传口径&#xff0c;本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”&#xff0c;而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起&#xff1a;用户到底在追求什么“封号重开”这四个字&#xff0c;放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流&#xff0c;背后是大量的时间和精力成本。正常情况下&#xff0c;没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”&#xff0c;而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时&#xff0c;就意识到&#xff1a;单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →