前言

TypeScript是JavaScript的、带有类型的超集,并且能够编译为普通的JavaScript。它是一种建立在JavaScript上的编程语言,也是一种工具。它是一个强大的编译器,你可以在代码上运行,将TypeScript编译为JavaScript。
它为JavaScript添加新功能和优势。但是,TypeScript在JavaScript环境无法运行,浏览器无法执行类型脚本。
优点:可读性好;类型检查;代码补全;易于维护;入门简单。它使编写干净的代码变得非常容易。
TypeScript添加类型和数据对类型非常重要,我们必须更明确地了解事情的运作方式,可以避免很多使用类型的意外和不必要的错误。TypeScript是可配置的。
TypeScript可以在开发过程中帮助我们进行检查,允许我们更早地修复错误。TypeScript只能在开发期间获得支持,不在运行时,因为这些类型脚本功能和检查没有内置到JavaScript引擎中,这样的逻辑就不能在浏览器中执行,它只能在开发期间执行。

一、安装TypeScript

首先,确保你的电脑安装了Node.js。
输入命令npm install -g typescript;把TypeScript编译器安装到全局,这样,所有的typescript项目都可以使用它。安装完成,我们可以使用 tsc 命令来执行 TypeScript的相关代码,输入tsc - v命令来查看版本号,看到TypeScript的版本号说明安装成功了。
在这里插入图片描述

二、基本使用

新建一个LearningTypeScript文件夹,用VSCode打开。在这个文件夹中新建一个demo01.ts文件。里面写一点内容,如下所示。
在这里插入图片描述
在终端输入tsc demo01.ts,TypeScript编译器就可以把ts文件编译成js文件了。
在这里插入图片描述
可以看到在文件夹中生成了一个新的demo01.js文件。
在这里插入图片描述
运行一下,输入:node demo01.js,可以看到输出了数字13。
在这里插入图片描述

三、配置编译版本

那么,JavaScript的版本这么多,tsc如何知道应该编译成哪种版本呢?
tsc默认会编译成ES3版本。我们试一下在demo01.ts文件中加一个async异步函数,它是ES1017版本的,应该如何编译呢?
在这里插入图片描述
我们可以在文件夹中新建一个tsconfig.json配置文件,通过compilerOptions属性来配置tsc编译器,target⽤于指定要编译成的版本,这里指定ES2017。
在这里插入图片描述
现在,再次运行tsc,后面不需要加文件名了。因为有了tsconfig.json文件之后,这个文件夹会自动成为typescript的项目,tsc会自动找到ts文件并进行编译。如果制定了文件名,那么这个配置文件的配置就会被忽略了。
在这里插入图片描述
打开js文件,发现和ts文件的async函数一样。
在这里插入图片描述

四、相关特性

1.基本类型

给变量定义类型有两种方式,一种是隐式的,一种是显式的。
隐式类型由typescript根据变量的值来推断类型。代码写法与js一样,但是,它后面不能用其他类型的值给它重新赋值。比如定义一个let a = 10,a = ‘hello’;这样编译器就会报错,提示Type 'string' is not assignable to type 'number'
在这里插入图片描述

基本类型与javascript一样:boolean number string undefined null 。显示类型的定义,就跟之前运行的ts代码示例一样,用冒号加类型来显示地规定这个变量是什么类型的。
格式如下:
let 变量名: 类型 = 初始值

// : boolean 表示是布尔类型的
let b: boolean = true;
// : number  表示是数值类型的
let c: number = 22;
// 字符串类型
let s: string = 'john';
// undefined
let u: undefined = undefined;
// null
let n: null = null;

如果想让一个变量可以是任何类型的,那么可以把它的类型定义为any。声明为 any 的变量可以赋予任意类型的值。
例如:给a一个数字类型的值,再改成字符串,这时候就不报错啦。
在这里插入图片描述

2.函数

类型也可以用在函数的参数和返回值中。

比如下面的例子中:定义一个加法函数,接收类型为number的两个参数a、b;返回值的类型也是number,返回值的类型定义在参数列表的小括号后面;再后面才是函数体。
函数类型的定义实际上就是: 参数的类型、**返回值的类型**
有两种方式定义函数,如下所示:

// 1.普通函数function
函数名(形参1: 类型=默认值, 形参2:类型=默认值): 返回值类型 { }

// 2.箭头函数
const 函数名(形参1: 类型=默认值, 形参2:类型=默认值):返回值类型 => { }

Eg:
在这里插入图片描述

函数返回值:如果函数没有返回值,那么,函数返回值类型为:void

//类型也可以用在函数的参数和返回值中
// 比如:定义一个函数add(),接收类型为number的参数n1、n2;返回值的类型为number,返回值的类型定义在参数列表的小括号后面;再后面才是函数体。
function add(n1: number, n2: number): number {
  // 通过使用 return 语句就可以实现返回值,在使用return语句时,函数会停止执行,并返回指定的值。
  return n1 + n2;
}

