TypeScript类型断言 #
一、类型断言概述 #
1.1 什么是类型断言 #
类型断言是一种告诉编译器"相信我,我知道我在做什么"的方式。它不会在运行时产生任何影响,只在编译时起作用。
typescript
let value: any = 'hello';
let length1: number = (value as string).length;
let length2: number = (<string>value).length;
1.2 两种语法 #
as语法(推荐) #
typescript
let value: any = 'hello';
let length: number = (value as string).length;
尖括号语法 #
typescript
let value: any = 'hello';
let length: number = (<string>value).length;
1.3 选择建议 #
- 在TypeScript中使用
as语法 - 在React JSX中使用
as语法(尖括号会与JSX冲突)
二、常用场景 #
2.1 any到具体类型 #
typescript
let value: any = 'hello';
let str: string = value as string;
console.log(str.toUpperCase());
2.2 unknown到具体类型 #
typescript
let value: unknown = 'hello';
let str: string = value as string;
console.log(str.toUpperCase());
2.3 DOM元素类型 #
typescript
const input = document.querySelector('input') as HTMLInputElement;
console.log(input.value);
const canvas = document.querySelector('canvas') as HTMLCanvasElement;
const ctx = canvas.getContext('2d');
2.4 事件对象 #
typescript
document.addEventListener('click', (event) => {
const target = event.target as HTMLButtonElement;
console.log(target.textContent);
});
2.5 JSON解析 #
typescript
interface User {
id: number;
name: string;
}
const json = '{"id": 1, "name": "Alice"}';
const user = JSON.parse(json) as User;
console.log(user.name);
三、非空断言 #
3.1 非空断言操作符 #
使用!断言值不为null或undefined:
typescript
let value: string | null = 'hello';
let length: number = value!.length;
console.log(length);
3.2 DOM元素 #
typescript
const element = document.getElementById('app')!;
element.textContent = 'Hello';
3.3 可选属性 #
typescript
interface User {
name: string;
email?: string;
}
const user: User = { name: 'Alice' };
const email: string = user.email!;
3.4 函数参数 #
typescript
function greet(name: string | null): void {
console.log(name!.toUpperCase());
}
greet('Alice');
greet(null);
四、const断言 #
4.1 基本用法 #
typescript
let x = 'hello' as const;
let arr = [1, 2, 3] as const;
let obj = { name: 'Alice' } as const;
4.2 字面量类型 #
typescript
let x = 'hello' as const;
x = 'world';
let x: 'hello' = 'hello';
4.3 只读数组 #
typescript
let arr = [1, 2, 3] as const;
arr.push(4);
arr[0] = 10;
4.4 只读对象 #
typescript
let obj = {
name: 'Alice',
age: 25
} as const;
obj.name = 'Bob';
4.5 元组类型 #
typescript
let point = [10, 20] as const;
let x: 10 = point[0];
let y: 20 = point[1];
五、双重断言 #
5.1 什么是双重断言 #
双重断言是先断言为unknown或any,再断言为目标类型:
typescript
let value: string = 'hello';
let num: number = value as unknown as number;
5.2 使用场景 #
typescript
interface A {
a: string;
}
interface B {
b: number;
}
let a: A = { a: 'hello' };
let b: B = a as unknown as B;
5.3 危险性 #
typescript
let value: string = 'hello';
let num: number = value as unknown as number;
console.log(num.toFixed(2));
5.4 避免使用 #
typescript
let value: string = 'hello';
let num: number = parseInt(value);
console.log(num.toFixed(2));
六、类型断言vs类型转换 #
6.1 类型断言 #
类型断言只在编译时起作用:
typescript
let value: any = 'hello';
let num: number = value as number;
console.log(typeof num);
6.2 类型转换 #
类型转换在运行时执行:
typescript
let value: any = '123';
let num: number = Number(value);
console.log(typeof num);
七、断言函数 #
7.1 asserts语法 #
typescript
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== 'string') {
throw new Error('Value is not a string');
}
}
function process(value: unknown): void {
assertIsString(value);
console.log(value.toUpperCase());
}
7.2 断言条件 #
typescript
function assert(condition: boolean, message: string): asserts condition {
if (!condition) {
throw new Error(message);
}
}
function divide(a: number, b: number): number {
assert(b !== 0, 'Cannot divide by zero');
return a / b;
}
7.3 断言非空 #
typescript
function assertDefined<T>(value: T | null | undefined): asserts value is T {
if (value === null || value === undefined) {
throw new Error('Value is null or undefined');
}
}
function process(value: string | null): void {
assertDefined(value);
console.log(value.toUpperCase());
}
八、实用示例 #
8.1 DOM操作 #
typescript
function getInputElement(id: string): HTMLInputElement {
const element = document.getElementById(id);
if (!(element instanceof HTMLInputElement)) {
throw new Error(`Element ${id} is not an input`);
}
return element;
}
const input = getInputElement('username');
console.log(input.value);
8.2 API响应 #
typescript
interface ApiResponse<T> {
code: number;
message: string;
data: T;
}
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
const data = await response.json() as ApiResponse<User>;
if (data.code !== 200) {
throw new Error(data.message);
}
return data.data;
}
8.3 类型守卫结合断言 #
typescript
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'name' in value
);
}
function assertUser(value: unknown): asserts value is User {
if (!isUser(value)) {
throw new Error('Invalid user object');
}
}
function process(value: unknown): void {
assertUser(value);
console.log(value.name);
}
8.4 枚举值断言 #
typescript
enum Status {
Pending = 'pending',
Approved = 'approved',
Rejected = 'rejected'
}
function isStatus(value: string): value is Status {
return Object.values(Status).includes(value as Status);
}
function assertStatus(value: string): asserts value is Status {
if (!isStatus(value)) {
throw new Error(`Invalid status: ${value}`);
}
}
function process(value: string): void {
assertStatus(value);
console.log(value);
}
九、最佳实践 #
9.1 优先使用类型守卫 #
typescript
function process(value: unknown): void {
if (typeof value === 'string') {
console.log(value.toUpperCase());
}
}
function processBad(value: unknown): void {
console.log((value as string).toUpperCase());
}
9.2 避免过度断言 #
typescript
const element = document.getElementById('app') as HTMLDivElement;
element.textContent = 'Hello';
const element2 = document.getElementById('app');
if (element2 instanceof HTMLDivElement) {
element2.textContent = 'Hello';
}
9.3 使用const断言 #
typescript
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000
} as const;
9.4 创建断言函数 #
typescript
function assertNever(value: never): never {
throw new Error(`Unexpected value: ${value}`);
}
type Shape = 'circle' | 'square';
function getArea(shape: Shape): number {
switch (shape) {
case 'circle':
return Math.PI;
case 'square':
return 1;
default:
return assertNever(shape);
}
}
十、总结 #
本章介绍了TypeScript类型断言:
断言类型 #
- as语法:推荐的断言语法
- 尖括号语法:传统语法
- 非空断言:
!断言非空 - const断言:创建只读字面量类型
使用场景 #
- DOM元素类型
- JSON解析
- any/unknown转换
- 类型收窄
最佳实践 #
- 优先使用类型守卫
- 避免过度断言
- 使用const断言创建常量
- 创建断言函数提高安全性
最后更新:2026-03-26