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 什么是双重断言 #

双重断言是先断言为unknownany,再断言为目标类型:

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类型断言:

断言类型 #

  1. as语法:推荐的断言语法
  2. 尖括号语法:传统语法
  3. 非空断言!断言非空
  4. const断言:创建只读字面量类型

使用场景 #

  1. DOM元素类型
  2. JSON解析
  3. any/unknown转换
  4. 类型收窄

最佳实践 #

  1. 优先使用类型守卫
  2. 避免过度断言
  3. 使用const断言创建常量
  4. 创建断言函数提高安全性
最后更新:2026-03-26