1. 开发环境搭建

1.下载Node.js

64:https://nodejs.org/dist/v14.15.1/node-v14.15.1-x64.msi

32:https://nodejs.org/dist/v14.15,1/node-v14.15.1-x86.msi

  1. 安装node.js
  2. 使用npm全局安装typescript
npm i -g typescript
  1. 创建一个ts文件
  2. 执行文件
tsc xxx.ts

2. 基本类型

1.类型声明

  • 类型声明是TS非常重要的一个特点;
  • 通过类型声明可以指定TS中变量(参数、形参)的类型;
  • 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错;
  • 简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值;语法:
let 变量: 类型;
   
   let 变量: 类型 = 值;
   
   function fn(参数: 类型, 参数: 类型): 类型{
       ...
   }

2. 自动类型判断

  • TS拥有自动的类型判断机制
  • 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
  • 所以如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明
  • 这一部分与Kotlin较为相似

类型

例子

描述

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中新增类型

1. number

let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: bigint = 100n;

2. boolean

let isDone: boolean = false

3. string

let color: string = "blue"
color = 'red'

let fullName: string = `Bob Bobbington`
let age: number = 37
let sentence: string = `Hello, my name is ${fullName}I'll be ${age + 1} years old next month.`

4. 字面量、联合类型

也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围

let color: 'red' | 'blue' | 'black';
let num: 1 | 2 | 3 | 4 | 5;

// 可以使用 | 连接多个类型(联合类型)
let b: "male" | "female"
b = "male"
b = "female"
// 上边的b只能是 male或者是famale固定值,下边这种方式规定类型更为灵活
let c : boolean | string
c = true
c = "str"

5. any

表示任意类型,一个变量设置类型为any后相当于对该变量关闭了Ts的类型检测,不建议使用

// 显示声明为any
let d: any = 4
d = 'hello'
d = true
// 声明变量如果不指定类型,则TS解析器会自动判断变量的类型为any(隐式声明)
let e
e = 10
e = true
// any类型可以赋值给任意变量
let s : stirng 
s = d

6. unknown

相当于是一个类型安全的any,unknown类型的变量不能直接赋值给其他变量

let notSure: unknown = 4
notSure = 'hello'

7. void

没有返回值

let unusable: void = undefined
 
 function fn() :void{
     
 }

8. never

永远不会有返回结果

// 规定函数的返回值是 never,写过kotlin的话看起来就不奇怪了
function error(message: string): never {
    throw new Error(message);
}

9. object

// object 表示一个js对象
let a : object
a = {}
a = function() {}
// {} 用来指定对象中包含哪些属性
// 语法 : {属性名: 属性值}
// 属性名后边添加 ? 表示属性值可为空
let b : {name: string,age?: number}
b = { name : 'test object'}
console.log(b)
// [propName: string]: any 表示任意类型的属性
let c : {name: string,[propName: string]: any}
c = {name: 'test',age : '18',gender: '男',sal:1000}

let d : (a1:number,a2:number) => number 
d = function (n,m){
    return n + m
}

10. array

let list: number[] = [1, 2, 3]
let list: Array<number> = [1, 2, 3]

11. tuple

元组,相当于是固定长度的数组

let x: [string, number]
x = ["hello", 10];

12. enum

enum Color {
    Red,
    Green,
    Blue,
}
let c: Color = Color.Green;

enum Color {
    Red = 1,
    Green,
    Blue,
}
let c: Color = Color.Green;

enum Color {
    Red = 1,
    Green = 2,
    Blue = 4,
}
let c: Color = Color.Green

let person: {name:string,gender: 0|1,age:number}
person = {
    name: 'eleven',
    gender : 1,
    age : 16
}

let j : {name:string} & {age :number}
j = {name:'test',age:18}

13. 类型断言

有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却并不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式:

  • 第一种
let someValue: unknown = "this is a string"
let strLength: number = (someValue as string).length
  • 第二种
let someValue: unknown = "this is a string"
let strLength: number = (<string>someValue).length

3. 编译选项

1. 自动编译文件

编译文件时,使用 -w 指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。

示例:

tsc xxx.ts -w

2. 自动编译整个项目

