TypeScript中的类型断言

虚烬
• 阅读 992
TypeScript 的类型断言看起来概念比较简单,但是对于刚接触 TypeScript 的使用者,可能对使用场景缺少认识,希望本文可以帮助你更了解类型断言。

当你使用一个值,但是 TypeScript 不知道具体类型 或者 TypeScript 记录的类型没有办法满足使用要求时,可以使用类型断言来明确指定为自己想要使用的类型。

语法:

类型断言有两种方式:

  1. 使用 <> 语法
  2. 使用 as 关键字

<> 会和 JSX 语法冲突,一般使用 as

我们来看几个类型断言的示例

1.对于通过标签获取的DOM,TypeScript可以推断出类型,但是对于其他方式,TypeScript无法推断,我们可以使用类型断言来明确指定元素类型。

const aEle = document.querySelector('a') // HTMLAnchorElement | null
const canvasEle = document.querySelector('#my_canvas') as HTMLCanvasElement
React.useEffect(() => {
  if (props.autoFocus) {
    const $this = ref.current as HTMLInputElement;
    ...
  }
}, []);

AntD中的示例:ActionButton.tsx

2.对于空对象占位,可以断言为特定类型,以获取正确的代码提示和类型推断

const [user, setUser] = useState<User | null>(null);
setUser(newUser);
const [user, setUser] = useState<User>({} as User);
setUser(newUser);

const 断言

const 断言告诉编译器为表达式推断出它能推断出的最窄或最特定的类型,而不是通用类型。

// point变成一个readonly 数组类型,修改数组内容会提示错误。
let point = [3, 4] as const; // readonly [3, 4]
point[0] = 1 // Error

我们来看一个代码示例:

function useDarkMode() {
  const [mode, setMode] = React.useState<'dark' | 'light'>(() => {
    // ...
    return 'light'
  })
  ...
  return [mode, setMode] as const
}
​
const [mode, setMode] = useDarkMode() // 伪代码,hook需要再函数组件中使用

我们来对比一下 mode 和 setMode 使用 as const 之后的差别:

在使用 const 断言之前,mode 和 setMode 类型为:

const mode: "dark" | "light" | React.Dispatch<React.SetStateAction<"dark" | "light">>
const setMode: "dark" | "light" | React.Dispatch<React.SetStateAction<"dark" | "light">>

TypeScript中的类型断言

调用setMode时,会提示错误,因为 'dark' | 'light' 并不是可调用类型。

TypeScript中的类型断言

使用 as const 断言之后,mode 和 setMode 类型为:

const mode: "dark" | "light"
const setMode: React.Dispatch<React.SetStateAction<"dark" | "light">>

TypeScript中的类型断言

TypeScript中的类型断言

调用传参错误时,也会有类型错误提示。

TypeScript中的类型断言

可以看到,对于数组来说,每个元素的类型是整个数组元素类型的联合类型

const arr = [1,'2'] 
// const arr: (string | number)[]

使用 as const 断言之后,数组会变成 readonly 数组且每个元素有了自己的特定类型,也有了更好的错误提示。

再来看一个 rxjs 中的示例:fromEvent.ts

// These constants are used to create handler registry functions using array mapping below.
// 这些常量用于使用下面的数组映射创建处理程序注册表函数
const nodeEventEmitterMethods = ['addListener', 'removeListener'] as const;
const eventTargetMethods = ['addEventListener', 'removeEventListener'] as const;
const jqueryMethods = ['on', 'off'] as const;

使用 as const之后,类型检测更为严格:

  • readonly 数组,每个元素都有自己的字面量类型,无法调整为其他值,杜绝被意外修改的可能
  • 在访问数组元素或进行数组解构时,因数组长度固定,避免越界,更不容易出错

const 断言和 typeof 搭配使用:useSelection.tsx

字符串使用 as const 之后,变量就有了字面量类型,typeof 操作符可以提取其字面量类型使用。

export const SELECTION_ALL = 'SELECT_ALL' as const;
export const SELECTION_INVERT = 'SELECT_INVERT' as const;
​
export type INTERNAL_SELECTION_ITEM =
  | SelectionItem
  | typeof SELECTION_ALL
  | typeof SELECTION_INVERT;

规避类型检查

TypeScript 只允许类型断言为一个更具体或者更不具体的类型,这个规则可以阻止一些错误的强制类型转换:

const x = "hello" as number;
// Error:将 'string' 类型转换为 'number' 类型可能是一个错误,因为这两种类型都没有充分重叠。如果这是故意的,请先将表达式转换为“unknown”。

