【简洁易学】TypeScript 学习笔记

TypeScript学习笔记

一、TS简介

1. 学习前提

学习前端必备语言javascript,它易学易用,开发过程中挖坑也容易(/狗头),维护起来比较难受,不太适合开发大型项目。

JS变量是一个动态类型,比如说let a = 123,后面也可以给a赋值为字符串、布尔值等等。

JS函数的参数没有类型限制,很自由也不报错,容易挖坑。

JS很好,但是也存在一些缺点让人头痛。

我们希望有一个新的语言,来弥补一些缺点,而不是替代JS。微软设计的TypeScript就很不错。

2. TypeScript是什么?

TS是以 JS 为基础构建的语言,是 JS 的一个超集

TS 扩展了 JS 并添加了类型,可以在支持JS的平台上执行。可能你在书写 TS 的时候觉得它事儿多,但是习惯之后会觉察出它的优势的,坚持下去。

TS 目前不能被 JS 解析器直接执行,我们要将 TS 编译成 JS 执行。

3. TypeScript增加了什么?

大体列举一下,后续会进行学习,不着急不着急

  • 类型
  • 支持ES的新特性
  • 添加ES不具备的新特性
  • 丰富的配置选项
  • 强大的开发工具

二、TS开发环境搭建

1. 下载、安装Node.js

系统最好是64位的因为这样内存会大一些。

node.js官网下载即可,用LTS这种长期维护版本,安装路径尽量不要有特殊符号和中文。

查看node版本命令:node -v

2. npm安装TypeScript

查看npm版本命令:npm -v

npm安装TS : npm i -g typescript,会有点慢,呆胶布,我会等。
在这里插入图片描述

检查:输入tsc,出现一堆乱七八糟,说明OK了

在这里插入图片描述

3. 创建一个TS文件,使用tsc对TS文件进行编译

推荐的是VSCode编辑器书写代码

在这里插入图片描述

我们都知道编辑器它不认ts文件呢,现在我们用**tsc编译器**编译一下,目录下会生成一个js文件
在这里插入图片描述

网页中引入js文件就可以执行了

三、TS的类型

1. 类型声明

TS 和 JS 的一个区别就是 TS 的变量有类型的概念

在 js 里我们可以给变量 a 任意赋值,可能给后期维护挖了大坑

let a;
a = 'hello';
a = 2;

那我们在TS中怎么做呢?

//声明一个变量,同时指定它的类型为number数字,
let a:number
a = 1 ; //不报错
a = ''  //报错

此时 a 只能赋值数字,要是赋值其他的类型将会报错
在这里插入图片描述

声明完变量直接赋值:

let c:boolean = true  //如果声明和赋值同时进行,那TS可以自动对变量进行类型检测
let c = false         //可以这样简写

函数参数类型:

function sum(a:number,b:number){
    return a + b
}
sum(a:123,b:'123')  //此时 b 会报错,相比于 js 能让人更好的发现问题从而进行修改,参数要是传多了也会报错。

返回值类型:

function sum(a:number,b:number):number{
    return a + b
}
let result = sum(a:123,b:'123')  

== ts 可以编译成任意版本的 js ,可以对编译器进行配置,来决定编译成哪种版本,后面会学习到==

要是想演示一下看效果,可以创建一个index.html文件,将js文件引入到html文件里面,运行html文件即可。

ts 代码改完了记得进行编译:tsc 文件名

小结:

let 变量 : 类型
let 变量 : 类型 = 值;
function fn(参数 : 类型 , 参数 : 类型) : 类型{ … }

2. 类型大全

类型描述
number任意数字
string任意字符串
boolean布尔值
字面量限制变量的值就是该字面量的值
any任意类型
unknown类型安全的any
void没有值或undefined
never不能是任何值
object任意的 JS 对象
array任意 JS 数组
tuple元素,TS 新增类型,固定长度的数组
enum枚举,TS 中新增类型
2.1 字面量

可以使用字面量进行类型声明

let a:number = 10;  //原写法
let a:10;    //使用字面量进行类型声明,说明a是number类型,但是这时a的值就固定了
a = 11;   //报错

