关于前端:使用TypeScript类型注解编写更干净的JS代码

3次阅读

共计 3967 个字符,预计需要花费 10 分钟才能阅读完成。

TypeScript 能够看作是 JavaScript 的超集,不仅蕴含了 JavaScript 的所有内容,还拓展了语法、规定了类型束缚,使得咱们能够编写更洁净、残缺的代码。

类型注解

TypeScript 提供了很多数据类型,通过类型对变量进行限度,称之为类型注解,应用类型注解后,就不可能随便变更变量的类型。

以下代码定义了一个字符串类型的变量,如果把它更改为数字类型时,代码编译阶段就会间接报错,提醒 “Type ‘number’ is not assignable to type ‘string'”。

这样保障变量的数据类型是固定的,那么它所能应用的办法也是确定的,不会呈现变量原本是字符串,调用了 toUpperCase 办法,起初在未测试到的某场景无心中把它改为数字类型后,调用 toUpperCase 间接报错的状况。

类型推导

当变量没有写数据类型时,ts 外部会进行 ” 类型推导 ”,通过上下文赋值语句判断出该变量的数据类型,所以在类型注解较为简单时且其能精确主动推导出类型时,不写类型注解对代码品质也没有影响。

TS 和 JS 共有的数据类型

TypeScript 蕴含了 JavaScript 所领有的数据类型,string、number、symbol、array、boolean、undefined、null、object。

其中,array 在定义的时候须要加上数组中的每一个数据的类型,是字符串、数字还是对象,这就使得数组中不能够写多种数据类型,如果有须要写多种数据类型的状况,能够间接不加类型注解,会主动进行【类型推导】。

let str: string = "string";
let num: number = 0;
let sym: symbol = Symbol("sym");

let arr1: string[] = ['alice', 'kiki', 'heidi']
let arr2: object[] = [{ name: 'alice'}]
let arr3: number[] = [1, 2, 3]

let flag: boolean = false;
let und: undefined = undefined;
let nu: null = null;
let user = {name: "alice"};

下面的对象 user 也是没有加类型注解的,因为如果定义为 object 类型,无奈获取和批改 user 对象上的属性。

这是因为 user 是 object 类型,但 object 类型上没有 name 属性,所以编译阶段会间接报错,所以对于对象能够不加类型注解,让其主动进行类型推导。

TS 独有的数据类型

此外 TypeScirpt 还减少了很多 JavaScript 没有的数据类型

any

any 是一个 “ 万金油 ” 的数据类型,示意 “ 任意 ” 数据类型,当变量的类型不确定且有可能发生变化时,能够定义为 any,此时变量的数据类型能够被随便更改,这其实会带来一些安全隐患。

比方上面的代码,将字符串当作函数应用,undefined 应用数字的办法。因为是 any 类型,类型有可能被改成字符串、数字、布尔值,所以这样的代码不会被 ts 检测出问题,但在运行时必定是会报错的。

let message: any = "message";
message();

message = 0;
message = undefined;
message.toFixed();

unknown

当一个变量的类型临时不确定时,能够应用 unknown 用来限度其类型。

let flag = true
let result: unknown;
if (flag) {result = 'Hello World'} else {result = 888}

它和 any 有些像,但区别在于 unknown 是不能被赋值给除了 any 和 unknown 类型的变量,这样使得 unknown 的值不能被乱用到其它中央。

void

当函数没有返回值时,实际上返回的就是 undefined,void 通常用来示意函数返回值为 undefined 或者 null。

以下模式都是能够的

function add(): void {}

function sub(): void {return undefined}

function mul(): void {return null}

当存在返回值时,编译是会报错的。

never

never 示意永远不会存在的类型,如果函数为死循环或者抛出异样时能够应用。

function foo(): never {while (true) {}}

function catchError(): never {throw new Error("error");
}

当咱们封装工具函数时,开始规定的函数入参为 string 类型,但可能后续在其它人开发过程中,减少了 number 类型,为了防止保护时遗记对该类型数据进行解决,能够把入参赋值给 never 类型的变量,使得编译不通过来避免开发者逻辑疏漏。

