Typescript

一、ts 开发环境安装

用 nodejs 安装 ts 的开发环境: npm i -g typescriptnpm i -g ts-node编写 ts 文件后执行tsc即可编译 ts 文件为 js 文件。通过tsc -init可生成配置文件。

二、ts 中的类型声明

1
2
3
4
5
let 变量: 类型;
let 变量: 类型 = 值;
function fn(参数: 类型,参数: 类型): 返回类型{
...
}

若值类型与变量类型不相同,则会报错。与 js 相比,ts 增加了为变量声明类型的功能,在开发中可以避免很多麻烦。

三、ts 中的类型

类型描述
number1,-1,22数字
string‘hello’,“hello”,`hello`字符串
booleantrue,false布尔值
字面量本身变量值就是限制类型
any*任意类型
unknown*类型安全的 any
void空值(undefined)无值
never没有值不为任何值
object{age:20}任意 js 对象
array[1,2,3]任意 js 数组
tuple[1,2]元素,定长数组
enumenum{A,B}枚举
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//字面量类型声明
let a: 10;
a = 10; //正确,可赋值为10
a = 20; //报错,只能为10

let b: "male" | "female"; // b只能等于"male"或"female"
b = "male"; //正确
b = "female" //正确
b = "hello" //报错
let c: number | string; //c只能为number类型和string类型

let d: any; //关闭类型检查,不建议使用
//声明变量若不指定类型,则自动判断any
//any类型变量可赋值给任何变量

let e: unknown = "hi";
//unknown类型可以被赋予任何值,但不能赋值给任何变量

let f:string = "hello";
f = e as string; //类型断言,可以让unknown类型变量赋值给相应变量

function fun():never{ //永远不会返回结果
//一般用于抛出异常
throw new Error('出错');
}

let g: {name:string,age?:age};
//属性名后加冒号代表属性可选。

let h: {name:string,[propName:string]?:any};
//[propName:string]?:any表示任意类型属性,且属性名为string,值可选

let i:(a: number,b: string)=>boolean;
//表示i为一个函数,且形参一为number类型,形参二为string类型,返回值为boolean类型

enum Gender{
Male = 1,
Female = 2
}
let j :{name:string,gender:Gender};
j={
name:"张三",
gender:Gender.Male // 1
}

四、ts 编译选项

tsc 文件名 -w监视某文件,当改变时就重新编译

要监视全部文件,需要执行tsc -init生成tsconfig.json文件,运行tsc -w即可监视全部文件。

配置属性

1
2
3
4
{
//include用来表示哪些文件需要被编译 **表示任意目录 *表示任意文件
"include": ["./src/**/*"]
}
1
2
3
4
{
//exclude用来表示哪些文件需要被排除
"exclude": []
}
1
2
3
{
"extends": "./路径/xxx.json" //表示继承于某个配置文件
}
1
2
3
4
{
//表示编译文件列表,编译文件少时才会使用
"files": ["xx.ts", "xx.ts", "xx.ts"]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"compilerOptions": {
"target": "ES6", //指定ts被编译的es版本
"module": "commonjs", //指定模块化规范
"lib": ["dom", "es6"], //指定要需要使用的库,一般不用添加该项,默认即可
"outDir": "./dist", //指定编译后文件所在目录
"outFile": "./dist/app.js", //将代码合并为一个文件,用的不多
"allowJs": false, //是否对js进行编译,默认false
"checkJs": false, //检查js代码是否符合语法规范,默认false
"removeComments": false, //是否移除注释,默认false
"noEmit": false, //不生成编译后文件,默认false
"noEmitOnError": false, //有错误时不生成编译后文件,默认false
"alwaysStrict": false, //编译后文件开启严格模式,默认false
"noImplicitAny": false, //不允许隐式any,默认false
"noImplicitThis": false, //不允许不明确类型的this,默认false
"strictNullChecks": false, //严格检查空值,默认false
"strict": false //所有严格检查的总开关,默认false,全开或全关
}
}

五、ts 的类