// 如果函数没有返回值,可以使用void类型表示函数没有返回值。如下所示:
// function add(n1:number,n2:number):void{
//   console.log(n1+n2)
// }

// 调用函数
// 不能使用字符串变量来接收函数的返回值,会报错。比如:let res:String = add(1,2);提示“number类型不能赋值给string类型!”
// 不能给函数传递字符串。比如:add("1",2);那么编译器会提示“字符串1不能传给number类型的函数!”
// TypeScript中调用函数时,必须传递与参数列表一样的参数,不能像js一样,可以不传或只传一个参数。比如:add(1);就会提示“没有给n2传值!”
// 在 TypeScript 函数里,如果我们定义了参数,则我们必须传入这些参数。除非将这些参数设置为可选,可选参数使用问号标识 ?。
add(1, 2);

可选参数:在参数后面加问号 ?

注意:可选参数只能出现在参数列表的最后,可选参数后面不能再有必填参数出现!!!
如下所示,函数fn()中传入了一个可选参数m,但是它放在了必填参数的前面,就会出现如下报错:
在这里插入图片描述
A required parameter cannot follow an optional parameter.
必选参数不能跟在可选参数后面。

3.组合类型 Union types |

如果一个变量可以有多个类型,但是又不想使用any破坏类型检查,就可以使用组合类型。

组合类型表示一个值的类型可以是多个类型中的一种。使用|来分隔每一个类型。

let 变量: 类型1 | 类型2 | 类型3 .... = 初始值
比如:一个变量p既可以是数字类型也可以是字符串类型。

let p:number | string = 10;
p = "hello typescript";

不过,代码这样看起来不大方便。并且这个组合类型只能给p使用。如果有别的变量也是数字或字符串类型,还要重复定义。
要解决这个问题,可以使用type关键字给这个组合类型起一个别名,也就是**类型别名**让代码更易读,也方便变量使用。
例子如下:

// 定义一个type名为NumStr。定义了一个number | string的联合类型变量,因此给变量赋值数值或字符串都是可以的。 
type NumStr = number | string;

// p变量定义一个数字
let p:NumStr = 10;
p = "hello typescript";

// q变量定义一个字符串值
let q:NumStr = "hi";

// 组合类型也可以直接使用字面值来定义,这样,就规定了一个变量的取值范围。
// 比如:想让字符串类型的变量只能去on或者off两者之一;那么就可以这么定义,在变量o后面直接使用on off
let o: "on" | "off" = "on";
// 可以给它赋值off
o = "off";
// 但是,不能给它赋值除了on、off之外的值,会报错,提示"hah不能赋值给用on或off定义的类型里面!"
// o = "hah";

4.交叉类型 Intersection types &

交叉类型利用&将多个类型合并为一个类型。交叉类型会包含所有类型的成员。

如下,显然就出现了报错,因为并不会有任何值满足既是number类型又是string类型的 ,一般不会这么写。
在这里插入图片描述
对象写法:

let p1:{id:number,name:string} & {age:number};  // p1必须有 id name age
p1 = {id:1,name:"ym",age:18}

如果漏写了属性,就会出现如下报错,几个属性都需要包括在内才行。
在这里插入图片描述
一个属性写了多个类型限制,像下面这么写,也会报错:
在这里插入图片描述
这样写才对:
如果一个属性出现多个类型的设置,那么需要都满足才行。id是number类型,并且为8,需要同时满足才行。

let p1:{id:number,name:string} & {age:number,id:8};  // p1必须有 id name age
p1 = {id:8,name:"ym",age:18}

如下所示,对象p包含接口IA与接口IB里面的所有属性。
在这里插入图片描述
也可以结合类型别名使用,如下所示:
在这里插入图片描述

5.类型别名

类型别名用来给一个类型起个新名字。它只是起了一个新名字,并没有创建新类型。

type 别名 = 类型
在这里插入图片描述
类型别名重复定义会报错:
在这里插入图片描述

6.对象类型----接口

TypeScript 中,使用interfaces接口,接口是用来规范一个对象里应该都有哪些属性,包括它的名字和它的类型。接口一般首字母大写。
约定俗成:接口的命名一般以大写字母I开头

interface 接口名  {
    属性1: 类型1;
    属性2: 类型2;
}
// 定义一个接口IPerson    接口首字母要大写
interface IPerson {
     // 接口里面有属性和类型;每个属性后面用分号分隔
    name:string;
    age:number;
    hobby:string;
}

// 根据接口IPerson定义对象,对象实现了接口IPerson的属性和方法。  
// 对象里面只能包括接口里定义的属性。对象里面不能多也不能少定义属性,会提示错误信息;
let jisoo:IPerson = {
    name:"jisoo", 
    age:25,   
    hobby:"sing",
}