tuple

tuple 意思是元组,和数组比拟类似,但元组和数组还是存在以下区别。

  • 数组中元素数据类型倡议是统一的,当数据类型不统一时思考放到元组或者对象。
  • 元组中每个元素都有本人的个性,能够通过索引值获取。
// 数组
const array: string[] = ["alice", "kiki"];
// 元组
const tuple: [string, number] = ["alice", 20];

函数参数和返回值

申明函数时,在函数的每个参数后增加类型注解,以申明函数承受的参数类型,限度参数类型、参数个数。

在函数列表前面定义的类型注解,用于限度函数返回值类型的。

// 限度参入类型
function foo(message: string, no: number) {}
// 限度返回值
function baz(message: string): string {return "string";}

当入参类型 / 个数没有达到注解要求时,编译会标红以揭示。

对象类型、可选类型、联结类型 也都是能够用于规定函数入参的。

  • 对象类型,定义对象中每个参数的数据类型
  • 可选类型,用?示意,意味着该参数是非必传的,必须写在必选类型前面
  • 联结类型,用 | 示意,A | B 意味着入参类型是 A 和 B 中的任意一个
function getPoint(point: { x: number; y: number; z?: number}) {}
getPoint({x: 10, y: 20});
getPoint({x: 10, y: 20, z: 30});

function printId(id: string | number) {}
printId(1);
printId("alice");

function foo(message?: string) {}
foo("message");
foo();

当须要规定的类型比拟长时,能够通过 type 关键字来定义类型别名

同时参数类型为【可选类型】能够了解该参数类型与 undefined 的【联结类型】,以下两个参数的入参实质上是一样的

function foo(message?: string) {}
foo("message");
foo();

function baz(message: string | undefined) {}
baz("message");
baz(undefined);

类型断言

有时候 TypeScirpt 获取到的类型是比拟宽泛的,这个时候能够应用类型断言,通过关键字 as 定义具体数据类型。

比方以下定义了两个类,Student 继承自 Person 类,且领有本人的 studying 办法,定义 sayHello 办法,要求入参类型为 Person,此时创立 Student 的实例对象 student,并调用 sayHello 办法,传入 student。

class Person {}
class Student extends Person {studying(){}}

function sayHello(p: Person){}
const student = new Student()
sayHello(student)

以上代码在编译的时候是没有问题的,但如果在 sayHello 办法中想要调用 Student 实例对象的 studying,是不能够的,因为尽管传入的参数是 Student 的实例对象,但它在 TypeScript 中只能被检测为 Person 类型,而 Person 上是没有 studying 办法的。

要想正确调用,须要应用类型断言规定入参的理论类型

function sayHello(p: Person){(p as Student).studying()}

非空类型断言

通过!符号来使不能通过编译的代码不被标红揭示,但如果运行阶段代码存在问题,依然是会抛出谬误的。

字面量

通过 const 定义的变量的数据类型为字面量类型,字面量里的值就是该变量赋值的内容。

通过字面量类型,可用于规定变量的抉择范畴,比方 flex 布局的 direction 能够抉择 row 或者 colums

type DirectionType = "row" | "colums";
let direction: DirectionType = "row";
direction = "colums";

当变量赋值为它类型注解中所没有蕴含的内容时,是会标红揭示的。

类型放大

类型放大示意当变量数据类型的范畴比拟大时,咱们能够通过 if、switch、in、typeof、instanceof 等形式进行判断来放大的变量的类型,以达到更精准的操作。

比方一个函数的参数类型可能为 string 和 number,间接获取 length 属性 是会报错的。因为只有 string 类型的变量能够获取到 length,但在 number 类型上是不存在的,所以此时能够通过 typeof 来判断入参类型,这个判断步骤也称为 ” 类型爱护 ”。

这些 ts 中的类型注解,能够帮忙开发者更好标准开发时的代码,缩小线上故障~

以上就是对于 TypeScript 类型注解的内容,对于 js 和 ts,还有很多须要开发者把握的中央,能够看看我写的其余博文,继续更新中~

正文完
 0