TypeScript学习笔记之类型窄化篇

 更新时间:2021年09月14日 10:32:43   作者:前端铁蛋儿  
目前用TypeScript的人越来越多,尤其是一些大厂,大的项目,github上面很多开源项目也都是ts语法编译的,这篇文章主要给大家介绍了关于TypeScript学习笔记之类型窄化的相关资料,需要的朋友可以参考下

前言

TS最好用的地方就是强类型,随之而来的就是类型窄化,摸鱼的时候顺道总结下.

类型推论

TypeScript里,在有些没有明确指出类型的地方,类型推论会帮助提供类型

Example:

let x = [0, 1, null] // number

let x = Math.random() < 0.5 ? 100 : "helloword" // number|string

let x: Animal[] = [new Rhino(), new Elephant(), new Snake()]; // Rhino | Elephant | Snake

如果没有找到最佳通用类型的话,类型推断的结果为联合数组类型

联合类型和类型守卫

Example:

// 联合类型
type Types = number | string

function typeFn(type: Types, input: string): string {
  //  如果这样写就需要判断type的类型
}

可以直接赋值类型推断

let x:number|string = 1
x="tiedan"

如果不判断会报错

function typeFn(type: number | string, input: string) {
  // 报错 运算符+号不能应用于 string 
  return new Array(type + 1).join("") + input
}

所以还得判断

function typeFn(type: number | string, input: string) {
  // 类型守卫
  if (typeof type === 'number') {
    return new Array(type + 1).join(" ") + input
  }
  return type + input
}

类型的窄化就是根据判断类型重新定义更具体的类型

那么问题来了学这玩意干嘛? js不香吗?

个人观点:

使用 TypeScript 可以帮你降低 JavaScript 弱语言的脆弱性,帮你减少由于不正确类型导致错误产生的风险,以及各种 JavaScript 版本混杂造成错误的风险。

TypeScript 只是把高级语言的强类型这个最主要的特征引入 JavaScript ,就解决了防止我们在编写 JavaScript 代码时因为数据类型的转换造成的意想不到的错误,增加了我们排查问题的困难性。

typeof的类型守卫:

"string"
"number"
"bigint" // ES10新增
"boolean"
"symbol" // ES6新增
"undefined"
"object"
"function"

注意: typeof null 等于 object

因此:

function strOrName(str: string | string[] | null) {
  if (typeof str === 'object') {
    for (const s of str) {
      // 报错 因为str有可能是null
      console.log(s)
    }
  } else if (typeof str === 'string') {
    console.log(str)
  } else {
    //......
  }
}

真值窄化

js的真值表很复杂, 除以下的是false其余的都是真。

0
NAN
""
0n // 0的bigint版本
null
undefined

避免null的错误可以利用真值窄化

// 利用真值判断
if (str && typeof strs === 'object') {
  for (const s of strs) {
    console.log(s)
  }
}

或者这样也行

function valOrName(values: number[] | undefined, filter: number): number[] | undefined {
  if (!values) {
    return values
  } else {
    return values.filter(x => x > filter)
  }
}

小结: 真值窄化帮助我们更好的处理null/undefined/0 等值

相等性窄化

想等性窄化就是利用 ===、 !== 、==、and、!= 等运算符进行窄化

Example1:

function strOrNum(x: string | number, y: string | boolean) {
  if (x === y) {
    // string
  } else {
    // string|number
  }
}

Example2:

function strOrName(str: string | string[] | null) {
  if (str !== null) {
    if (typeof str === 'object') {
      for (const s of str) {
        console.log(s) // []
      }
    } else if (typeof str === 'string') {
      console.log(str) // string
    } else {
      // .....
    }
  }
}

Example3:

interface Types {
  value: number | null | undefined
}

function valOrType(type: Types, val: number) {
  // null和undefined 都是false 只能是number
  if (type.value != null) {
    type.value *= val
  }
}

in操作符窄化

in是检查对象中是否有属性,现在充当了一个 "type guard" 的角色。

Example:

interface A { a: number };
interface B { b: string };

function foo(x: A | B) {
    if ("a" in x) {
        return x.a;
    }
    return x.b;
}

instanceof窄化

instanceof表达式的右侧必须属于类型 any,或属于可分配给 Function接口类型的类型。