一般这样用:

联合类型常用

// |表示或,用来连接多个类型(联合类型)
let b:string | boolean
b = true  //不报错
b = 'hello'  //不报错


let a: 10 | 11   
a = 10  //不报错
a = 11 //不报错
a = 12  //报错
2.2 any / unknown

表示任意类型,设置any类型后对该变量关闭类型检测,不建议使用any

声明变量不指定类型,则TS解析器自动判断变量的类型为any(隐式any

let c:any;
//均不报错
c = false
c = 'hello'
c = 123

如果实在不知道变量d的类型,那我们可以使用unknown

unknown实际上是一个类型安全的any。

//unknown 表示未知类型
//均不报错
let d : unknown;
d = 123
d = 'hello'
d = true

=c 的类型是any,可以赋值给任意变量;unknow类型的变量d赋值给其他类型的变量会报错=

s = 'ruru'
s = c;  //不报错
s = d;  //报错,这种情况可以处理

处理办法

  1. 判断
if (typeof d === 'string') {
    s = d;
}
  1. 类型断言
/*
*语法:
*   变量 as 类型
*   <类型>变量
**/
s = d as string;
s = <string>d;
2.3 void / never

设置函数返回值用的多

void表示为空

没有返回值,类型设置为void,没写类型默认是void

function fn():void{
}

never表示永远不会返回结果

function fn2():never{
    throw new Error('报错了')
}
2.4 object

在js中一切皆对象

//object表示一个对象,这种写法不常用
let a: object;
a = {};
a = function () { };

语法:{属性名:属性值 , 属性名:属性值}

{}指定对象中可以包含哪些属性

//这种常用
//?表示可选属性
let b: { name: string, age?: number };
b = { name: '孙' }
b = { name: '孙', age: 18 }

优化一下:

//?表示可选属性
//[propName: string]: any 表示任意类型的属性
let b: { name: string, [propName: string]: any };
b = { name: '孙' }
b = { name: '孙', age: 18, a: 1, b: 2 }

函数

设置函数结构的类型声明

语法:(形参:类型,形参:类型) => 返回值

//没啥意义,我们是希望来限制它的结构
let f:Function

这样写:希望函数f的参数类型都是number,返回值也是number

let f:(a:number,b:number) => number
f = function(n1,n2){
    return n1 + n2
}

语法学习无捷径,多写多做是良训。

2.5 array

开发中数组中存储一种类型的值。

语法:类型[ ] or Array<类型>

let e: string[];
let x: Array<string>;
let z: number[];
e = ['a','b',1]  //报错,因为里面有数字和字符串两种类型
x = ['1','2','3']
z = [1,2,3]
2.6 tuple

元组类型,TS新增,固定长度的数组

语法:[类型,类型,…]

let v: [string, string];
v = ['h', 'h']
v = ['a','a','a']   //报错
2.7 enum

枚举,TS新增,把可能情况都列出来

enum Gender {
    //定义一个枚举的类
    Male,
    Female
}

let i: { name: string, age: number, gender: number }
i = {
    name: '孙悟空',
    age: 500,
    gender: 1
}
console.log(i.gender = Gender.Male)
2.8 其它
  • &与
let t = {name:String}& {age:number}  //这代表对象t要同时有这两种属性
  • 类型的别名

1 | 2 | 3 | 4起个别名,很方便,简化类型的使用。

type myType = 1 | 2 | 3 | 4
let a: myType;
let b: myType;
let c : myType;

四、编译选项

1. 监视

TS写完之后需要编译才能执行。

新建一个TS文件,我们编写一段代码,运行 tsc 文件名 进行编译。

每当修改ts文件时都要一遍遍重新编译,忒麻烦,我们使用监视器监视我们这段代码,每当代码发生变化时就重新编译代码,不需要手动操作了。

有个时间间隔,需要等待一下

tsc 文件名 -w  

在这里插入图片描述

只针对于单一文件,需要每个文件都配置。不太适合日常开发。ctrl c退出监视。

2. tsconfig.json

在目录下创建一个tsconfig.json文件,对tsc进行配置.
在这里插入图片描述

这时命令行输入 tsc就可以编译文件里所有的TS文件了。

tsc -w 监视的是所有的TS文件

tsconfig.json是ts编译器的配置文件,ts编译器可以根据它的信息来对代码进行编译。

3. 配置选项

3.1 include / exclude

这两个直接写在大括号里

include:用来指定哪些ts文件需要被编译

    "include": [
        // 表示src目录下的任意文件夹下的任意文件都能被执行
        "./src/**/*"
    ]

exclude:指定不需要编译的,默认值"node_modules","bower_components","jspm_packages"

 "exclude": [
        //表示src目录下的app.ts不需要被编译
        "./src/app2.ts"
 ]
3.2 extends files

这两个直接写在大括号里

extends:定义被继承的配置文件

//当前配置文件会自动包含config目录下base.json中的所有配置信息

"extends":"./config/base"

files:指定被编译文件的列表,文件少可能才会用到

"files":[
	"app.ts",
	"app2.ts",
	...
]
3.3 CompilerOptions【重要】

编译器选项,稍微麻烦一些,且看下面详解

3.3.1 target

指定TS被编译为的ES版本,默认ES3版本

可选:'ES3' , 'ES5' , 'ES2016' , 'ES2017' , 'ES2018' , 'ES2019' , 'ES2020'

例如转成ES6版本,esnext代表的是ES最新版本

"CompilerOptions": {
        "target": "es6"
    }
3.3.2 module

指定使用的模块化的规范

可选:none,commonjs,and,system,umd,es6

"CompilerOptions": {
        "target": "ES6",
        "module": "commonjs"
    }
3.3.3 lib

指定项目中用到的库,一般情况不需要改。

只要是在浏览器中运行一般不需要管,在node.js中执行根据实际情况修改。

 "CompilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        //"lib": [
         //   "dom"
       // ]
    }