1. 自动编译配置

如果直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件。

但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置文件 tsconfig.json,tsconfig.json是一个JSON文件,添加配置文件后,只需只需 tsc 命令即可完成对整个项目的编译

  • webstorm默认
{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "sourceMap": true
  },
  "exclude": [
    "node_modules"
  ]
}

添加完成配置文件之后可以使用下列命令对全项目自动编译

tsc -w

2. 配置选项

选项

默认值

描述

示例

include

[“**/*”]

用来指定哪些文件用来编译

include":[“src/**/*”, “tests/**/*”]

exclude

[“node_modules”, “bower_components”, “jspm_packages”]

定义需要排除在外的目录

“exclude”: [“./src/hello/**/*”]

extends

定义被继承的配置文件

“extends”: “./configs/base”

files

指定被编译文件的列表,只有需要编译的文件少时才会用到

“files”: [ “core.ts”, “sys.ts”, “types.ts”, “scanner.ts”, “parser.ts”, “utilities.ts”, “binder.ts”, “checker.ts”, “tsc.ts” ]

compilerOptions

太多了下边讲

compilerOptions中包含的选项较多

  • target,用来指定编译之后的ES的版本
{
  "compilerOptions": {
    // target 用来指定ts编译的ES的版本
    // ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
    "target": "ES2015",
  }
}
  • module,指定要使用的模块化的规范
{
  "compilerOptions": {
    // 指定模块化规范
    // 'none','commonjs','amd','system','umd','es6','es2015','es2020','esnext'
    "module": "ES2015"
  }
}
  • lib,指定代码运行时所包含的库(宿主环境)
"compilerOptions": {
    // 可选值多得一批 ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost ......
    "lib": ["ES6", "DOM"]
}
  • outDir,编译后文件所在的目录
"compilerOptions": {
      // 指定编译后的js存放目录
      "outDir":"./dist"
  }
  • outFile,将所有的文件编译为一个js文件,
"compilerOptions": {
    //设置outFile之后,默认会将所有的编写在全局作用域中的代码合并为一个js文件,
    // 如果module制定了None、System或AMD则会将模块一起合并到文件之中
    // 也就是说如果报错了就把module换成上边的三种,建议system
    "outFile": "./dist/app.js"
}
  • rootDir,指定代码的根目录,默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过rootDir可以手动指定根目录
"compilerOptions": {
    "rootDir": "./src"
}
  • allowJs,是否编译js文件,默认为false
"compilerOptions": {
    "allowJs": false
}
  • checkJs,是否对js文件进行检查,默认是false
"compilerOptions": {
    "checkJs": false
}
  • removeComments,是否删除注释,默认是false
"compilerOptions": {
    // 不编译ts里边的注释
    "removeComments": true
}
  • noEmit,不生成编译后的文件,默认值是false
  • noEmitOnError,当发生错误是不编译文件
  • sourceMap,是否生成sourceMap,默认值:false

下列为阉割检查模式

  • strict:启用所有的严格检查,默认值为true,设置后相当于开启了所有的严格检查
  • alwaysStrict: 总是以严格模式对代码进行编译
  • noImplicitAny: 禁止隐式的any类型
  • noImplicitThis:禁止类型不明确的this
  • strictBindCallApply:严格检查bind、call和apply的参数列表
  • strictFunctionTypes:严格检查函数的类型
  • strictNullChecks:严格的空值检查
  • strictPropertyInitialization:严格检查属性是否初始化

额外检查

  • noFallthroughCasesInSwitch:检查switch语句包含正确的break
  • noImplicitReturns :检查函数没有隐式的返回值
  • noUnusedLocals: 检查未使用的局部变量
  • noUnusedParameters:检查未使用的参数

高级模式

  • allowUnreachableCode:检查不可达代码,

4. webpack整合打包

1. 初始化项目

# 创建文件夹
mkdir part3
# 进入文件夹
cd part3
# 使用npm初始化
npm init
# 加载相关依赖 ts-loader用于在webpack中编译ts文件
cnpm i -D webpack webpack-cli typescript ts-loader

2. 创建webpack配置

创建一个webpack.config.js文件

