美文网首页
TypeScript中的类型断言

TypeScript中的类型断言

作者: 一颗小行星_混沌前端 | 来源:发表于2022-07-25 19:05 被阅读0次

    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">>
    
    image-20220726173035919 image-20220726173102524

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

    image-20220726173131771

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

    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

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

    相关文章

      网友评论

          本文标题:TypeScript中的类型断言

          本文链接:https://www.haomeiwen.com/subject/uqzoirtx.html