3.3.4 outDir outFile

outDir:指定编译后文件所在目录

outFile:代码合并为一个文件, 全局作用域中的代码会合并到同一个文件中,用的不多,了解一下。

"CompilerOptions": {
        "target": "ES6",
        "module": "commonjs",
       // "lib": [
        //    "dom"
        //],
        "outDir": "./dist",
        "outFile": "./dist/app.js"
    }
3.3.5 allowJs checkJs

checkJs:是否对js文件进行编译,默认是false

checkJs:检查js代码是否符合js代码规范,默认值false

"allowJs": true,
"checkJs": true
3.3.5 removeComments noEmit noEmitError

removeComments: 是否移除注释

"removeComments":true

noEmit: 不生成编译后的文件

"noEmit":true

noEmitError有错误时不生成编译后的文件

"noEmitError": true
3.3.6 alawaysStrict noImplicitAny noImplicitThis

alawaysStrict : 指定编译后的文件是否使用严格模式

"alwaysStrict":true

noImplicitAny: 不允许隐式的any类型

"noImplicitAny": true

noImplicitThis: 不允许不明确类型的this

"noImplicitThis":false
3.3.7 strictNullChecks strict

strictNullChecks :严格检查空值

"strictNullChecks":true

box1不存在也没有报错,当设置了strictNullChecks时,会报错“box1可能为空”

let box1 = document.getElementById('box1');
box1.addEventListener('click', function () {
    alert('hello');
})

解决办法:可以使用if判断是否为空。

strict:总开关,开发建议设为true

综上

以上是比较常用的,其他的用到现查。

五、webpack打包ts代码

1.初始化项目:

生成一个package.json

npm init -y

2. 下载构建工具

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

3.创建webpack.config.js并编写

//引入一个包
const path = require('path');

//webpack配置信息都写在module.exports里面
module.exports = {
    //指定入口文件,在文件中新添加一个index.ts
    entry: './src/index.ts',

    //指定打包文件
    output: {
        path: path.resolve(__dirname, "dist"),
        //打包好文件的文件
        filename: 'bundle.js'
    },

    //指定webpack打包时要使用的模块
    module: {
        //指定要加载的规则
        rules: [
            {
                //test:规则生效的文件
                //用ts-loader处理ts结尾的文件
                test: /\.ts$/,
                use: 'ts-loader',  //要使用的loader
                exclude: /node-modules/  //要排除的文件
            }
        ]
    }
}