// 引入一个包
const path = require('path')
// webpack中的所有配置信息否应该卸载 module.exports中
module.exports = {
    // 指定入口文件
    entry:"./src/index.ts",
    // 指定打包文件输出的目录
    output: {
        // 相当于 ./dist
        path: path.resolve(__dirname,'dist'),
        // 打包后的文件
        filename:"bundle.js"
    },
    // 指定webpack打包是要使用的模块
    module:{
        // 指定加载的规则
        rules: [
            {
                // test 指定的是规则生效的文件 ,匹配所有以 .ts结尾的文件
                test: /\.ts$/,
                // 指定loader解析
                use: 'ts-loader',
                // 指定要派出的文件
                exclude: /node-modules/
            }
        ]
    }
}

3. 创建ts配置文件

使用webstorm的话直接用它新建的就行了

{
  "compilerOptions": {
    "module": "ES6",
    "target": "ES6",
    "sourceMap": false,
    "strict": true
  },
  "exclude": [
    "node_modules"
  ]
}

4. 运行打包

  1. src目录下创建index.ts
function sum(firstNum: number,lastNum: number) :number{
    return firstNum + lastNum
}
  1. 修改package.json,添加打包配置
{
  "name": "part3",
  "version": "1.0.0",
  "description": "使用webpack整合typescript打包",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    // 在这里添加build参数,使用webpack打包  
    "build": "webpack"
  },
  "author": "eleven",
  "license": "ISC",
  "devDependencies": {
    "ts-loader": "^9.4.1",
    "typescript": "^4.8.4",
    "webpack": "^5.74.0",
    "webpack-cli": "^4.10.0"
  }
}
  1. 运行打包
# 运行打包
npm run build
# 打包之后会出现下列提示信息
> part3@1.0.0 build E:\study\code\typescript\part3
> webpack

asset bundle.js 0 bytes [emitted] [minimized] (name: main)
./src/index.ts 15 bytes [built] [code generated]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

webpack 5.74.0 compiled with 1 warning in 1061 ms
  1. 如果出现了跟上边的提示mode错误,可以修改一下打包参数
{
    "scripts": {
    	"build": "webpack --mode production"    
    }
}
  1. 打包完成之后会在项目目录下生成dist/bundle.js

5. 优化打包

  1. 添加webpack插件,可以自动的生成html文件
cnpm i -D html-webpack-plugin
  1. 修改webpack.config.js
// 引入html插件
const HTMLWebpackPlugin = require('html-webpack-plugin')
// 在 module.exports 中添加插件
module.exports = {
    plugins:[
        new HTMLWebpackPlugin()
    ]
}
  1. 重新执行打包命令
cnpm run build
  1. 修改生成的html的titile
plugins:[
    new HTMLWebpackPlugin({
        // 这种情况只能指定生成的html的那个title
        title: '这是自顶一个的title'
    })
]
  1. 设置生成的模板,让后续生成的按照这个模板文件生成,在src下创建模板文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Lesscoding</title>
    <link rel="icon" href="https://lesscoding.net/img/icon_2.da28b7db.png">
</head>
<body>

</body>
</html>
  1. 修改webpack.config.js
plugins:[
    new HTMLWebpack({
        template:'./src/template.html'
    })
]
  1. 添加webpack开发服务器,自动打开浏览器
npm install -D webpack-dev-server
  1. 修改package.json
{
    "script":{
        // 使用chrome打开
        // 这里如果提示Cannot GET /chrome 就把chrome.exe删掉
        // 如果提示mode xxx 则改成webpack server --open --mode production
        "start":"webpack serve --open chrome.exe"
    }
}
  1. 运行
npm start
  1. 添加一个clean-webpack-plugin,打包时删除旧的文件
npm i -D clean-wepack-plugin
  1. 修改webpack-config.json
// 引入clean插件
const CLeanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
    plugins:[
        new CleanWebpackPlugin()
    ],
    // 用来设置引用的模块
    resolve: {
        // 解析的后缀
        extensions: ['.ts','.js']
    }
}

6. 使用babel相关兼容


  1. 添加相关npm依赖
