玩转typescript,使开发更高效

1,724 阅读10分钟

首先我要说明一下为什么要写这篇文章?

团队协作中变量类型传错

写代码中变量名称拼写等低级错误,不提示错误造成难排查错误

代码不规范,可读性差

Typescript作为新的知识不能快速入手

typeScript涵盖的知识还是比较多的,我们通过一节课让大家统统掌握也不现实,所以本篇文章主要我来讲一些入门方面的知识,期待大家能更好的喜欢上这门语言,并应用到自己的项目中

本篇文章的目标是让大家:

认识学习typescript的必要性

了解typescript的基础知识

学习一门新的语言,我们首先要了解这门新语言会给我们带来什么?有什么特点? 我们来通过名字初步看看typeScript到底是什么 我们看到typeScript,分解开来就是"type"和"script",字面意思是“用类型来标注javascript”

typeScript是微软提出的,基于javascript做了一些优化调整,使javascript更加的规范化,有助于开发者的使用、理解和使程序的健壮性。

学习一门新语言我们先要看看发展趋势以及受欢迎度,我们先通过stackoverflow网站的一组统计数据了解一下:

全球开发者最想学的语言排名

全球所有语言薪资排名

从以上图标我们了解到typescript是非常受欢迎的,而且学习掌握这门语言,可以有力的提高我们的竞争力

为了省点笔墨,下面我们用TS来表示typeScript

TS为什么如此受欢迎,到底能解决什么问题?

谈到解决什么问题,我们先来探讨一下工作中遇到的一些问题

比如有一天接到需求,让在原有项目上做新的需求,这时候我们就可能需要调用别人写的方法,为了搞清楚函数的参数类型以及用法就需要读别人的代码,读的过程那叫一个累呀,心中万马奔腾;或者是读自己之前写的代码,经过了这么久的打磨,可能会想自己之前为什么要这么写,瞬间有急迫的重构想法,好不容易重构好了,才发现很多调用的地方都需要改掉,还有看运行的时候是不是报错,简直是日了狗了......

比如我们的页面一片白屏还不报错,经过许久排查才发现是参数拼写错误.....

比如我们调用接口报错,满有底气的对后端说你这接口为什么老报错?结果后端经过查询后说你参数类型传错了,瞬间有被打脸的感觉.....

这样的例子比比皆是,如果用了typescript,这些问题都可以得到解决或者说根本出现不了

使用typeScript带来的好处

1.开发效率显著提升

2.bug数量减少

3.错误提前暴露,在编译阶段暴露

4.代码更规范

5.查文档更方便

使用TS的过程中我们会感觉到很多BUG在我们刚写完代码就提示出错,这就是错误提前暴露在编译阶段;协同开发的时候因为代码更规范了,标注也很详细具体,甚至对某些方法的调用都可以写一个文档,这时候我们调用已有的方法会感觉很舒服。

TS是什么?

通过上图我们看到,ts包含了es5,es6,es7等知识,ts并不是一门新的语言,它就是js的一个超集,最终要编译成纯粹的JS才能在浏览器上运行。

ts的核心在**"TYPE"**上,重点在类型,下面我们会讲到

TS很难吗?

其实只要把握一条核心,TS其实很容易掌握:

是什么类型就要赋值给什么类型

说了这么多,大家肯定迫不及待的想学习TS了,下面我们就讲一下TS的基础知识

TS的基础知识

1.原始数据类型(布尔值、数值、字符串、null、undefined)类型定义

2.赋值任意值类型和联合类型

3.类型推断

4.对象类型定义(接口和泛型)

5.函数参数及返回值类型定义

6.JS内置对象的类型定义

原始数据类型(布尔值、数值、字符串、null、undefined)

let u: boolean = false;
let d: number = 6;
let m: string = 'Tom’;
let n: null = null;
let u: undefined = undefined;

如上面,我们希望这个参数是什么类型,就在参数后面写 ": 类型" 就可以了, 是不是很好理解

我们可能会问,如果定义了一个类型,比如number,这时候我们可能赋的值是null或undefined,会不会报错?

其实 undefined 和 null 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给任意 类型的变量,所以不会报错。

// 这样不会报错
let d: number = undefined;

赋值任意值类型或联合类型

有时候我们需要给参数赋值多种类型,比如不想限制死参数类型,这时候我们就需要思考:

我需要赋值多种类型怎么办?

": any" 标注后代表任意类型,这样我们赋值任意类型的值都是可以的

let m: any = 'seven’;
m = 7; 

但有时候我们不想输入“任意类型”,我们只想输入某些类型

这时候就引入了"联合类型"的概念,何谓 联合类型,怎么使用?

联合类型从字面上推断就是同时符合多种类型,多种类型之间用管道符"|"分割

比如需要参数是字符串或数值,可以这么写

let n: string | number;
n = 'seven’;
n = 7; 

对于函数的参数也是一样的,在参数后面直接加类型