4. tsconfig.json文件配置

{
    "CompilerOptions": {
        "module": "ES2015",
        "target": "ES2015",
        "strict": true
    }
}

打包,在package.json中添加一行命令"build":"webpack
在这里插入图片描述

执行webpack,对文件进行打包

npm run build

出现一个dist文件夹,就成功了!

5. 补充

自动生成html文件,自动引入js文件

安装插件:

npm i -D html-webpack-plugin  //帮助我们自动生成html文件

webpack.config.js里引入并编写代码

const HTMLWebpackPlugin = require('html-webpack-plugin')

//配置webpack插件,
    plugins: [
        new HTMLWebpackPlugin({
//          title:'ruru'  //自定义title
            template:"文件地址"  //写好一个文件,作为生成html文件的模板
        });
    ]

在浏览器中访问网页,自动刷新

安装插件

npm i -D webpack-dev-server

package.json配置:"start": "webpack serve --open chrome.exe"

 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "start": "webpack serve --open chrome.exe"   //新添的
  },

启动项目成功会自动打开浏览器。可以实时更新

编译前dist目录清空

安装插件

npm i -D clean-webpack-plugin

和那个html用法一样

const {CleanWebpackPlugin} = require('clean-webpack-plugin')

//配置webpack插件,
    plugins: [
        new CleanWebpackPlugin(),
        new HTMLWebpackPlugin({
//          title:'ruru'  //自定义title
            template:"文件地址"  //写好一个文件,作为生成html文件的模板
        });
    ]

告诉webpack哪些模块可以被引入

webpack.config.js中设置

//用来设置引用模块
    resolve: {
        extensions: ['.ts', '.js']
    }
}

让代码有更好的兼容性

安装babel插件

npm i -D @babel/core @babel/preset-env @babel-loader core-js

package.json中查看是否成功安装成功。

修改webpack.config.js文件

 //指定webpack打包时要使用的模块
    module: {
        //指定要加载的规则
        rules: [
            {
                //test:规则生效的文件
                //用ts-loader处理ts结尾的文件
                test: /\.ts$/,
                use: [
                    {
                        loader: 'babel-loader',  //指定加载器
                        //配置babel
                        options: {
                            //设置预定义的环境
                            presets: [
                                //指定环境插件
                                "@babel/preset-env",
                                //配置信息
                                {
                                    //要兼容的目标浏览器
                                    targets: {
                                        "chrome": "88"
                                    },
                                    //指定corejs的版本
                                    "corejs": "3",
                                    //使用corejs方式使用usage表示按需加载
                                    "useBuiltIns": "usage"
                                }

                            ]
                        }
                    },
                    'ts-loader'
                ],  //要使用的loader
                exclude: /node-modules/  //要排除的文件
            }
        ]
    },

六、面向对象

程序之中所有操作都要通过对象来完成。

操作浏览器要使用window对象,操作网页使用document对象,操作控制台使用console对象。

对象包含属性方法

1. 类class

类是对象的模型,我们通过类创建对象。比如说Car类可以创建汽车的对象。

定义类:

// 使用class关键字定义类
class Person {
    name: string = 'ruru' //实例属性
    age: number = 18
    static sex:string = "女"
    readonly anim:string = "shushu"  //只读
    sayHello(){   //定义方法
        console.log('hello!!')
    }

}
//使用类创建一个对象
const p1 = new Person();

直接定义的属性是实例属性,通过实例访问。

在类中属性前使用static关键字可以定义类属性(静态属性),可以通过类访问

readonly开头的属性只读,不可更改。

方法和类在上述三点是相通的

2. 构造函数和this

class Dog {
    name: string
    age:number
    // 构造函数在对象创建时调用
    //再实例方法中,this表示的是当前的实例
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
        console.log(this)
    }
}

const d1 = new Dog('wang', 1);
const d2 = new Dog('bai', 2)

这样就可以传入不同参数获得不同的对象

通过this表示当前调用方法的对象。

3. 继承

Dog类

