类型推断与类型断言
本节目标
- 理解 TS 在哪些地方会自动推断
- 掌握类型断言
as的写法与「何时该用、何时危险」 - 区分
as与「非空断言!」
TS 推断能力很强:变量初始化、返回值、解构都能推断。
// 运行环境:Node.js 16+ + typescript;类型检查 npx tsc --noEmit ts-l8.ts
// 推断:从初始值推出 number
const n = 42
// 推断:从返回值推出 string
function getName() { return 'Tom' }
// 类型断言 as:你比编译器更清楚类型时,主动「告诉」它
const input = document.getElementById('name') as HTMLInputElement
// 上面若不加 as,getElementById 返回的是 HTMLElement | null,没有 .value
console.log(input.value)
// 断言的另一种写法(JSX 里只能用 as,避免和泛型语法冲突)
const val = (<HTMLInputElement>document.getElementById('name')).value⚠️ 危险信号:as 是「你向编译器保证没错」,编译器不再检查。乱用 as 会把类型系统的保护全关掉。
// 非空断言 !:告诉编译器「这里绝对不是 null/undefined」
function first<T>(arr: T[]): T {
return arr[0]! // 你保证数组非空;若实际为空,运行时直接崩
}原则:能不用断言就不用;非用不可时,优先用「类型守卫」替代 as(见 ts-l12)。
名词解释
类型断言(Type Assertion,as):相当于你对编译器说「相信我,我知道它实际是什么类型」。它只在编译期改变 TS 的看法,运行时什么都不做、不做任何转换。就像给编译器戴上一副你指定的眼镜,但眼镜不会真的改变物体本身。
非空断言(Non-null Assertion,!):x! 表示「我保证 x 不是 null/undefined」。它是 as 的一个特例,专治「可能为空的变量」。风险极高:一旦你保证错了,运行时就是真正的 TypeError。
课后练习
练习 1:下面哪行用了断言后可能运行时崩溃?
const el = document.querySelector('.btn') as HTMLButtonElement
el.click()答案:如果页面上根本没有
.btn这个元素,querySelector返回null,as强行当成按钮,调.click()会在运行时抛Cannot read properties of null。正确做法是用if (el) el.click()守卫,而不是断言。
练习 2:as 和类型转换(如 Number('1'))有什么本质区别?
答案:
as只是编译期的「看法调整」,零运行时开销、不改变值;Number('1')是真正的运行时转换,把字符串变成数字。很多人把as误当成「转换」,这是大坑。
总结
我的态度很鲜明:as 和 ! 是「逃生舱」,不是「日常交通工具」。每写一次断言,你就亲手拆掉了一块 TS 的安全护栏。我见过太多项目因为滥用 as any 把整个 TS 价值归零。正确顺序是:先尝试用类型守卫、泛型、精确标注来解决;实在绕不过(比如接第三方库、DOM 查询)才用 as,而且窄到最小范围。非空断言 ! 我几乎从不主动写——它等于在赌运行时,而赌运气的代码最不可靠。