TypeScript unknown:校验外部任务再收窄类型
从 unknown 开始验证外部输入,逐步检查对象、字段类型与分钟范围,避免用类型断言伪装已经可信的数据。
本节目标
从 unknown 开始验证外部输入,逐步检查对象、字段类型与分钟范围,避免用类型断言伪装已经可信的数据。
环境与运行方法
安装 Node.js 与项目内 TypeScript 编译器。保存为 lesson.ts,执行 npx tsc lesson.ts --strict --target ES2020 --module commonjs --outDir dist,再运行 node dist/lesson.js。编译成功不等于外部数据已经校验。
核心思路
unknown 要求先检查再访问,适合网络与文件边界。运行时类型守卫只有真正完成检查才可信,函数返回类型写成 input is Task 并不会替作者自动验证实现。
完整示例
type Task = {title: string; minutes: number};
function isTask(input: unknown): input is Task {
if (typeof input !== "object" || input === null) return false;
const value = input as Record<string, unknown>;
return typeof value.title === "string" && value.title.trim() !== ""
&& typeof value.minutes === "number"
&& Number.isInteger(value.minutes)
&& value.minutes >= 0 && value.minutes <= 1440;
}
const samples: unknown[] = [{title: "review", minutes: 30}, null, {title: "bad", minutes: "30"}];
for (const value of samples) {
console.log(isTask(value) ? value.title + "=" + value.minutes : "invalid");
}预期输出
review=30
invalid
invalid逐步理解
先排除 null,因为 typeof null 也是 object。转换为键值未知的记录只是为了逐字段检查,没有直接断言为最终 Task。字符串标题还要检查非空,分钟数同时检查类型、整数与范围。
通过守卫后,分支内 value 被收窄成 Task,可以安全访问声明字段。本守卫允许额外字段,且不防止稍后修改对象;如果需要冻结或只保留允许字段,应在通过后构造新的数据对象。
常见问题与边界
- typeof 对数组也返回 object,字段检查仍必须完整。
- 单独 Number.isInteger 不能替代字段类型收窄。
- 不要返回恒真类型守卫来压制编译错误。
动手练习
验证空白标题、minutes=0 和 minutes=1441。
参考答案
空白标题失败,零分钟通过,1441 超上限失败。边界值用于检查比较运算符是否与业务要求一致。
文章回复
0 条公开回复