function g(s: string | number): number {    
	return s.length;
}
function a(): void {    
	alert('My name is Tom’);
} 

大家有没有注意到函数这里还有一个类型,那这个类型是干什么的? 大家都知道函数不仅有参数类型,还有返回值的类型,这个类型代表的是函数的返回值类型

类型推断

有的时候,如果我们不设置类型,ts会进行类型推断,基本推断原理就是第一次赋值的 数据类型

let m= 'seven’;
m = 7; 

事实上,它等价于:

let m: string = 'seven’;
m = 7; 

所以上面这样定义会报错,因为推断的是字符串,却赋值了数值。 如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类 型检查:

let n;
n = 'seven’;
n = 7; 

这个也是很好理解的,定义的时候没有赋值,那就没有办法推断具体属于什么类型,只能按任意类型来推断。

对象类型定义(接口、泛型)

在讲对象类型定义的时候,我们会接触到 "接口" 的概念。

我们先来回忆一下传统的接口,就是按照服务端的要求提交对应格式数据,

Ts中的接口也是类似这样的,我们通过一个例子就可以很快明白接口的定义

interface Person {    
	name: string;    
	age: number;
}
let tom: Person = {    
	name: 'Tom',    
	age: 25
}; 

仔细观察上面例子,我们看到定义一个接口要用 "interface"来声明,后面跟一个接口名称,例如"Person",接口名称要首字母大写,这是规范,就不过多赘述了。

定义的变量比接口少了一些属性是不允许的

interface Person {    
	name: string;    
	age: number;
}
let tom: Person = {    
	name: 'Tom’
}; 

多一些属性也是不允许的

interface Person {    
	name: string;    
	age: number;
}
let tom: Person = {    
	name: 'Tom',    
	age: 25,    
	gender: 'male’
}; 

所以,赋值的时候,变量的形状必须和接口的形状保持一致 这时候我们感觉不够灵活,因为工作中可能有些属性可有可无,这时候可以用ts的可选属性 可选属性怎么标示呢? 只要在 ":"前加上"?" 就可以了,代表这个属性可有可无

interface Person {    
	name: string;    
	age?: number;
}
let tom: Person = {    
	name: 'Tom’
}; 

但是要注意 可选属性要放在确定属性的后面,否则会报错,例如下面这样写是不对的

interface Person {;    
	age?: number;
	name: string
}
let tom: Person = {    
	name: 'Tom',    
	age: 25
}; 

但是依然可能会需要添加一些事先不需要声明的属性,我们可以使用ts的对象任意属性,使用  [propName: string] 定义了任意属性取 string 类型的值

interface Person {    
   name: string;    
   age?: number;    
   [propName: string]: any;
}
let tom: Person = {    
   name: 'Tom',    
   gender: 'male’
}; 

一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集

这也比较好理解,既然有任意属性的类型了,那我已经定义的确定属性和可选属性是不是要符合任意类型的规范, 例如下面这样就会报错,因为任意类型是字符串类型,而age可选属性的类型是number,number不是string的子集

interface Person {    
	name: string;    
	age?: number;    
	[propName: string]: string;
}
let tom: Person = {    
	name: 'Tom',    
	age: 25,    
	gender: 'male’
}; 

一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,则可以使用联合类型: 例如上面报错的例子可以这么改:

interface Person {    
	name: string;    
	age?: number;    
	[propName: string]: string | number;
}
let tom: Person = {    
	name: 'Tom',    
	age: 25,    
	gender: 'male’
}; 

数组的类型

类型 + 方括号、数组泛型

let f: number[] = [1, 1, 2, 3, 5];
let f: Array<number> = [1, 1, 2, 3, 5];

let list: any[] = ['1', 25, { w: '111' }]; 

上面的例子,聪明的你一看就明白了,数组类型也一样,也是参数后面加 ": 类型",而这个类型可以用 "类型+[]"或者"Array<类型>" 表示

上面说了用接口来标示对象,那可不可以用接口来标示数组呢?

当然是可以的

用接口表示数组,标示方法为 "[index: 类型]: 类型",例如:

interface n {    
	[index: number]: number;
}
let fibonacci: n = [1, 1, 2, 3, 5]; 

函数的类型

对于函数,我们在学习了上面的各种类型后,很容易的就看懂下面的函数参数和返回值类型标注了,我就不过多赘述了,直接看例子:

函数申明

function sum(x: number, y: number): number {    
	return x + y;
} 

函数表达式

let mySum = function (x: number, y: number): number {    
	return x + y;
}; 

用接口定义函数的形状

interface SearchFunc {    
	(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {   
	return source.search(subString) !== -1;
} 

有时候我们的函数某些参数可能可有可无,一句话,跟上面一样,来看例子

function buildName(firstName: string, lastName?: string) {    
	if (lastName) {        
		return firstName + ' ' + lastName;    
	} else {        
		return firstName;    
	}
}
let tomcat = buildName('Tom', 'Cat’);
let tom = buildName('Tom'); 

ECMAScript 的内置对象

let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred’);
let d: Date = new Date();
let r: RegExp = /[a-z]/; 

DOM 和 BOM 的内置对象

let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div’);
document.addEventListener('click', function(e: MouseEvent) {  
	// Do something
}); 

讲了这么多,迫不及待的我赶快来试试吧

老套路,先安装,再使用

TS的安装

npm install -g typescript
//执行上面命令安装

$ tsc -v 
//执行这个命令如果输出下面的版本号,则表示安装成功
Version 3.2.2

新建一个 test.ts 的文件

var message:string = "Hello World”
 
console.log(message)

执行命令 tsc test.ts,我们看到自动编译好的JS文件

var message = "Hello World";
 
console.log(message);

说明TS是要编译成JS才能在浏览器上运行

话说我们的基础课程就讲到这里了,虽然没说话,只是打字,但还是很口干,一个字渴

希望大家看完最后干三件事:收藏、点赞、关注

欢迎大家评论区留言,如果大家想更深入的学习TS,我们下一集讲一下TS的精通课程,期待我的下一集课程吧

就这样