TypeScript
TypeScript是什么?
TypeScript
是JavaScript
的一个超集,支持ECMAScript 6
标准(ES6
教程)。TypeScript
由微软开发的自由和开源的编程语言。TypeScript
设计目标是开发大型应用,它可以编译成纯JavaScript
,编译出来的JavaScript
可以运行在任何浏览器上。TypeScript
本身并非什么高深的技术,凡是有JavaScript
基础的同学都可以轻松掌握
TypeScript的特性
TypeScript
是一种给JavaScript
添加特性的语言扩展。增加的功能包括:- 类型批注和编译时类型检查
- 类型推断
- 类型擦除
- 接口枚举
Mixin
- 泛型编程
- 名字空间
- 元组
Await
- 以下功能是从
ECMA 2015
反向移植而来:- 类
- 模块
lambda
函数的箭头语法- 可选参数以及默认参数
TypeScript
和JavaScript
的区别
TypeScript
是JavaScript
的超集,扩展了JavaScript
的语法,因此现有的JavaScript
代码可与TypeScript
一起工作无需任何修改,TypeScript
通过类型注解提供编译时的静态类型检查。TypeScript
可处理已有的JavaScript
代码,并只对其中的TypeScript
代码进行编译。- 优势一:类型化思维方式,使得开发更加严谨,提前发现错误,减少改
Bug
时间。 - 优势二:类型系统提高了代码可读性,并使维护和重构代码更加容易。
- 优势三:补充了接口、枚举等开发大型应用时
JS
缺失的功能。 Vue 3
源码使用TS重写,释放出重要信号:TS
是趋势。Angular
默认支持TS
;React
与TS
美配合,是很多大型项目的首选
TypeScript
的安装
-
有两种主要的方式来获取
TypeScript
工具:-
通过
npm(Node.js包管理器) tsc –v
查看版本-
npm:包的管理器
-
install:安装,简写为i
-
global:全局,简写-g
-
全局安装,当前电脑任意位置都可以使用
npm install -global typescript
-
局部安装,当前项目中安装
// 初始化项目 npm init -y(英文目录) npm init(中文目录) npm install typescript
-
-
安装
Visual Studio
的TypeScript
插件
-
-
注意:由于
Vscode
的终端默认使用powershell
,默认禁止输入脚本(指令)- 解决办法:以管理员身份运行
powershell
,终端执行set-ExecutionPolicy RemoteSigned
;输入y
- 解决办法:以管理员身份运行
Hello TypeScript(全局)
-
通常我们使用
.ts
作为TypeScript
代码文件的扩展名-
目录结构:
-
在
index.html
中<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body></body> <script src="./index.js"></script> </html>
-
在
index.ts
中console.log("Hello TypeScript!");
-
使用方式:
-
打开终端,通过
tsc fileName
编译转化为js
文件(注意你的当前目录所在) -
这个时候你就会发现文件目录多出来一个
index.js
文件 -
打开
index.html
,控制台打印结果。或者也可以在终端node
执行index.js
文件
-
Hello TypeScript(局部)
-
创建文件夹
typescript
-
在终端初始化项目
npm init -y
-
这个时候
typescript
文件夹下会多出一个package.json
文件 -
终端局部安装
npm install typescript
-
package.json文件夹里面会多出一个
"typescript": "^4.7.2"
,这个就表示安装的typescript
版本是4.7.2
的
TypeScript 转换为 JavaScript
TypeScript 转换为 JavaScript
-
目录结构
-
在
index.ts
中console.log("Hello TypeScript!");
-
自动编译
TypeScript
-
安装
npm i ts-node-dev --save-dev
-
packages.json
中添加脚本{ "name": "typescript", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "ts-node-dev --respawn --transpile-only index.ts" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "typescript": "^4.7.2" } }
-
在终端中使用
npm start
启动 -
这样我们就不需要在修改
index.ts
的同时还有一直在控制台输入node index.ts
,当你修改index.ts
保存后它就会自动执行。
-
TypeScript 构成
- TypeScript 程序由以下几个部分组成:
- 模块
- 函数
- 变量
- 语句和表达式
- 注释
TypeScript 基础类型
类型 | 例子 | 描述 |
---|---|---|
number | 1,-33,2.5 | 任意数字 |
string | ‘hi’,“hi”,hi | 任意字符串 |
boolean | true、false | 布尔值 true 或 false |
字面量 | 其本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的 any |
void | 空值(undefined) | 没有值(或 undefined) |
never | 没有值 | 不能是任何值 |
object | {name:“孙悟空”} | 任意的 JS 对象 |
array | [1,2,3] | 任意 JS 数组 |
tuple | [4,5] | 元组,TS 新增类型,固定长度数组 |
enum | enum{A,B} | 枚举,TS 中新增类型 |
TypeScript 基础类型
-
number
:双精度64
位浮点值。它可以用来表示整数和分数// 十进制 let a: number = 10; // 这里限制了a的数据类型为number console.log(a); // 10 // 八进制 let b: number = 0o744; console.log(b); //484 // 二进制 let c: number = 0b1010; console.log(c); // 1010 // 十六进制 let d: number = 0xf00d; console.log(d); // 61453
TypeScript 基础类型
-
boolean
let a: boolean = false; let b: boolean = true; let c = true; console.log(a, b, c);
-
string
let a: string = "hello"; setTimeout(() => { a = "world"; console.log(a); }, 2000); console.log(a);
TypeScript 基础类型
-
字面量:也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围
// 字面量类型 限制取值范围 // 传的参数的取值只能是 "red" | "green" | "yellow" | "blue" 不能是别的 const a = (b: "red" | "green" | "yellow" | "blue") => { console.log(b); // red }; a("red"); const foo = (n: 10 | 20 | 30 | "red") => { console.log(n); // 10 }; foo(10);
-
any
// 任意类型 let a: any = "aaa"; a = 10; a = false; console.log(a); // false
-
unknown
// 不知道是什么类型 let a: unknown = "a"; a = 10; console.log(a); // 10
TypeScript 基础类型
-
tuple
// tuple 元组 类似js中的数组,它是元素可以是任意类型的 let x: [number, string]; x = [10, "hello"];
-
array
// array 数组 let arr: Array<any> = [1, 2, 3, "hello", true]; let arr1: Array<number> = [1, 2, 3]; let arr2: Array<Object> = [{ name: "Linux", age: 28 }]; console.log(arr); // [1, 2, 3, "hello", true] console.log(arr1); // [1, 2, 3] console.log(arr2); // [{ name: "Linux", age: 28 }]
-
enum
枚举// 通常情况下我们使用枚举类型定义一类常量 enum Color { red = "red", blue = "blue", } console.log(Color.red); // red console.log(Color.blue); // blue // 枚举类可以作为变量的数据类型 let a: Color = Color.red; // a = '' 警告 console.log(a); // red
TypeScript 基础类型
-
类型断言(类型转换)
-
有些情况下,变量的类型对于我们来说是很明确,但是
TS
编译器却并不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式-
第一种
let a: unknown = "hello ts"; let lg: number = (a as string).length; console.log(lg); // 8
-
第二种
let a: unknown = "hello ts"; let lgx: number = (<string>a).length; console.log(lgx); // 8
-
TypeScript函数(一)
-
函数定义
// 普通定义函数方式 function foo() { console.log("foo"); // foo } foo(); // 声明式 const bar = function () { console.log("bar"); // bar }; bar();
-
函数返回值
-
我们会希望函数将执行的结果返回到调用它的地方,通过使用
return
语句就可以实现。 -
在使用
return
语句时,函数会停止执行,并返回指定的值。 -
注意:返回值的类型需要与函数定义的返回类型(
return_type
)一致// function function_name(): return_type { // // 语句 // return value; // } function foo(): boolean { return true; } console.log(foo()); // true function bar(): Object { return { name: "foo", age: 42, }; } console.log(bar()); // { name: 'foo', age: 42 } // 没有返回值 function bo(): void {} bo();
-
TypeScript函数(二)
-
带参数函数
-
在调用函数时,您可以向其传递值,这些值被称为参数。
-
这些参数可以在函数中使用。
-
您可以向函数发送多个参数,每个参数使用逗号 , 分隔
function bar(a: number, b: string) { console.log(a, b); // 10 hello } bar(10, "hello");
-
-
可选参数
-
在
TypeScript
函数里,如果我们定义了参数,则我们必须传入这些参数,除非将这些参数设置为可选,可选参数使用问号标识 ? -
可选参数必须跟在必需参数后面。 如果上例我们想让
b
是可选的,a
必选,那么就要调整它们的位置,把b
放在后面。如果都是可选参数就没关系。// 可选参数 ? // 可选参数需要放在固定参数的后面 function foo(a: number, b?: string) { console.log(a, b); // 10 undefined } foo(10);
-
TypeScript函数(三)
-
默认参数
-
可以设置参数的默认值,这样在调用函数的时候,如果不传入该参数的值,则使用默认参数
// 参数的默认值 // 参数有了默认值,就可以不传,不传就以默认值为准 // 传了以实际值为准 function test(a: number, b: number = 10) { console.log(a, b); // 10 10 // 10 20 } test(10); test(10, 20);
-
-
剩余参数
-
有一种情况,我们不知道要向函数传入多少个参数,这时候我们就可以使用剩余参数来定义。
-
剩余参数语法允许我们将一个不确定数量的参数作为一个数组传入。
// 剩余参数 function boo(a: number, ...args: any[]) { console.log(a, ...args); // 10 [ 20, 30, 40 ] } boo(10, [20, 30, 40]);
-
TypeScript函数(四)
-
匿名函数(函数表达式)
const msg = function () { return "Hello"; }; console.log(msg()); // Hello
-
匿名函数自调用
(function () { console.log("hello"); })();
-
Lambda
函数(箭头函数)const a = (a: number, c: boolean = false, b?: string): number => { console.log(a, b, c); // 10 "hello" true return 10; }; a(10, true, "hello");
TypeScript 联合类型
-
联合类型(
Union Types
)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值。-
注意:只能赋值指定的类型,如果赋值其它类型就会报错。
-
语法:
Type1|Type2|Type3
let a: number | string; a = 10; a = "hello"; console.log(a); // hello
-
-
联合类型数组
// 可以放入number类型和string类型的元素 let b: Array<number | string> = []; b = [10, "hello", 20]; console.log(b); // 只能同时放入number类型或者string类型 let c: number[] | string[]; c = [10, 20]; console.log(c); // [10, 20] c = ["hello", "ts"]; console.log(c); // [ 'hello', 'ts' ] const foo = (a: number | string): void => { console.log(a); // 10 // hello }; foo(10); foo("hello");
TypeScript 类(一)
-
TypeScript
是面向对象的JavaScript
-
类描述了所创建的对象共同的属性和方法。
-
TypeScript
支持面向对象的所有特性,比如 类、接口等 -
定义类的关键字为
class
,后面紧跟类名,类可以包含以下几个模块(类的数据成员):- 字段 − 类里面声明的变量。字段表示对象的有关数据。
- 构造函数 − 实例化时调用,可以为类的对象分配内存。
- 方法 − 对象要执行的操作。
-
创建实例化对象
-
我们定义出来的类是可以作为类型去使用的
// 创建类 class Car { // 字段[属性、成员变量] brand: string; timestamp: Date; // 构造函数 // constructor 初始化参数 constructor(brand: string, timestamp: Date) { this.brand = brand; this.timestamp = timestamp; } // 方法(普通函数) disp(): void { console.log(`品牌:${this.brand}`); } // 箭头函数 sayHi = (name: string): string => { console.log(name); // hello return name; }; } // 创建对象的方式一 const car = new Car("法拉利", new Date()); console.log(car.brand, car.timestamp); // 法拉利 2022-05-26T10:36:54.145Z car.disp(); // 品牌:法拉利 car.sayHi("hello"); // 创建对象的方式二 const baoma: Car = { brand: "宝马", timestamp: new Date(), // 重写方法 disp() {}, sayHi(): string { return ""; }, }; baoma.disp(); const foo = (car: Car) => { console.log(car); // Car { // sayHi: [Function (anonymous)], // brand: '法拉利', // timestamp: 2022-05-28T02:08:48.847Z // } }; foo(new Car("法拉利", new Date()));
TypeScript 类(二)
-
static
关键字-
static
关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用// 被 static 修饰的方法和属性 叫做静态方法和静态属性 // 静态方法和属性 在使用的时候需要被类直接调用 不需要实例化(不需要创建对象) class Person { static title = 10; static sayHi() { console.log("Hello"); // Hello } } console.log(Person.title); // 10 // 可以赋值 console.log((Person.title = 20)); // 20 Person.sayHi();
-
-
instanceof
运算符instanceof
运算符用于判断对象是否是指定的类型,如果是返回true
,否则返回false
-
访问控制修饰符
-
TypeScript
中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript
支持3
种不同的访问权限public
(默认) : 公有,可以在任何地方被访问。(写或不写都是public
)protected
: 受保护,可以被其自身以及其子类和父类访问。private
: 私有,只能被其定义所在的类访问
TypeScript 类的继承
-
TypeScript
支持继承类,即我们可以在创建类的时候继承一个已存在的类,这个已存在的类称为父类,继承它的类称为子类。 -
类继承使用关键字
extends
,子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。 -
TypeScript
一次只能继承一个类,不支持继承多个类,但TypeScript
支持多重继承(Student
继承Person
,Children
继承Student
)。 -
继承类的方法重写
-
类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。
-
其中
super
关键字是对父类的直接引用,该关键字可以引用父类的属性和方法。class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } sayHi = (): void => { console.log(`${this.name}:我今年 ${this.age}`); }; } class Student extends Person { constructor(name: string, age: number) { super(name, age); } } class Children extends Student { constructor(name: string, age: number) { super(name, age); } // 方法也可以被重写 sayHi = (): void => { console.log("hi"); }; }
TypeScript抽象类
- 什么是抽象类?
- 被
abstract
修饰的类,就是抽象类,抽象类又叫基类(父类) - 证明只能作为父类使用,不能作为子类使用
- 被
abstract
修饰的方法叫做抽象方法,被abstract
修饰的属性叫做抽象属性,抽象类在被被继承时,抽象方法和抽象属性必须重写
- 被
- 为什么要有抽象类?
- 为了规定类中的一些属性和方法,在被继承的时候必须重写,所以被
abstract
修饰的方法和属性,在继承时必须重写,分别叫做抽象类和抽象方法
- 为了规定类中的一些属性和方法,在被继承的时候必须重写,所以被
- 抽象类的特点:
- 抽象类自身无法实例化,必须由子类(派生类)进行实例化
- 抽象类也可以拥有自己的抽象方法和属性
- 抽象类中的抽象方法和抽象属性必须被重写
TypeScript抽象类的定义与使用
abstract class Animal {
abstract name: string;
// 抽象方法不能有方法体
abstract speak(): void;
abstract say: () => void;
}
class Dog extends Animal {
// 抽象类在被被继承时,抽象方法和抽象属性必须重写
name: string;
constructor(name: string) {
super();
this.name = name;
}
speak(): void {
console.log(`${this.name}:汪汪汪`);
}
say = () => void {};
}
const dog = new Dog("泰迪");
console.log(dog);
dog.speak();
TypeScript接口
-
接口定义使用
interface
关键字 -
接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性
-
需要注意接口不能转换为
JavaScript
。 它只是TypeScript
的一部分。interface IPerson { firstName: string; lastName: string; sayHi: () => void; } const customer: IPerson = { firstName: "Tom", lastName: "Hanks", sayHi: (): string => { return "Hi there"; }, }; interface IA { a: string; } // 类实现接口 同时实现多个接口 class Student implements IPerson, IA { firstName: string; lastName: string; a: string; constructor(firstName: string, lastName: string, a: string) { this.firstName = firstName; this.lastName = lastName; this.a = a; } sayHi = (): void => { console.log(`${this.firstName}${this.lastName}`); }; } const stu = new Student("王", "五", "好"); stu.sayHi();
实现接口
-
接口的实现使用
implements
关键字 -
同一个类可以实现多个接口
-
抽象类也可以实现接口
-
接口不能实现接口,但可以使用
extends
扩展interface IPerson { firstName: string; lastName: string; } // 接口可以被扩展 interface IB extends IPerson { age: number; } class Student implements IB { age: number; firstName: string; lastName: string; }
泛型
-
在定义函数和类时,遇到类型不明确的时候就可以使用泛型
-
泛型可以指定多个
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } // T 可以是任意字符 一般使用 T K V function foo<T>(a: any) { console.log(a); } const p = new Person("张三", 20); foo<Person>(p); foo<Number>(10);