我们再来看一个 Antd 中的使用示例: back-top

React.useEffect(() => {
  bindScrollEvent();
  return () => {
    if (scrollEvent.current) {
      scrollEvent.current.remove();
    }
    (handleScroll as any).cancel();
  };
}, [props.target]);

handleScroll 是一个函数,但是其他文件中被增加了 cancel 属性,此处直接调用 cancel 方法, TypeScript会提示错误,可以断言为 any 来规避 TypeScript 的类型检查

双重断言

对于我们已经明确的变量类型,如果不存在重叠,可以先断言为一个宽泛的类型(any、unknown),再断言为一个具体的类型。

// es default export should use const instead of let
const ExportTypography = (RefTypography as unknown) as React.FC<TypographyProps>;

Typography

注意:当使用断言时,应该确保你了解当前值的类型,避免出错。对于可以收窄的类型,尽量使用类型收窄而非断言。

点赞
收藏
评论区
推荐文章
皮卡皮卡皮 皮卡皮卡皮
4年前
了解什么是 TypeScript
内容纲要了解什么是TypeScriptTypeScript基本语法TypeScript介绍TypeScript是什么TypeScript是JavaScript的强类型版本。然后在编译期去掉类型和特有语法,生成纯粹的JavaScript代码。由于最终在浏览器中运行的仍然是JavaScript,所以TypeScript并
Easter79 Easter79
4年前
typeScript数据类型
//布尔类型letisDone:booleanfalse;//数字类型所有数字都是浮点数numberletdecLiteral:number6;lethexLiteral:number0xf00d;letbinaryLiteral:number0b101
Souleigh ✨ Souleigh ✨
5年前
TypeScript: 请停止使用 any
当我们开发TypeScript代码时,很可能会遇到any关键字。我们看到的大多数用法都表明我们正在处理TypeScript中的基本类型。在文档中我们可能会找到:(…)来不使用TypeScript或第3方库编写的代码的值。在这些情况下,我们可能要选择退出类型检查。为此,我们将这些值标记为any类型:什么是any因此any
Jacquelyn38 Jacquelyn38
4年前
零基础学习TypeScript(源码开源)
今天,这篇文章篇幅很短,主要开放我最近学习整理TypeScript源码。|文件夹|作用|||||demo1|TypeScript的定义||demo2|基础环境搭建||demo3|基础类型和对象类型||demo4|类型注解和类型推断||demo5|函数相关类型||demo6|数组与元组||dem
爱丽丝13 爱丽丝13
4年前
TypeScript 4.2 有哪些新特性
TypeScript4.2发布了!对于不熟悉TypeScript的人来说,TypeScript就是增加了静态类型和类型检查的JavaScript。有了类型限制,你就可以精确的表达你的函数需要什么类型的参数以及返回什么类型的结果。同时,利用TypeScript的类型检查,你可以很容易避免一些常见错误,例如拼写错误或者忘记处理null和un
Wesley13 Wesley13
4年前
2、typescript
有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。通过_类型断言_这种方式可以告诉编译器,“相信我,我知道自己在干什么”。类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。它没有运行时的影响,只是在编译阶段起作用。TypeScript会假设你
Easter79 Easter79
4年前
TypeScript高级类型
交叉类型(IntersectionTypes)交叉类型是将多个类型合并为一个类型。这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。例如,Person&Serializable&Loggable同时是Person_和_Serializable_和_Loggable。就是说这个类型的对
Easter79 Easter79
4年前
TypeScript学习笔记
TypeScript学习笔记TypeScript是JavaScript的超集,任何合法的JS程序都是合法的TypeScript程序TypeScript通过向JavaScript增加可选的静态类型声明来把JavaScript变成强类型程序语言。静态类型声明可约束函数、变量、属性等程序实体。TypeScript语言内
Easter79 Easter79
4年前
TypeScript
数组的类型在TypeScript中,数组类型有多种定义方式,比较灵活。「类型方括号」表示法最简单的方法是使用「类型方括号」来表示数组:letfibonacci:number1,1,2,3,5;数组的项中不允许出现其他的类型:
程序员小五 程序员小五
1年前
融云IM干货丨UINI-app支持TypeScript吗?
UINIapp支持TypeScript开发。具体来说,UINIapp允许在项目中使用TypeScript,并提供了相应的类型定义文件。开发者可以通过以下方式进行TypeScript配置:1.项目创建:在HBuilderX中创建项目时,可以在vue或nvue
虚烬
虚烬
Lv1
忽闻歌古调,归思欲沾巾。
文章
2
粉丝
0
获赞
0
热门文章