断言与收窄
as any、satisfies、non-null、instanceof、type predicates。
35 分钟
断言与收窄
运行时数据来自 API、表单、第三方库,编译器无法自动知道具体类型。本课讲解 as、as any、satisfies、非空断言、instanceof、type predicates 等收窄手段,衔接 typescript-essentials 的联合类型,并应用于 nestjs-essentials 的 Pipe 校验与 nextjs-essentials 的服务端数据解析。
学习目标
- 区分类型断言与类型收窄
- 正确使用
satisfies保留字面量信息 - 编写自定义 type predicate 函数
类型断言 as
// 断言:告诉编译器「我比你知道得更准」
const el = document.getElementById("root") as HTMLDivElement;
// as any:绕过检查,应极少使用
const data = JSON.parse(raw) as any;
// 双重断言(危险,仅迁移遗留代码)
const legacy = (unknownValue as unknown) as LegacyShape;
satisfies:校验但不拓宽
type RouteConfig = Record<string, { path: string; protected: boolean }>;
const routes = {
home: { path: "/", protected: false },
dashboard: { path: "/dashboard", protected: true },
} satisfies RouteConfig;
// routes.home.path 推断为 "/" 而非 string
const homePath = routes.home.path;
非空断言 !
function initChart(canvas: HTMLCanvasElement | null) {
const ctx = canvas!.getContext("2d"); // 确信非 null 时使用
ctx?.fillRect(0, 0, 100, 100);
}
instanceof 与 in
class ApiError extends Error {
constructor(public status: number, message: string) {
super(message);
}
}
function handleError(err: unknown): string {
if (err instanceof ApiError) {
return `HTTP ${err.status}: ${err.message}`;
}
if (err instanceof Error) {
return err.message;
}
return String(err);
}
Type Predicates
interface Track {
slug: string;
title: string;
}
function isTrack(value: unknown): value is Track {
return (
typeof value === "object" &&
value !== null &&
"slug" in value &&
"title" in value &&
typeof (value as Track).slug === "string"
);
}
function parseTracks(data: unknown): Track[] {
if (!Array.isArray(data)) return [];
return data.filter(isTrack);
}
练习
- 用
satisfies定义 platform 路由常量,保留字面量类型