《Go 后端开发者学 TypeScript:typescript 类型断言》

0 阅读3分钟

TypeScript 中的类型断言(Type Assertion),就是告诉编译器:

“我知道这个变量是什么类型,你按照我指定的类型来处理。”

类型断言最常用的语法是:

变量 as 类型

注意:类型断言只影响编译阶段的类型检查,不会在运行时进行类型转换,也不会校验数据是否符合类型。

1. 最简单的类型断言

let value: unknown = "hello";

// 断言为 string 类型
const str = value as string;

console.log(str.length); // 5
console.log(str.toUpperCase()); // HELLO

这里:

value as string

表示告诉 TypeScript,value 是字符串类型。

2. 对象类型断言

假设有一个用户类型:

interface User {
  id: number;
  name: string;
  age: number;
}

使用类型断言:

const data: unknown = {
  id: 1001,
  name: "张三",
  age: 25
};

const user = data as User;

console.log(user.name); // 张三
console.log(user.age);  // 25

这里的 as User 让编译器按照 User 类型检查 user。

但是如果实际数据缺少属性:

const data: unknown = {
  id: 1001,
  name: "张三"
};

const user = data as User;

console.log(user.age); // undefined

TypeScript 不会报编译错误,但运行时可能出问题。

3. 联合类型断言

let value: string | number = "hello";

const str = value as string;

console.log(str.length); // 5

当变量可能有多种类型时,可以使用断言指定其中一种类型。

不过,更推荐使用类型收窄:

function printValue(value: string | number) {
  if (typeof value === "string") {
    console.log(value.length);
  } else {
    console.log(value.toFixed(2));
  }
}

因为类型收窄会进行真实的运行时判断,而断言不会。

4. API 返回值类型断言

实际业务开发中非常常见。

interface Task {
  taskId: string;
  status: string;
  priority: number;
}

async function getTask() {
  const response = await fetch("/api/task");

  const data = (await response.json()) as Task;

  console.log(data.taskId);
  console.log(data.status);
}

这里:

as Task

表示告诉 TypeScript,API 返回的数据符合 Task 类型。

但是如果接口实际返回:

{
  "taskId": "1001",
  "status": "running"
}

缺少 priority,类型断言也不会发现。

5. 双重断言:as unknown as T

当两个类型没有足够的结构重叠时,TypeScript 通常不允许直接断言。

interface User {
  name: string;
}

interface Task {
  taskId: number;
}

const user: User = {
  name: "张三"
};

// ❌ 类型不兼容
// const task = user as Task;

// ✅ 双重断言可以通过编译
const task = user as unknown as Task;

这里:

user as unknown as Task

分为两步:

  1. user as unknown:先断言为 unknown。
  2. as Task:再断言为 Task。

双重断言会绕过部分类型安全检查,一般不建议随意使用。

6. 非空断言:!

这是 TypeScript 中另一个常见的断言语法。

function getName(name: string | null) {
  return name!.toUpperCase();
}

name! 告诉 TypeScript:

我确信 name 不会是 null 或 undefined。

不过,如果传入 null:

getName(null); // 运行时报错

因此非空断言也存在运行时风险。

7. as const 常量断言

const STATUS = {
  PENDING: "pending",
  RUNNING: "running",
  SUCCESS: "success"
} as const;

使用 as const 后,TypeScript 推断为:

{
  readonly PENDING: "pending";
  readonly RUNNING: "running";
  readonly SUCCESS: "success";
}

这与普通 as Type 不完全一样,它会保留字面量类型,并为对象和数组字面量添加只读约束。

8. as 和 : 的区别(重点)

interface User {
  id: number;
  name: string;
}

方式一:类型声明 :

const user: User = {
  id: 1
};
// ❌ 报错:缺少 name

编译器要求赋值的数据符合 User 类型。

方式二:类型断言 as

const user = {
  id: 1
} as User;
// ✅ 可以通过编译

即使缺少 name,由于存在部分结构重叠,断言仍可能通过。

9. 总结

语法作用
value as string把变量视为 string 类型
data as User把对象视为 User 类型
value as unknown as T双重断言,绕过某些类型兼容限制
value!非空断言
value as const字面量常量断言
const value: T类型声明,不是类型断言

实际开发建议:

  • 已知变量类型:优先使用 : Type。
  • 需要校验某个表达式的类型:考虑 satisfies Type。
  • 编译器无法确定,但你确信变量类型:使用 as Type。
  • 来自接口或外部的不可信数据:使用运行时校验,而不是仅使用类型断言。

最重要的一句话:类型断言不是类型转换。

例如:

const value = "123";

const num = value as unknown as number;

console.log(typeof num); // string

虽然 TypeScript 认为 num 是 number,但运行时它依然是字符串。

如果你真正想把字符串转换成数字,应该使用:

const num = Number(value);

console.log(typeof num); // number