前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库TypeScript const 类型参数 readonly 字面量推断
TyTypeScript泛型设计

TypeScript 的 const 类型参数怎么写,可变与 readonly 约束怎样影响推断?

这个修饰符调整调用处的推断策略,不能恢复调用之前已经丢失的信息。

前端进阶之旅 · 一题精讲更新于 2026.09.06
TypeScript#泛型设计#类型系统
先看核心答案读代码示例
理解线索

保留调用边界上的细粒度信息

  1. 字面量入口直接写在调用位置的对象或数组提供具体值
  2. 常量推断尽量保留字面量、只读属性与元组形状
  3. 约束检查依据约束与当前编译器确定可变或只读形状

该特性从 TypeScript 5.0 起提供,发布类型声明时还需要考虑消费端编译器版本。

核心回答

先记住这个答案

TypeScript 5.0 引入 const 类型参数,语法是在类型参数前写 const,例如 <const T extends readonly string[]>。它让符合条件的调用处字面量优先保留较窄信息,适合路由表和事件名列表。约束与编译器版本都会影响结果:本批使用的 TypeScript 5.9.3 中,直接数组字面量在 readonly 约束下得到只读元组,在可变约束下也能保留可变元组,不能机械套用旧示例中的宽数组回退结论。已经拓宽的 string[] 变量仍不会恢复原始名单。这个修饰符也不会冻结对象。

  • 正确语法是在类型参数前写 const
  • 约束与编译器版本共同影响元组可变性
  • 已拓宽变量和运行时冻结不由该修饰符解决

为什么 API 作者会需要这个修饰符

配置辅助函数常希望知道用户提供了哪些具体名称,而不是只得到字符串数组。要求每个调用者记得追加 as const 容易遗漏,const 类型参数可以把合适的推断偏好放进函数签名,让常见字面量调用更自然地保留信息。

示例对比只读约束与可变约束,并加入已经声明为 string[] 的变量。当前编译器对两种直接字面量调用都保留元组,只读性质随约束不同;宽变量则仍是宽数组。应核对实际使用版本,不能把早期版本的回退示例当成所有版本永久不变的规则。

对照约束与输入来源造成的推断差异TypeScript
function names<const T extends readonly string[]>(value: T): T { return value; }
function mutableNames<const T extends string[]>(value: T): T { return value; }
const exact = names(['open', 'close']);
const mutable = mutableNames(['open', 'close']);
const stored: string[] = ['open', 'close'];
const widened = names(stored);

在 TypeScript 5.9.3 中,exact 是 readonly ["open", "close"],mutable 是可变的 ["open", "close"],widened 仍为 string[]。函数体返回原引用,静态推断没有在运行时复制或冻结输入。

只读约束与实际写入责任怎样配合

如果函数只观察配置,接受 readonly 数组能同时兼容可变数组和只读元组,通常比要求调用方交出写入权限更贴合需求。如果函数确实要修改数组,就不能只为了保留窄推断而假装只读,应重新设计输入输出和可变性责任。

const 类型参数与调用方 as const 可以出现在不同边界:前者让 API 选择推断策略,后者由表达式作者声明字面量意图。两者都属于静态类型机制,不会代替 Object.freeze 或不可变数据结构,也不能阻止其他可写引用修改共享对象。

版本与已有变量为什么是边界

一个变量在调用前已被推断或注解成 string[],函数接收到的证据就是这个类型。即使运行时目前只有两个元素,编译器也不能据此保证以后永远没有第三种字符串。需要静态名单时,应在列表定义处保留元组或有限联合信息。

库发布包含 const 类型参数的声明时,旧编译器可能连语法都无法解析。应声明支持的 TypeScript 范围,并在消费端版本上验证声明产物。不要只看库自身编译成功,就认为所有下游工具链都能读取这份公开类型接口。

回答前,多想一步

容易答错的地方

正确写法是 T extends const
const 是类型参数声明上的修饰符,应该写在 T 前面;写成 T extends const 并不会启用这种推断,本例编译器会报告找不到 const 类型名称。
加 const 就能恢复任何变量的字面量集合
提前拓宽的信息不会凭空恢复,输入来源和约束都会限制推断;应在需要保留名单的声明边界就表达对应的静态契约。
试着用自己的话回答

面试官还会怎么问?

为什么只读约束能接受普通可变数组?

只读使用者只承诺观察,不要求获得写入能力,因此可变数组通常可以满足这种较小使用契约;反向把只读元组交给可变接口则不同。

const 类型参数会让所有调用结果都只读吗?

不会无条件改写已有输入类型,它主要影响合适的字面量推断;传入已经声明的可变变量时,仍应查看返回的实际类型。

需要真正冻结配置应该怎么做?

应在运行时执行符合对象层级的冻结或采用不可变更新策略,并明确共享引用边界;类型修饰符只能提供开发阶段的静态约束。

从一道题,走向一组知识

把知识连起来

类型系统基础

TypeScript 为什么把对象中的字符串推断成 string,如何保留字面量?

先理解对象与数组信息为什么会在声明时拓宽

泛型设计

TypeScript 数组为什么允许协变赋值,readonly 怎样减少不安全写入?

只读输入契约还能减少可变数组协变带来的写入问题

参考资料

  • TypeScript 5.0:const Type Parameters

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 为什么 API 作者会需要这个修饰符
  3. 只读约束与实际写入责任怎样配合
  4. 版本与已有变量为什么是边界
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