1
2
3
4
5
6
7
8
9
class Person {
readonly name: string = "张三"; //readonly只读属性
static age: number = 20; //static静态属性
static hello() {
//lei'fan
}
}
const p = new Person();
p.hello(); //调用静态方法可以直接 类.方法名

六、ts 的构造函数和 this

创建构造函数

1
2
3
4
5
6
7
class Dog {
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const dog = new Dog("狗1", 2);

this 代表 Dog 的每个实例对象,对象是谁 this 就是谁。

七、继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
call() {
console.log("call");
}
}
class Dog extends Animal {
run() {
console.log("狗跑");
}
call() {
console.log("狗叫");
}
}
class Cat extends Animal {
run() {
console.log("猫跑");
}
call() {
console.log("猫叫");
}
}

继承将多个类中共有的代码写道一个父类中,供其他子类继承。

八、super 关键字

super 用于在子类中调用父类的方法或属性。

1
2
3
4
5
6
7
8
class Cat extends Animal {
run() {
console.log("猫跑");
}
call() {
super.call(); //输出call,调用的是父类方法
}
}

在子类构造函数中默认会调用 super(),并传入值。

1
2
3
4
5
6
7
8
9
10
11
class Cat extends Animal {
constructor(name: string, age: number) {
super(name, age);
}
run() {
console.log("猫跑");
}
call() {
super.call(); //输出call,调用的是父类方法
}
}

九、抽象类

抽象类以 abstract 开头,不能用于创建对象,只能用于继承。

1
2
3
4
5
6
7
8
9
abstract class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
abstract call(); //抽象方法,没有方法体,只能定义在抽象类中,子类必须进行重写。
}

十、接口

1
2
3
4
5
6
7
8
9
10
11
12
13
interface MyCode{     //定义一个类中应该包含哪些属性和方法
name: string;
age: number;
hello():string;
}
interface MyCode{ //可重复定义
hobby: string;
}
const obj: MyCode={ //将同名接口中的属性与方法都要定义
name:'张三';
age:20;
hobby:'打球';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface MyCode {
//定义一个类中应该包含哪些属性和方法
name: string;
hello(): string;
}
//实现接口
class MyClass implements MyCode {
name: string;
constructor(name: string) {
this.name = name;
}
hello(): string {
return "hello";
}
}
  • 接口可重复定义,但实际效果是将所有同名接口合为一个接口。

  • 接口可以限制类的结构

  • 接口中所有的属性没有实际的值

  • 接口只定义对象的解构卖不考录实际值

十一、属性的封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Cat {
private _name: string;
private _age: number;
constructor(name: string, age: number) {
this._name = name;
this._age = age;
}
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
get age(): number {
return this._age;
}
set age(value: number) {
this._age = value;
}
}
  • publich 可在任意位置访问(默认值)

  • private 私有属性,私有属性只能在类内部访问

  • protected 受保护的属性,只能在当前类以及其子类中进行访问

十二、泛型

在定义函数或类时,如果遇到类型不明确就可以使用泛型

1
2
3
4
5
function fn<T>(a: T): T {
return a;
}
fn(10); //不指定泛型
fn<string>("hello"); //指定泛型
1
2
3
4
5
function fn2<T, K>(a: T, b: K): T {
return a;
}
fn2(123, "123");
fn2<string>(123, "123");
1
2
3
4
5
6
7
interface Inter{
length: number;
}
function fn3<T extend Inter>(a:T):number{ //T必须是Inter的子类
return a.length;
}
fn3('123');

十三、webpack 打包 ts

  1. 初始化项目
    npm init -y

  2. 安装 webpack
    npm i -D webpack webpack-cli typescript ts-loader

  3. 新建 webpack 配置文件webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cosnt path = require('path');
module.exports = {
entry: "./src/index.ts",
output: {
path: path.resolve(__dirname,'dir'),
filename: "bundle.js"
},
module: {
rules:[
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node-modules/
}
]
}
}
  1. 在 package.json 的 scripts 属性中添加

1
"build": "webpack"

打包可执行npm run build