Example:

function dateInval(x: Date | string) {
  if (x instanceof Date) {
    // Date
  } else {
    // string
  }
}

窄化的本质

窄化的本质是重新定义类型

Example:

function example() {
  let x: string | number | boolean
  x = Math.random() < 0.5
  if (Math.random() < 0.5) {
    x = 'hello' // string
  } else {
    x = 100 // number
  }
  return x; // string|number
}

联合类型的窄化

Example1:

interface Shape {
  kind: "cirle" | "square",
  redius?: number
  sideLength?: number
}

// 报错

function getArea(shape: Shape) {
	return Math.PI * shape.redius ** 2
}
// 窄化还是报错

function getArea(shape: Shape) {
  if (shape.kind === 'cirle') {
    return Math.PI * shape.redius ** 2
  }
}
// 利用非空断言阔以

function getArea(shape: Shape) {
  if (shape.kind === 'cirle') {
    return Math.PI * shape.redius! ** 2
  }
}

Example2:

interface Circle {
  kind: "cirle";
  redius: number;
}

interface Square {
  kind: "square";
  redius: number;
}

type Shape = Circle | Square

function getArea(shape: Shape) {
  if (shape.kind === 'cirle') { // 窄化
    return Math.PI * shape.redius ** 2
  }
}

// 或者

function getArea(shape: Shape) {
  switch (shape.kind) {
    case "cirle":
      return Math.PI * shape.redius ** 2
    case "square":
      return shape.sideLength ** 2
    default:
      const _example: never = shape
      return _example
  }
}

总结

到此这篇关于TypeScript学习笔记之类型窄化篇的文章就介绍到这了,更多相关TypeScript类型窄化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • jq.ajax+php+mysql实现关键字模糊查询(示例讲解)

    jq.ajax+php+mysql实现关键字模糊查询(示例讲解)

    下面小编就为大家分享一篇jq.ajax+php+mysql实现关键字模糊查询(示例讲解),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • js 判断 enter 事件

    js 判断 enter 事件

    本文是在Web中通过Javascript判断键盘按键事件,并改变按键的默认动作。
    2009-02-02
  • ajax前台后台跨域请求处理方式

    ajax前台后台跨域请求处理方式

    本篇文章通过前台跨域请求处理以及后台跨域的数据处理方式介绍,详细分析了ajax跨域的问题,对此有需要的朋友学习下。
    2018-02-02
  • 在JS方法中返回多个值的方法汇总

    在JS方法中返回多个值的方法汇总

    本文给大家汇总了在javascript方法中返回多个值的方法,都是在个人项目中检验过的,这里推荐给大家,有需要的小伙伴可以参考下。
    2015-05-05
  • Rollup处理并打包JS文件项目实例代码

    Rollup处理并打包JS文件项目实例代码

    rollup是一款用来es6模块打包代码的构建工具(支持css和js打包)。这篇文章主要介绍了Rollup处理并打包JS文件项目实例,需要的朋友可以参考下
    2018-05-05
  • 从Immutable.js到Redux函数式编程

    从Immutable.js到Redux函数式编程

    这篇文章主要为大家介绍了从Immutable.js到Redux函数式编程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • js表单提交和submit提交的区别实例分析

    js表单提交和submit提交的区别实例分析

    这篇文章主要介绍了js表单提交和submit提交的区别,结合实例形式较为详细的分析了js表单提交和submit提交具体实现方法与使用技巧,需要的朋友可以参考下
    2015-12-12
  • JS+HTML5 canvas绘制验证码示例

    JS+HTML5 canvas绘制验证码示例

    这篇文章主要介绍了JS+HTML5 canvas绘制验证码,结合实例形式分析了HTML5 canvas图形绘制相关操作技巧,需要的朋友可以参考下
    2018-12-12
  • JS实现打字游戏

    JS实现打字游戏

    这篇文章主要为大家详细介绍了JS实现打字游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • JavaScript中数组成员的添加、删除介绍

    JavaScript中数组成员的添加、删除介绍

    这篇文章主要介绍了JavaScript中数组成员的添加、删除介绍,本文主要讲解push()、unshift()、pop()、shift()等函数的应用,需要的朋友可以参考下
    2014-12-12

最新评论