# 安装@babel/core
# 安装@babel/preset-env 预设浏览器版本
# 安装 babel-loader 加载器
# 安装core-js 兼容不同浏览器js
cnpm i -D @babel/core @babel/preset-env babel-loader core-js
  1. 修改webpack.config.js,添加相关内容
module.exports = {
    output: {
        // 指定不适用 箭头函数包含,兼容ie浏览器
        environment:{
            arrowFunction: false
        }
    },
    // 指定webpack打包是要使用的模块
    module:{
        // 指定加载的规则
        rules: [
            {
                // test 指定的是规则生效的文件 ,匹配所有以 .ts结尾的文件
                test: /\.ts$/,
                // 将use改为数组 指定loader加载器,从后往前执行
                use: [
                    // 相较于直接写加载器名称,这种配置更为全面
                    {
                        //指定加载器
                        loader:'babel-loader',
                        // 配置babel
                        options:{
                            presets:[
                                [
                                    //指定环境插件
                                    "@babel/preset-env",
                                    //配置信息
                                    {
                                        // 运行到的浏览器的版本
                                        targets:{
                                            "chrome":"88",
                                            // ie 不支持let const写上这个肯定所有浏览器都可以执行
                                            "ie":"8"
                                        },
                                        // 看 package.json中引入的corejs的大版本
                                        "corejs":"3",
                                        // 使用 corejs 的方法 "usage"表示按需加载
                                        "useBuiltIns":"usage"
                                    }
                                ]
                            ]
                        }
                    },
                    'ts-loader'
                ],
                // 指定要派出的文件
                exclude: /node-modules/
            }
        ]
    }
}

5. 面向对象

如果学过java的话这个地方还是比较好理解的,我个人的理解就是将一个事物抽象出来的就是一个对象。如一辆车包含车牌,颜色,发动机,配置,准驾牌照等

1. 定义类

// 使用class关键字定义
class Person{
    // 实例属性,需要创建对象才可以方位
    name: string
    // 当然你可以用private对类进行封装
    private age: number
    // 和java一样静态变量,直接类名调用就行
    static gender :string = '男'
	// 相当于java中的final
    readonly arg1 :string = '只读属性不能改变'
    // 相当于java中的常量 static final 
    // 必须是 static readonly
    static readonly arg2 :string = '静态只读属性'
    // 全参构造方法
    constructor(name:string,age:number) {
        this.name = name
        this.age = age
    }
}

const person = new Person("test",18)

console.log(Person.gender)

2. 添加方法

这里可以对类进行一下封装,要是有个什么lombok-ts之类的就好了哈哈哈哈

class Person1{

    private age: number

    private name: string

    public getName(): string {
        return this.name
    }

    public setName(name?: string){
        this.name = name
    }

    public getAge(): number{
        return this.age
    }

    public setAge(age?: number){
        this.age = age
    }

    public static sayHello(){
        console.log('拜拜啦 ts')
    }

}

const p1 = new Person1()
p1.setAge(10)
p1.setName(null)
console.log(p1,'p1')
Person1.sayHello()

3. 继承

class Animal{
    name: string
    footNumber: number
    constructor(name: string,footNumber: number) {
        this.name = name
        this.footNumber = footNumber
    }
    say(){}
}

class Dog extends Animal{
    say() {
        console.log(`我的名字是${this.name},有${this.footNumber}只脚`)
    }
}

class Cat extends Animal{
    say() {
        console.log(`我的名字是${this.name},有${this.footNumber}只脚`)
    }
}

let wangcai: Animal = new Dog('旺财', 4)
let zhaocai: Cat = new Cat('招财',4)
wangcai.say()
zhaocai.say()

4. 抽象类

使用abstract 定义类,

  • 抽象类不能创建示例
  • 抽象类可以添加抽象方法
abstract class AnimalTest {
    name:string
    footer:number
    // 定义抽象方法
    abstract say()

    public eat(){
        console.log('吃饭啦')
    }
    
    constructor(name: string,footer:number) {
        this.name = name
        this.footer = footer
    }
}

class Chicken extends AnimalTest{
    say() {
        console.log('咯咯哒')
    }

}

let chicken = new Chicken('铁公鸡',2)
console.log(chicken.say())
console.log(chicken.eat())

5. 接口

