搭建开发环境

1、安装node.js。

2、使用npm全局安装typescript。

1
npm install -g typescript

3、第一个typescript程序

1
console.log("hello world!")

进行编译:

1
tsc hello_world.ts

编译成功后会生成hello_world.js文件。

基本类型

基本类型

类型例子描述
number1,33,2.5任意数字
string“hello”任意字符串
booleantrue、false布尔类型
字面量其本身限制变量的值就是该自变量的值
any*任意类型
unknown*类型安全的any
void空值(undefind)没有值(undefined)
never没有值不能是任何值
object{name:”小猪”}任意的js对象
array[1,2,3]任意js数组
tuple[4,5]固定长度的数组
enumenum(A,B)枚举类型

声明变量

1
2
3
4
5
6
7
8
9
10
11
12
let a: number;  // 声明变量a指明类型为number。
// a="hello"; 编辑器会报错、编译过程会报错,但会生成js文件。
let b: string; // 声明变量b指明类型为string。
let c: boolean = true; //声明变量c为boolean类型,并赋初值。
let d = false;
// d=123; 报错,变量d的声明和定义是同时进行的,TS会自动判断类型。


// 定义函数形参a、b的类型为number,函数返回值类型为number
function sum(a: number, b: number): number {
return 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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// 字面量类型
let e: 10;
// e="xiaozhu"; // 报错
let f: "male" | "female"; // 取或
f = "male"; // 正确
// f = "hello" 错误
let g: boolean | string; // 取或

// any 任意类型 默认类型
let h: any;
h = 10; // 正确
h = "hello"; // 正确

//unknown 类型
let i: unknown;
i = 10; // 正确
i = "hello"; // 正确
// 与any区别?
/**
* any类型的变量可以赋值给任意的数据类型
* unknown类型不可以
* 例如:
* f=h; 正确
* b=i; 错误
* 我偏要赋值怎么办捏??-做类型判断
* if(typedef(i)==="string") b=i; // 正确
*/
// 类型断言 告诉编译器 i的类型就是string
b = i as string;
b = <string>i;

//never 永远不会返回结果
function Jun(): never {
throw new Error("报错了!");
}

//object类型
let j: object;
j = {};
// {}指定对象中包含哪些属性
let k: {
name: string, // 必传
age: number // 必传
}
let l: {
name: string,
age?: number // age属性可有可无 可选属性
}
let m: {
name: string, // name 必传
[propName: string]: any //任意类型的属性,没有、一个或多个
}
// n是一个函数
let n: (a: number, b: number) => number


//array类型
let o: string[];
let p: number[];
let q: Array<number>;

//tuple类型 固定长度的数组
let r: [string, string];

//enum 枚举类型
enum Gender {
Male = 0,
Female = 1
}
let s: { name: string, gender: Gender };
s = {
name: "小猪猪",
gender: Gender.Female
}

// 类型别名
type MyType = string | boolean | object;
let u: MyType;

编译选项

  • 热加载单个文件

    1
    2
    tsc app.ts -w
    # app.ts发生变化后自动编译
  • 热加载所有文件

    • 新建tsconfig.json配置文件
    1
    2
    3
    {

    }
    • 运行tsc -w监视全部文件
  • tsconfig.json属性

    • include指定编译的文件的地址
    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
    "include": [
    "./src/**/*" //根目录下src目录下的任意目录下的任意文件
    ]
    /**
    * **表示任意目录
    * *表示任意文件
    */
    }
    • exclude指定不编译的文件的地址
    1
    2
    3
    4
    5
    6
    {
    ...
    "exclude": [
    "./src/noc/**/*"
    ]
    }
    • extends指定要继承的配置文件的地址
    1
    2
    3
    4
    {
    ...
    "extends": ""
    }
    • files指定要编译的文件
    1
    2
    3
    4
    5
    {
    "files": [
    "src/app/app.ts"
    ]
    }
    • compilerOptions编译器的选项
    属性含义可选值
    target指定ts被编译的ES的版本“ES3”, “ES5”, “ES6”, “ES2015”, “ES2016”, “ES2017”, “ES2018”, “ES2019”, “ES2020”, “ES2021”, “ES2022”, “ESNext”
    module指定要使用的模块化的规范“CommonJS”, “AMD”, “System”, “UMD”, “ES6”, “ES2015”, “ES2020”, “ESNext”, “None”, “es2022”, “node12”, “nodenext”
    lib用来指定项目中要使用的库……(一般不需要动)
    outDir用来指定编译后文件所在的目录“./dist”
    outFile将编译后的文件合并到一个文件中“./dist/app.js”
    allowJs是否对js文件进行编译true、false
    checkJs是否检查js代码规范true、false
    removeComments是否移除注释true、false
    noEmit不生成编译后的文件true、false
    noEmitOnError有错误时不生成文件true、false
    alwaysStrict是否开启严格模式true、false
    noImplicitAny是否不允许默认属性类型为anytrue、false
    noImplicitThis是否不允许不明确类型的thistrue、false
    strictNullChecks是否严格检查空值true、false
    strict所有严格检查的总开关true、false
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    {
    ...
    "compilerOptions": {
    "target": "es6",
    "module": "es2015",
    "lib": ["dom"], //一般默认
    "outDir": "./dist",
    "outFile": "./dist/all.js",
    "allowJs": false,
    "checkJs": false,
    "removeComments": false,
    "noEmit": false,
    "noEmitOnError": false,
    "alwaysStrict": false,//有导入导出时自动进入严格模式
    "noImplicitAny": false,
    "noImplicitThis": false,
    "strictNullChecks": false,
    "strict": false,
    }
    }