对象与接口定义的属性类型要对应。
IPerson接口中定义的name是string类型的,对象中如果把name赋值为number类型,就会报错。
在这里插入图片描述
定义的变量⽐接⼝多了或者少了⼀些属性都是不允许的。
在这里插入图片描述
在这里插入图片描述
接口中定义了属性,定义空对象也会报错:
在这里插入图片描述

可选属性:有时我们希望不要完全匹配接口中的所有属性,那么可以用可选属性,表示该属性可以不存在,在属性后添加问号 ?

// 带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?
interface IPerson1 {
  name: string;
  hobby:string;
  // age为可选属性
  age?: number;
}

let James: IPerson1 = {
  name: 'James',
  hobby:"跑步",
};

在这里插入图片描述

接口继承 extends关键字

利用extends实现接口继承。如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用。格式如下所示:

interface 接口2 extends 接口1 {
    属性1: 类型1, // 接口2中特有的类型
    ... 
}

如下所示:接口IChild继承接口IPerson,那么IChild就继承了IPerson的全部属性,那么IChild一共就有4个属性了。
在这里插入图片描述
也可以实现继承多个接口:

interface 接口3 extends 接口1,接口2 {
    属性1: 类型1// 接口3中特有的类型
    ... 
}

如下所示,接口IC继承了接口IA和IB,那么IC就会包含IA和IB的所有属性。
在这里插入图片描述

接口定义不确定的属性

接口定义了不确定的属性,那么根据接口定义的对象就可以写任意的属性和值。
在这里插入图片描述

接口实现implements

实现接口的类必须要全部实现接口中的所有属性和方法(可选属性可不写)
在这里插入图片描述

7.数组类型

给数组规定类型,可以保证里面的元素都是同一个类型,以防在统一处理数组元素时,混进来其他类型的元素,导致异常。或者防止意外给数组元素赋了其他类型的值。
要定义数组类型的方法有如下两种:
第一种,可以在类型后面加一对空的方括号 [],表示由此类型元素组成的一个数组;

let 变量: 类型[] = [1...]

第二种方式是使用数组泛型,Array<元素类型>。

let 变量: Array<类型> = [1...]
// 定义一个number类型的数组  
// 方式1:可以在类型后面加一对空的方括号 [],表示由此类型元素组成的一个数组
let arr1: number[] = [1, 2, 3];
// 方式2:是使用数组泛型,Array<元素类型>。
// 泛型属于面向对象语言中比较高级的特性。 应用在数组身上,同样可以用来规定数组中元素的类型。
let arr2: Array<number> = [1, 2, 3];

8.元组tuple

我们知道数组中元素的数据类型都一般是相同的(any[] 类型的数组可以不同),如果存储的元素数据类型不同,则需要使用元组。

// TypeScript中有一个元组tuple。它是一个有限元素数量的数组(固定的数组),并且长度也是固定的。但是,每个元素需要分别指定是什么类型。
// 比如:这里有一个三元组就是这个数组中有三个元素。规定第一个元素是number类型,第二个元素是string类型,第三个元素是boolean类型。
// 声明一个元组并初始化
let mytup:[number,string,boolean] = [1,"joy",true];

访问元组:元组中元素使用索引来访问,第一个元素的索引值为 0,第二个为 1,以此类推第 n 个为 n-1。
元组运算:我们可以使用以下两个函数向元组添加新元素或者删除元素。

  • push() 向元组添加元素,添加在最后面。
  • pop() 从元组中移除元素(最后一个),并返回移除的元素。

9.类型断言

类型断言可以将一种类型强制转换成另外一种类型。
有两种方式:

// 尖括号写法
let str:any = "hello";
let strLength:number  = (<string>str).length;

// as 写法
let str:any = "hello";
let strLength:number  = (str as string).length;
 // as HTMLElement 是类型断言
  let myChart = echarts.init(document.getElementById("charts") as HTMLElement);

10.泛型

概念:在定义函数、接口、类的时候不预先指定具体的数据类型,而是在使用函数、接口、类的时候才能确定数据的类型。

目的:为了提高可复用性,增强灵活性。

定义一个函数,传入参数n,限制类型为number类型,函数返回值也限制为number类型。
在这里插入图片描述
如果想返回别的类型,就需要添加新的,代码会越来越冗余。
在这里插入图片描述
这时,我们就可以用到泛型了。
在这里插入图片描述

在这里插入图片描述
泛型也可以定义多个类型变量:
在这里插入图片描述

泛型在类型别名上的使用:
在这里插入图片描述
泛型在接口上的使用:
举例如下:
在这里插入图片描述
在这里插入图片描述
泛型约束 extends关键字

格式: 泛型约束是约束泛型的,需要在<>里面写。

下面的代码,给泛型P进行了约束,约束成string或者number类型的,由于boolean不满足约束的类型限制,就会出现报错。
在这里插入图片描述
结合一下类型别名:
在这里插入图片描述

11.小技巧

通过给TypeScript添加注释内容,那么在使用时就会有注释的提示了,可以方便一些。
在这里插入图片描述

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