也是使用interface完成,与type相似,但是type不允许重复定义

接口可以在定义类的时候限制类的结构

(function () {
    // 描述一个对象的类型
    type myType = {
        name: string,
        age: number
    }
    
    const obj: myType = {
        name:'test',
        age:500
    }
    // 接口允许重复定义,会将所有的属性拼接
    interface myInterface{
        name: string,
        age: number,
    }
   interface myInterface{
        gender: string
        sayHello()
    }

    const myInter: myInterface ={
        name:'sss',
        age:18,
        gender:'男',
        sayHello() {
            console.log('haha')
        }
    }
	// 接口实现类
    class MyInterfaceImpl implements myInterface{
        age: number;
        gender: string;
        name: string;
		
        sayHello() {
        }

    }
})

6. 封装

私有化属性,公共方法

  • 类比java

这种方式需要写get set比较费劲

class Person1{

    private age: number

    private name: string

    public getName(): string {
        return this.name
    }

    public setName(name?: string){
        this.name = name
    }

    public getAge(): number{
        return this.age
    }

    public setAge(age?: number){
        this.age = age
    }

    public static sayHello(){
        console.log('拜拜啦 ts')
    }

}

const p1 = new Person1()
p1.setAge(10)
p1.setName(null)
console.log(p1,'p1')
Person1.sayHello()
  • 优化getter setter
class Person{
    name: string
    
    get name(): string{
        return this.name
    }
    
    set name(name: string){
        this.name = name
    }
}

console.log

7. 泛型

function fn(a: any): any {
    return a
}

function fnT<T> (a: T): T{
    return a
}

// 不指定类型 js自动推断
let result = fnT(10)
// 指定泛型
let result2 = fnT<string>('-10')
//反省可以同时指定多个
function fn2<T,K>(a: T,b:K):T{
    return  a
}

fn2<number,string>(2,'2')

interface Interface {
    length: number
}
// 指定泛型的父类,只要是父类或者是其子类就行
function fn3<T extends Interface>(a: T):number {
    return a.length
}

class MyClass<T> {
    age: T
    constructor(age: T) {
        this.age = age
    }
}

6. 项目demo

创建一个新的文件夹,将上边的package.jsontsconfig.json,webpack.config.js复制过来

1. 添加less支持

  • 添加npm依赖
# 添加相关依赖
npm i -D less less-loader css-loader style-loader
  • 修改webpack配置
module:{
    // 指定加载的规则
    rules: [
        // 设置支持 less文件处理
        {
            test: /\.less$/,
            use:[
                'style-loader',
                'css-loader',
                'less-loader'
            ]
        }
    ]
}

2. 添加css老版本支持

  • 添加npm依赖
# 添加相关依赖
npm i -D postcss postcss-loader postcss-preset-env
  • 修改webpack配置
module:{
    // 指定加载的规则
    rules: [
        // 设置支持 less文件处理
        {
            test: /\.less$/,
            use:[
                'style-loader',
                'css-loader',
                // postcss
                {
                    loader: 'postcss-loader',
                    options: {
                        postcssOptions:{
                            plugins: [
                                [
                                    "postcss-preset-env",
                                    {
                                        // 兼容每个浏览器的最新的两个版本
                                        browsers:'last 2 version'
                                    }
                                ]
                            ]
                        }

                    }
                },
                'less-loader'
            ]
        }
    ]
}
'less-loader'
        ]
    }
]

}

## 2. 添加css老版本支持

- 添加npm依赖

```shell
# 添加相关依赖
npm i -D postcss postcss-loader postcss-preset-env
  • 修改webpack配置
module:{
    // 指定加载的规则
    rules: [
        // 设置支持 less文件处理
        {
            test: /\.less$/,
            use:[
                'style-loader',
                'css-loader',
                // postcss
                {
                    loader: 'postcss-loader',
                    options: {
                        postcssOptions:{
                            plugins: [
                                [
                                    "postcss-preset-env",
                                    {
                                        // 兼容每个浏览器的最新的两个版本
                                        browsers:'last 2 version'
                                    }
                                ]
                            ]
                        }

                    }
                },
                'less-loader'
            ]
        }
    ]
}