ts类型断言与类型推断

类型断言

在 TypeScript 中,类型断言(Type Assertion)是一种告诉编译器"我知道这个值的类型是什么"的机制。这种机制主要有两种形式:尖括号语法(Angle Bracket Syntax)和 as 语法。

尖括号语法

typescript 复制代码
let value: any = "This is a string";
let strLength: number = (<string>value).length;

// 或者
let alternativeWay: number = (value as string).length;

在上面的例子中,value 被声明为 any 类型,然后通过尖括号语法或 as 语法将其断言为 string 类型,以便获取其 length 属性。这样,开发者告诉 TypeScript 编译器:"我确信 value 是一个字符串。"

as语法

ini 复制代码
let value: any = "This is a string";
let strLength: number = (value as string).length;

在这个例子中,我们使用了 as 语法来进行类型断言,效果和尖括号语法是一样的。


举个例子,现在有这样一个函数,

kotlin 复制代码
const getLength = target => {
  if (target.length) {
    return target.length;
  } else {
    return target.toString().length;
  }
};

这是一个 JavaScript 函数,用于获取目标对象的长度。函数采用一个参数 target,然后通过检查目标对象的 .length 属性是否存在来确定其类型。

如果目标对象有 .length 属性,函数直接返回该属性的值,假定该对象是一个具有长度属性的对象(比如数组、字符串等)。

如果目标对象没有 .length 属性,函数假设该对象可能是一个不具有 .length 属性的对象,然后通过将其转换为字符串并获取字符串的长度来返回对象的长度。

现在考虑这个函数的TypeScript实现,如果按下述方式编写

typescript 复制代码
const getLength = (target: string | number): number => {
  if (target.length) { // 类型"string | number"上不存在属性"length"。类型"number"上不存在属性"length"。
    return target.length; // error 报错信息看下方
  } else {
    return target.toString().length;
  }
};

函数的参数 target 被定义为 string | number,表示它可以是字符串或数字类型。然而,在 TypeScript 中,对于联合类型,你不能直接访问其类型的属性或方法,因为并非所有可能的类型都具有相同的属性。

在这个函数中,TypeScript 报错是因为它无法确定 target 到底是一个字符串还是一个数字,而它尝试访问 .length 属性,这个属性在数字类型上是不存在的。

因此可以考虑采用类型断言

typescript 复制代码
const getStrLength = (target: string | number): number => {
  if ((<string>target).length) { // 这种形式在JSX代码中不可以使用,而且也是TSLint不建议的写法
    return (target as string).length; // 这种形式是没有任何问题的写法,所以建议大家始终使用这种形式
  } else {
    return target.toString().length;
  }
};

我们希望对 target 进行判断并访问其 length 属性,但由于 target 是一个联合类型 string | number,TypeScript 不确定它的具体类型。因此,我们在进行判断之前需要告诉 TypeScript 我们认为 target 是一个字符串类型。

在这个函数中,使用了类型断言来告诉 TypeScript,你确定 target 是一个字符串。有两种类型断言的写法:

(<string>target).length:这是一种旧式的写法,不推荐在 JSX 代码中使用,而且 TSLint 也不建议这种写法。

(target as string).length:这是一种更现代、更安全的写法,也是推荐使用的方式。

所以,建议使用第二种写法,即 (target as string).length。这样可以避免潜在的问题,并且在 JSX 代码中也是可用的。

类型推断

多类型联合

ini 复制代码
let arr = [1, "a"];
arr = ["b", 2, false]; // error 不能将类型"false"分配给类型"string | number"

当我们定义一个数组或元组时,TypeScript 会对数组中元素的类型进行合并形成联合类型。这就意味着,数组或元组的元素可以是多个不同类型中的任意一种。

在给定的例子中,arr 的元素类型被推断为 string | number,这表示数组中的元素可以是 string 类型,也可以是 number 类型,但不允许其他类型,例如 boolean。所以,当尝试将 false 赋值给 arr 时,TypeScript 报错,因为 false 的类型是 boolean,不属于联合类型 string | number。

ini 复制代码
let value = Math.random() * 10 > 5 ? 'abc' : 123
value = false // error 不能将类型"false"分配给类型"string | number"

value 的类型被推断为联合类型 string | number。这是因为它的赋值取决于三元操作符的条件。如果条件为真,value 是字符串类型 'abc',如果条件为假,value 是数值类型 123。

当你尝试将 false 赋值给 value 时,TypeScript 报错。这是因为 false 的类型不属于 string | number 联合类型,所以 TypeScript 认为这是一个类型不匹配的错误。

这种方式使得 TypeScript 可以在编译阶段捕获到潜在的类型错误,增加了代码的类型安全性。

上下文类型

在 TypeScript 中,上下文类型是一种类型推断的机制,它是根据变量声明的上下文来推断该变量的类型。上下文类型通常发生在赋值语句的左侧,即当你给一个变量赋值时,TypeScript 根据变量被赋值的上下文来推断变量的类型。

javascript 复制代码
window.onmousedown = function(mouseEvent) {
  console.log(mouseEvent.a); // error 类型"MouseEvent"上不存在属性"a"
};

window.onmousedown 被赋值为一个函数,而该函数有一个参数 mouseEvent。TypeScript 尝试根据赋值语句的上下文来推断 mouseEvent 的类型。

上下文: window.onmousedown 是一个事件处理函数,因此 TypeScript 推断 mouseEvent 应该是鼠标事件对象 (MouseEvent)。

推断的类型: TypeScript 推断 mouseEvent 的类型为 MouseEvent,因为它是 onmousedown 事件处理函数的参数。

类型检查: 在你尝试访问 mouseEvent.a 时,TypeScript 进行了类型检查。由于 MouseEvent 类型并没有名为 a 的属性,所以 TypeScript 报错,指出在 MouseEvent 上不存在属性 a。

总体而言,上下文类型推断是 TypeScript 在缺少显式类型注释时,通过根据表达式的上下文(在这里是事件处理函数)来推断变量类型的一种方式。

相关推荐
gis开发之家10 小时前
vue3直击架构痛点 依赖倒置与接口隔离——打造坚如磐石的插件与高阶组件(HOC)模式
javascript·架构·typescript·前端框架·vue3
冬枳11 小时前
基于OpenSeagragon封装的前端病理切片展示组件
前端·typescript
退休倒计时15 小时前
【每日一题】LeetCode 287. 寻找重复数 TypeScript
算法·leetcode·typescript
@@@@@@@@542 天前
JavaScript 的缺点与 TypeScript 的弥补
开发语言·javascript·typescript
用户0934077735142 天前
HarmonyOS WPS Open SDK 实践:最小打开闭环与 enableEdit 分支处理
typescript·harmonyos
柯克七七2 天前
我把 bug 修得太干净了,测试组以为这个模块本来就没问题
前端·javascript·typescript
退休倒计时2 天前
【每日一题】LeetCode 39. 组合总和 TypeScript
算法·leetcode·typescript
yyt3630458412 天前
KlineChartQuant Tooltip 高频交互 200FPS 性能优化完整复盘
前端·经验分享·性能优化·typescript·vue·交互·chrome devtools
用户0934077735143 天前
HarmonyOS WPS Open SDK 实践:办公审批附件「打开—编辑—回传」代码实现
typescript·harmonyos
Flynt3 天前
TypeScript 5.8 让我少踩了一个大坑,顺手再聊聊 --erasableSyntaxOnly
前端·javascript·typescript