TypeScript学习笔记之类型窄化篇

目录
  • 前言
  • 类型推论
  • 真值窄化
  • 相等性窄化
  • in操作符窄化
  • instanceof窄化
  • 窄化的本质
  • 联合类型的窄化
  • 总结

前言

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类型窄化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 你不知道的 TypeScript 高级类型(小结)

    前言 对于有 JavaScript 基础的同学来说,入门 TypeScript 其实很容易,只需要简单掌握其基础的类型系统就可以逐步将 JS 应用过渡到 TS 应用. // js const double = (num) => 2 * num // ts const double = (num: number): number => 2 * num 然而,当应用越来越复杂,我们很容易把一些变量设置为 any 类型,TypeScript 写着写着也就成了 AnyScript.为了让大家能更加深入

  • TypeScript Type Innference(类型判断)

    TypeScript 是微软开发的 JavaScript 的超集,TypeScript兼容JavaScript,可以载入JavaScript代码然后运行.TypeScript与JavaScript相比进步的地方 包括:加入注释,让编译器理解所支持的对象和函数,编译器会移除注释,不会增加开销:增加一个完整的类结构,使之更新是传统的面向对象语言. 为什么会有 TypeScript? JavaScript 只是一个脚本语言,并非设计用于开发大型 Web 应用,JavaScript 没有提供类和模块的概

  • TypeScript 学习笔记之基本类型

    在 TypeScript 中一共有 7 种基本类型. 1.boolean 复制代码 代码如下: var isDone: boolean = false; 2.number 代表 JavaScript 中的数字.在 JavaScript 中,无论是"整数"还是"浮点数",都是以双精度浮点类型存储的. 复制代码 代码如下: var height: number = 6; 3.string 代表字符串.跟 JavaScript 一样,可以使用一对双引号(")或一

  • TypeScript入门-基本数据类型

    大致介绍 TypeScript是由C#语言之父Anders Hejlsberg主导开发的一门编程语言,TypeScript本质上是向JavaScript语言添加了可选的静态类型和基于类的面向对象编程,它相当于是JavaScript的超集 ES5.ES6和TypeScript的关系: 安装 首先需要安装npm,然后在输入 npm install -g typescript 安装完成后,因为TypeScript是以.ts结尾的,要想运行就得把他编译js文件,编译的方法特别简单就是使用tsc命令 ts

  • TypeScript学习笔记之类型窄化篇

    目录 前言 类型推论 真值窄化 相等性窄化 in操作符窄化 instanceof窄化 窄化的本质 联合类型的窄化 总结 前言 TS最好用的地方就是强类型,随之而来的就是类型窄化,摸鱼的时候顺道总结下. 类型推论 TypeScript里,在有些没有明确指出类型的地方,类型推论会帮助提供类型 Example: let x = [0, 1, null] // number let x = Math.random() < 0.5 ? 100 : "helloword" // number

  • TypeScript 学习笔记之 typeScript类定义,类的继承,类成员修饰符

    目录 1.类的定义 2.类的继承 3.修饰符 前言: typeScript 中的类与 ES6 中的类非常相似,如果不知道 ES6 中的类,建议先学习下 ES6 中的 class .本篇文章重点介绍 typeScript 中的类定义.继承以及修饰符. 1.类的定义 类描述了所创建的对象共同的属性和方法.typeScript 支持面向对象的所有特性,比如类.接口等. 在 typeScript 中定义类的时候,使用 class 关键字,类名首字母使用大写,类可以包含以下三个模块: ​字段​ - 字段是

  • Python3.4学习笔记之类型判断,异常处理,终止程序操作小结

    本文实例讲述了Python3.4类型判断,异常处理,终止程序操作.分享给大家供大家参考,具体如下: python3.4学习笔记 类型判断,异常处理,终止程序,实例代码: #idle中按F5可以运行代码 #引入外部模块 import xxx #random模块,randint(开始数,结束数) 产生整数随机数 import random import sys import os secret = random.randint(1,10) temp = input("请输入一个数字\n")

  • TypeScript学习之强制类型的转换

    前言 使用强类型变量常常需要从一种类型向另一种类型转换,通常使用ToString或ParseInt可以来实现一些简单的转换,但是有时候需要像.NET语言中那样将一种类型显示的转换为另一种类型,在TypeScript规范中,被称为"类型断言",它仍然是类型转换,只是语法是有些不同.下面来详细看看TypeScript的强制类型转换. TypeScript强制类型转换 在 TypeScript 中将一个 number 转换成 string ,这样做会报错: var a:number = 12

  • Lua学习笔记之类型与值

    基础介绍 Lua是一种动态类型的语言.在语言中没有类型定义的语法,每个值都带有其自身的类型信息.在Lua中有8种基本类型,分别是: nil(空)类型 boolean(布尔)类型 number(数字)类型 string(字符串)类型 userdata(自定义类型) function(函数)类型 thread(线程)类型 table(表)类型 以上是Lua中的8中基本类型,我们可以使用type函数,判断一个值得类型,type函数返回一个对应类型的字符串描述.例如: local iValue = 10

  • Flask框架学习笔记(一)安装篇(windows安装与centos安装)

    Flask 依赖于两个外部库: Werkzeug  和  Jinja2  . Werkzeug 是一个 WSGI (在 web 应用和多种服务器之间开发和部署的标准 Python 接口) 的工具集,Jinja2 负责渲染模板. 一.安装 Flask安装的前提条件 1.已安装python2.x版本 2.已安装easy_install 在安装flask之前,你必须要先安装python和easy_install,easy_install只支持pyhon2.x版本不支持python3.x版本,所以你在安

  • ORACLE学习笔记-添加更新数据函数篇

    一.添加数据 /*添加数据*/ insert into STU values('stu0004','赵一',18,1,"kc0004"); insert into STU(STU_ID,STU_NAME,STU_AGE,STU_SET ) values('stu0013','储十一',19,1); 说明:如果不指定将数据添加到那个字段,那么此时必须列出全部数据,如果列出字段,则一一对应,必须列出约束不为空的所有字段,否则报错. 二.更新数据 /*更新数据*/ update STU SE

  • Vue学习笔记进阶篇之函数化组件解析

    这两天学习了Vue.js 感觉函数化组件这个地方知识点挺多的,而且很重要,所以,今天添加一点小笔记 介绍 之前创建的锚点标题组件是比较简单,没有管理或者监听任何传递给他的状态,也没有生命周期方法.它只是一个接收参数的函数. 在这个例子中,我们标记组件为 functional, 这意味它是无状态(没有 data),无实例(没有 this 上下文). 一个 函数化组件 就像这样: Vue.component('my-component', { functional: true, // 为了弥补缺少的

  • JavaWeb学习笔记分享(必看篇)

    自定义列表 <dl></dl>:表示列表的范围 **在里面 <dt></dt>:上层内容 **在里面 <dd></dd>:下层内容 有序列表 <ol></ol>:有序列表的范围 --属性 type:设置排序方式,1(默认),a,i.. **在ol标签里面 <li>具体内容</li> 无序列表 <ul></ul>:无序列表的范围 --属性 type:circle(空

随机推荐