编程前端开发员

描述 TypeScript 中的类型保护机制(Type Guards)并提供使用示例。其主要优点是什么,以及在实现自定义类型保护函数时需要考虑哪些细节?

用 Hintsage AI 助手通过面试

回答。

类型保护—是一种机制,允许在代码块中基于某些检查(例如,通过 typeofinstanceof 或返回表达式 param is SomeType 的特殊函数)来细化变量的类型。

主要优点—是在编译时通过类型检查提高安全性,减少运行时错误。

示例:

interface Fish { swim: () => void } interface Bird { fly: () => void } function isFish(pet: Fish | Bird): pet is Fish { return (pet as Fish).swim !== undefined; } function move(pet: Fish | Bird) { if (isFish(pet)) { pet.swim(); } else { pet.fly(); } }

在这里,函数 isFish 是一个自定义类型保护。

细节:

  • 任何附加的逻辑检查必须与类型化严格相关。
  • 类型保护函数中的错误可能导致在运行时类型错误的识别。

有陷阱的问题。

问题: "TypeScript 编译器是否会始终只依赖于保护函数的返回值,或还会在函数内部进行其他分析?"

回答: TypeScript 编译器仅依赖于返回值的签名 param is Type。函数保护内部发生的事情不进行正确性分析。

示例(危险错误!):

function isString(x: any): x is string { return true; } // 编译器会认为始终是字符串,尽管事实并非如此: if (isString(123)) { // 这里 x 类型为字符串,但实际上是数字 }

因为对主题细节不熟悉而导致的实际错误示例。


故事

在一个前后端共享 DTO 的项目中,忘记在自定义类型保护内部添加严格检查。结果部分数据错误地被视为所需类型,导致客户端在尝试使用缺失属性时出现故障。


故事

开发者编写了类型保护,依赖于可选字段,但是数据结构允许根本不存在该字段。最终类型的 switch-case 缺少了分支,编译器没有发出警告—运行时出现异常。


故事

在某个服务中,转换到 TypeScript 时仅依赖于内置的类型保护(typeofinstanceof)。在执行检查时如果对象原型发生变化,就会变得不正确,导致在生产环境中出现难以调试的错误。