class Dog {
    name: string
    age:number
    
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    sayHello(){
        console.log('汪汪汪!')
    }
}

const d1 = new Dog('xiaohei', 2)
d1.sayHello()

Cat类

class Cat {
    name: string
    age: number

    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    sayHello() {
        console.log('喵喵喵~')
    }

}

const c1 = new Cat('xiaobai', 1)
c1.sayHello()

这两个类的结构很相似,代码很冗余。

代码提取出来,然后共享

定义一个Animal

class Animal {
    name: string
    age: number

    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    sayHello() {
        console.log('喵喵喵~')
    }
}

class Dog extends Animal {  //继承
	run(){
        console.log('旺财在跑')
	}
}

class Cat extends Animal {  //继承
	sayHello(){
        console.log('喵喵喵')   //覆盖掉父类的方法,这种叫做方法的重写
    }
}

使用继承后,子类将拥有父类所有的方法和属性。

通过继承可以将多个类中共有的代码写在一个父类中,避免代码的重复。

可以直接在子类中添加你想要添加属性和方法,可以正常使用,参考Dog里的run方法。

继承中的super,表示当前类的父类

class Dog extends Animal {
    sayHello() {
        super.sayHello();
    }
}

注意:如果在子类写了构造函数,此时在子类的构造函数中必须对父类的构造函数进行构造。

4. 抽象类

禁止一个类来创建对象

abstract开头的类是抽象类,不能创建对象只能作为父类用来继承,没有其它作用。

抽象类中可以添加抽象方法,使用abstract开头,只能定义在抽象类中,子类必须对抽象方法进行重写

abstract class Animal{
    name:string
    constructor(name:string){
        this.name = name
    }
    abstract sayHello(){  //在子类中必须被重写哦
        //console.log('动物在叫!')
	}
}

5. 接口

接口用于定义一个类结构,interface开头

接口用来定义一个类中应该包含哪些属性和方法

接口也可以当成类型声明去使用

接口可以在定义类的时候去限制类的结构,接口中的属性都不能有实际值,只定义对象的结构不考虑实际值,接口中的方法都是抽象方法。

定义类时,可以使类去实现一个接口,实现接口就是使类满足接口的要求。

interface myInterface {
    name: string
    age: number
}
const obj: myInterface = {
    name: 'ruru',
    age: 18
}

6. 属性的封装

现在属性是在对象中设置的,属性可以任意的被修改。

class Per {
    name: string
    age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
}
const p2 = new Per('ruru', 20);

数据可随意修改,非常不安全,很危险。

TS 可以在属性前添加属性的修饰符:publicprivate

class Per {
    _name: string   //改成私有属性,外部不能访问
    _age: number
    constructor(name: string, age: number) {
        this._name = name
        this._age = age
    }
}

记得在tsconfig.json文件中配置"noEmitOnError":true

通过在类中添加方法,让外部能间接的获取设置这些属性值。

getName(){
	return this._name
}
p2.getName()
setName(value:string){
	this._name = value
}

p2.setName('猪')

现在选择主动权在我,我可以控制数据是否能被访问,从而有效保证数据的安全。

getter方法用来读取属性

setter方法用来设置属性

​ - 它们被称为属性的存取器

使用存取器设置name属性:

get name(){	
	return this._name
}

set name(value){
	this.name = value
}
p2.name = "猪"  //直接修改即可

私有属性private无法在子类中访问

保护属性protect只能在当前类和子类中访问

7. 泛型

定义函数或者类时类型不明确,执行时才能确定类型

泛型可同时指定多个

function fn<T>(a:T):T{
	return a;	
}
//指定两个泛型
function fn2<T,K>(a:T,b:K):T{
    return a+b;
}

使用:

//直接调用
fn(10);

//指定泛型
fn<string>("hello")

T extends Inter表示泛型T必须是Inter实现类(子类)

interface Inter{
    length:number
}
function f3<T extends Inter>(a:T):number{
    return a.length;
}

对象:

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

const mc = new MyClass<String>('孙悟空')

总结

love and peace
希望大家学的开心
欢迎指正
在这里插入图片描述

  • 46
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值