使用webpack打包TS代码

1、项目初始化

1
npm init -y

生成package.json

2、安装依赖

1
npm i -D webpack webpack-cli typescript ts-loader

-D 开发依赖

Refusing to install package with name “webpack” under a package?

修改package.json中的name属性不为webpack即可。

3、配置webpack.config.js

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
// 引入一个包
const path = require("path");

//webpack中的所有配置信息
module.exports = {
//定义环境
mode: "development",
//指定入口文件
entry: "./src/index.ts",

//指定打包文件所在目录
output: {
//指定打包文件的目录
path: path.resolve(__dirname, "dist"),
//打包后文件的名字
filename: "bundle.js",
},

//指定打包时使用的模块
module: {
//指定要加载的规则
rules: [
{
//test指定的是规则生效的文件
test: /\.ts$/,
use:'ts-loader',
exclude:/node-moudules/,
},
],
},
};

4、创建tsconfig.json

1
2
3
4
5
6
7
{
"compilerOptions": {
"module": "es6",
"target": "es6",
"strict": true
}
}

5、修改package.json,添加指令

1
2
3
4
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack" //添加的
},

6、自动生成html文件并引入js

  • 安装插件
1
npm i -D html-webpack-plugin
  • 在webpack.config.js中配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
// 引入html插件
const HTMLWebpackPlugin=require('html-webpack-plugin')
//webpack中的所有配置信息
module.exports = {
...
//配置插件
plugins:[
new HTMLWebpackPlugin(
{
//title:"我的html" //无模板时指定自动生成的html的title属性
template:"./src/index.html" //指定生成的html的模板
}
),
]
};

7、配置webpack服务器

  • 安装插件
1
npm i -D webpack-dev-server
  • 配置package.json
1
2
3
4
5
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack serve --open"
},

​ 执行npm start 热更新。

8、编译前删除已编译文件插件

  • 安装插件
1
npm i -D clean-webpack-plugin
  • 在webpack.config.js中配置
1
2
3
4
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
plugins: [
new CleanWebpackPlugin(),
],

9、设置可以引用的模块

1
2
3
4
5
6
7
8
//webpack中的所有配置信息
module.exports = {
...
//设置可以引用的模块
resolve: {
extensions: [".ts", ".js"],
},
};

10、使用Babel解决多浏览器版本兼容问题

  • 安装依赖
1
npm i -D @babel/core @babel/preset-env babel-loader core-js
  • 修改webpack.config.js配置文件
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
45
output: {
...
environment:{
arrowFunction:false // 不使用箭头函数
}
},
module: {
//指定要加载的规则
rules: [
{
//test指定的是规则生效的文件
test: /\.ts$/,
use: [
//配置babel
{
//指定加载器
loader: "babel-loader",
// 设置babel
options: {
//设置预定义环境
presets: [
[
//指定环境的插件
"@babel/preset-env",
//配置信息
{
//要兼容的浏览器
targets: {
chrome: "88",
},
//指定core-js的版本
"corejs": "3",
//使用corejs的方式
useBuiltIns: "usage", //按需加载
},
],
],
},
},
"ts-loader", // 谁在后面谁先执行
],
exclude: /node-moudules/,
},
],
},

