【简洁易学】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
希望大家学的开心
欢迎指正
在这里插入图片描述

相关推荐

  1. typescript学习笔记

    2024-05-03 22:00:04       45 阅读
  2. TypeScript 学习笔记

    2024-05-03 22:00:04       40 阅读
  3. TypeScript 学习笔记

    2024-05-03 22:00:04       36 阅读
  4. TypeScript 学习笔记

    2024-05-03 22:00:04       29 阅读
  5. Typescript学习笔记

    2024-05-03 22:00:04       41 阅读
  6. TypeScript 学习笔记

    2024-05-03 22:00:04       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-03 22:00:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-03 22:00:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-05-03 22:00:04       82 阅读
  4. Python语言-面向对象

    2024-05-03 22:00:04       91 阅读

热门阅读

  1. 模拟退火算法matlab代码

    2024-05-03 22:00:04       29 阅读
  2. 【软测学习笔记】MySQL入门Day02

    2024-05-03 22:00:04       38 阅读
  3. 算法===二分查找

    2024-05-03 22:00:04       36 阅读
  4. 【Qt】Qt输出多页pdf

    2024-05-03 22:00:04       36 阅读
  5. 函数与作用域

    2024-05-03 22:00:04       38 阅读
  6. AtCoder Beginner Contest 351 D题 Grid and Magnet

    2024-05-03 22:00:04       37 阅读