面向对象

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
//使用class定义类
class Person {
// 属性
name: string;
age: number;
// 静态属性,不需要创建对象也可以使用
static beautiful: boolean = true;
// 只读属性,不可以修改
readonly rich: boolean = false;

// 构造函数
constructor(name: string, age: number) {
// this表示当前的实例
this.name = name;
this.age = age;
}

//定义函数
sayHello(): void {
console.log("I love you.");
}
//定义静态函数
static sayPromise(): void {
console.log("I will marry you.");
}
}

const ps = new Person('小猪', 18);
console.log(ps.name);
console.log(Person.beautiful);

ps.sayHello();
Person.sayPromise();

继承

继承之后子类拥有父类所有的方法和属性,子类可以拥有自己的方法。

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
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHi() {
console.log("I am an animal.");
}
}


// 继承之后子类拥有父类所有的方法和属性
class Dog extends Animal {
constructor(name: string, age: number) {
//调用父类的构造函数(子类的构造函数必须调用super)
super(name, age);
}
// 方法重写
sayHi() {
console.log("I am a Dog.");
}

}

class Cat extends Animal {
constructor(name: string, age: number) {
super(name, age);
}
sayHi() {
console.log("I am a cat!");
}
}

const XiaoMing = new Dog('xiaozhu', 19);
const XiaoZhu = new Cat('xiaozhu', 19);

抽象类

1
2
3
4
5
6
7
8
9
10
11
//定义抽象类  不能用animal类直接创建对象
abstract class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 抽象方法 没有具体实现 具体实现由子类决定
abstract sayHi():void;
}

接口

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
//接口用来定义一个类的结构(属性和方法)
//同时也可以当成类型声明去使用
//只定义结构不考虑实际值
//接口定义的是一个规范
interface myInterface {
name: string;
age: number;
}

interface myInterface {
gender: boolean;
//定义的方法没有方法体
sayHello(): void;
}

const obj: myInterface = {
name: "xiaozhu",
age: 18,
gender: false,
sayHello(): void {
console.log("good morning.");
}
}

//实现接口,所有属性和方法全部要有
class MyClass implements myInterface {
name: string;
age: number;
gender: boolean;
constructor(name: string, age: number, gender: boolean) {
this.age = age;
this.name = name;
this.gender = gender;
}
sayHello(): void {
console.log("hello");

}
}

属性的封装

类的属性不能直接赋值,而应当由方法进行修改

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
class Person {
// 添加属性修饰符
// public 任意改(默认值)
// private 私有属性,只能在类内部进行修改 子类不可访问
// protected 只能在当前类及其子类中使用
// 通过在类中添加方法使得私有属性被外部访问
private _name: string;
private _age: number;
constructor(name: string, age: number) {
this._name = name;
this._age = age;
}
// 使用get方法获取name属性
getName(): string {
return this._name;
}
// 使用set方法设置name属性
setName(name: string): boolean {
this._name = name;
return true;
}


// 使用TS的方法来处理
//-----------------------------------//
// TS中设置getter方法
get name() {
return this._name;
}
// TS中设置setter方法
set name(name: string) {
this._name = name;
}
}

const pers = new Person01("小猪", 18);

//调用get方法 看起来像属性
console.log(pers.name);
//调用set方法 看起来像属性赋值
pers.name = "可爱猪猪";

补充:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
//等价写法:
class Animal{
constructor(public name:string,public age:number){
}
}

泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//在定义函数或类时,遇到类型不明确的可以使用泛型
function fn<T>(a: T): T {
return a;
}
// 可以直接调用具有泛型的函数
fn(10);
fn<string>('hello');

function fn2<T, K>(a: T, b: K): T {
return a;
}

fn2<number, string>(123, 'hello');


interface Inter {
length: Number
}
// 泛型T必须实现了Inter接口
function fn3<T extends Inter>(){

}

基于typescript的贪食蛇游戏:github