1. 为什么要学习TypeScript?
javaScript的书写自由度非常高,最为突出的就是JavaScript没有类型的概念。该笔记是在学习尚硅谷李立超老师的学习视频结合官方文档所做。
例如以下代码:
//JS声明的变量是动态类型
let a = 0 //数值类型
a='你好'// a又变成字符串类型
a=true// a又变成布尔类型
这样看起来书写方便,但是在项目开发时不易于维护,因为变量类型容易被修改。
当多个地方需要使用该变量时,不小心修改了类型。即使发生了报错也不会在修改
的地方报错,而是在调用时报错,这样排查狠消耗时间。
针对这一问题推出了TypeScript,TypeScript扩展了JavaScript,并添加了类型可以说TS时JS的超集,它是以JS为基础构建的语言,可以在任何支持JS的平台中执行。但是TS不能被JS的解析器(也就是浏览器)直接执行。
2. TypeScript安装
注意 前提是电脑已经安装了node.js
1.输入命令行安装
npm i -g typescript //全局安装
2.创建.ts文件
demo.ts文件
let 变量 :类型 = 值;
let a : Number=30;
3.执行命令行 tsc xxx.ts 将ts文件编译为js文件
3.TypeScript的类型声明
类型声明是TS的最重要的特点之一。当变量指定类型后,如果该变量赋值时,值不是其指定的类型就会报错。
变量:
let a : Number;
a = 10;
//也可以写成:
let a : Number = 10 //常见
//如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测
//所以上面可以简写为
let a = 10(不推荐)
函数:
//在JS中函数是不考虑参数的类型和个数的
//而TS可以规定参数的个数 类型 和返回值的类型
function sum ( a : Number. b : Number) :Number{//(这个是规定返回值类型)
return a + b
}
TypeScript类型
类型 | 描述 |
---|---|
String | 字符串类型 |
Nubmer | 数字类型 |
Boolean | 布尔值类型 |
Object | 对象类型 |
Array | 数组类型 |
any | 任意类型(不推荐) |
unknown | 类型安全的any类型 |
void | 空值(undefined) |
never | 不能是任何值 |
tuple | 元组,TS新增类型,固定长度数组 |
enum | 枚举,TS新增类型 |
1.简单类型
//1.字符串
let name : String
name = "下面的格式我也能写"
//2.数值
let age : Number = 18;
//3.Boolean类型
let isUser :Boolean = false;
2.any 任意类型
any任意类型 不推荐使用。
3.unknown类型
//unknown 是类型安全的any类型
let user:unknown ;
let name:unknown ;
user= "憨八龟";
// 注意:unknown类型的变量不能直接赋值给其他变量
例如: let name = user 则直接报错
此时我们可以使用类型断言
//类型断言,可以用来告诉解析器的变量的实际类型
name = user as String
//或者
name = <string> user
4.void类型
void类型一般表示一个空值。
常用场景:当方法没有返回值的时候
function sum (num1:Number,num2:Number):void{
console.log(num1)
}
5.never类型
never类型表示永远不会返回结果。
使用场景:抛出异常
function fn():never{
throw new Error ("报错了")//JS报错后无法继续向下执行
}
6.object类型
//常常用来指定对象中包含了哪些属性
//语法:{属性名:类型}
//在属性名后面加上? 表示该属性是可选的
let a :{ name : string , age? : Number}
//注意 name属性如果没有赋值就报错
a={name:'憨八龟'} 或a={name:"憨八龟",age:19}
//[xxx:string]:any 表示字符串形式的属性名:任何类型的属性值
let c :{name : string ,[rname : string ] : any}
c= { name : " 憨八龟" ,age : 18 ,gender:"公" ,hello:"你好"}
设置函数结构的类型声明
语法: (形参:类型,形参:类型...) =>返回值类型
let d (a:number,b:number) =>number
d = function (n1:number,n2 ; number): number{
retrun n1 + n2
}
6.Array类型
//Array的声明方式:
//类型[]或 Array <类型>18350089047 13400505548
let arr : Number [] //数值数组
let arr: Array <Number>
7.tuple类型
元组,元组就是固定长度的数组。(TS新增)
let strArr :[string,string]
strArr=['hello','word'] //多一个少一个 类型不同都会报错
8.enum枚举
在实际应用中,有的变量只有几种可能取值。如人的性别只有两种可能取值,星期只有七种可能取值。在TS中对这样取值比较特殊的变量可以定义为枚举类型。所谓枚举是指将变量的值一一列举出来,变量只限于列举出来的值的范围内取值。
定义一个变量是枚举类型,可以先定义一个枚举类型名,然后再说明这个变量是该枚举类型。
enum arr{
save, //如果不写默认从0开始递增
type,//1
num=9,//如果赋值则从赋值开始开始递增
num2,//10
}
console.log(arr.save);//0
console.log(arr.type);//1
console.log(num.type);//9
console.log(num2.type);//10
4. TS的编译
4.1编译监听
前面说到 TS目前不能在浏览器上直接运行,需要转化为响应的js文件。则通过 tsc xxx.ts 命令进行编译,但是我们不可能每改一次代码执行一次这个命令,所以需要对文件进行监听。
//命令行代码:
tsc xxx.ts -w // w watch的缩写
但是前面这种写法只能监听一个TS文件,监听多个文件只能开启多个终端,这不符合我们的日常开发需求。所以我们真正开发时采用以下的方法。
- 首先在根目录创建tsconfig.json配置文件,手动创建或通过 tsc - - init自动创建
- 运行tsc 编译所有在目录下的ts文件
- 运行tsc -m 监听所在目录下的所有ts文件。
4.2tsconfig.json 文件配置
1.include
用来定义需要排除在外的元素。
tsconfig.json
{
//用来指定哪些ts文件要被编译
"include":[
'./scr/**/*', //**表示任意目录, *表示任意文件
]
}
2.exclude
用来指定哪些文件不需要被编译。 如果没有特殊指定, "exclude"
默认情况下会排除node_modules
,bower_components
,jspm_packages
和<outDir>
目录。
tsconfig.json
{
"exclude":[
"./src/banner/**/*"
]
}
3.extends
继承。这个有点类似js 的引入。extends
是tsconfig.json
文件里的顶级属性(与compilerOptions
,files
,include
,和exclude
一样)。 extends
的值是一个字符串,包含指向另一个要继承文件的路径。
tsconfig.json
{
"extends":’./config/base‘ //继承config/base.json文件
}
4.files
指定一个包含相对或绝对文件路径的列表。
官网案例
{
"files": [
"core.ts",
"sys.ts",
"types.ts",
"scanner.ts",
"parser.ts",
"utilities.ts",
"binder.ts",
"checker.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",
"tsc.ts",
"diagnosticInformationMap.generated.ts"
]
}
5.compilerOptions (重点)
编译选项是配置文件重非常重要也比较复杂的配置选项。
在compilerOptions中包含多个子选项,用来完成对编译的配置。
东西太多 无法一 一列举 详情需访问官网 或者初始化配置 tsc --init 来查看
'compilerOptions':{
"target" :"ES5", //用来设置编译的ECMAscript版本+
"module":"es6", //指定要使用的模块化规范
"lib":[ ], //lib用来指定项目中要使用的库
"outDir":"./dist:", //用来指定编译后文件所在的目录
"outFile":"./dist/app.js" //将编译的代码合并到一个文件上
"allowJs":true, //是否对JS文件进行编译
"removeComments":true //是否移除注释
"noEmit":false //不生成编译后的文件
"noEmitOnError":true //当有错误时不编译文件
"strict":true //所有严格检查的总开关 这个开启 底下的四个默认为true 推荐为true
"alwaysStrict":false //设置是否为编译后的文件开启严格模式
"noImpLicitAny":true, //不允许隐式的any类型(就是必须声明)
"noImplicitThis":true, //不允许不明确类型的this 方法中的this需指定在参数中 this:any
"strictNullChecks":true //严格检查空值 如果有可能存在null则报错
}
4.3 webpack打包TS
环境需提前安装node。
1.在项目目录下 通过命令行生成package.json
npm init -y //生成package.json文件
//安装webpack和TS依赖 (已经安装的跳过)
npm install -D webpack webpack-cli typescript ts-loader
2.在package.json文件的scripts字段中添加运行webpack
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
3.在项目目录下创建webpack.config.js配置文件
//引入node 路径包
const path = require('path')
//导出所有webpack配置
module.exports = {
//指定路口文件
entry: "./src/index.ts",
//指定打包文件所在目录
output: {
//指定打包文件的目录
path: path.resolve(__dirname, 'dist'),
//打包的文件名
filename: "bundle.js",
},
//指定webpack打包时使用的模块
module: {
//指定要加载的规则
rules: [
{ //指定规则生效的文件
test: /\.ts$/,
//使用ts-loader打包ts文件
use: "ts-loader",
//设置不需要打包的文件
exclude: /node_modules/
}
]
}
}
4.项目根目录创建tsconfig.json配置文件
{
//这是我自己的配置
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true
}
}
**5. 打包编译只需运行 npm run bulid **
6.html-webpack-plugin插件
打包完成我们需要在html页面显示时,需要安装这个插件,可以动态生成html页面。(以前是手动创建html文件,用script标签手动引入)
npm i -D html-webpack-plugin
之后需在webpack.config.js中配置
const htmlWebpackPlugin = require('html-webpack-plugin')
//导出所有webpack配置
module.exports = {
//配置webpack插件
plugins: [
new htmlWebpackPlugin()
]
}
7.webpack配置模块格式
有的时候我们不同模块之间需要互相引入某些值,例如模块A需要引入模块B的值,但是如果两者都是TS文件,则无法执行(webpack默认不支持TS模块引入),但是可以通过相关的配置,设置允许TS文件格式进行模块导入。
需要在webpack.config.js文件中添加字段:
module.exports = {
//用来设置引用模块格式
resolve: {
extensions: ['.ts', '.js'] //表示允许.ts 和.js文件进行模块化操作(例如模块的引入 导出)
}
}
8.安装webpack的babel插件
npm i -D @babel/core @babel/preset-env babel-loader core.js
安装完之后需要在webpack.config.js中进行babel的配置:
module.exports = {
//告诉webpack不使用箭头函数
//因为webpack打包时会将代码块打包到一个自调用函数中,该函数内部使用箭头函数
//而IE不支持
evironment:{
arrowFunction:false
},
//指定webpack打包时使用的模块
module: {
//指定要加载的规则
rules: [
{ //指定规则生效的文件
test: /\.ts$/,
//使用ts-loader打包ts文件
use: [
//配置babel
{
//指定加载器
loader: "label-loader",
//设置babel
options: {
//设置预定义的环境
presets: [
[
//指定环境的插件
"@babel/preset-env",
{
//要兼容浏览器版本
targets: {
"ie": "11"
},
//指定corejs版本
"corejs": "4",
// 使用corejs的方式
"useBuiltIns": "usage" //按需加载
}
]
]
}
},
"ts-loader",
],
//设置不需要打包的文件
exclude: /node_modules/
}
]
},
}
5.接口
接口与class(类)有些类似,接口也是用来定义一个类结构。建议先学class类
//在接口之前我们定义一个对象的类型
type myType={
name:string, //和接口的区别 接口可以重复声明 这里不可以
age:number
}
//现在用接口给定义一个类结构,定义一个类中应该包含哪些属性和方法
//同时 接口也可以当作类型声明去使用
//接口是interface 名称{}
interface myType{
name:string,
age:number
}
const obj:myType={
name:"sss",
age:"111"
}
1.注意接口中的所有属性都不能有实际的值,接口只能定义对象的结构。
interface myType{
name:string,
age:number
sayHello:void //在接口中的所有方法都是抽象方法
}
2.定义类时,可以使类去实现一个接口,实现接口就是使类满足接口的需求
interface myType{
name:string,
age:number
sayHello:void //在接口中的所有方法都是抽象方法
}
//实现接口 通过implements
class MyClass implements myType{
name:string;
constructor(name:string){
this.name=name
}
sayHello(){
console.log( "谢谢你来看我的笔记")
}
}
6.class属性的修饰符
TS可以在属性前面添加属性的修饰符
属性修饰符 | 作用 |
---|---|
static | 使用static开头的属性成为静态属性(类属性),只能通过类去调用 |
readonly | 表示一个只读属性,只能读取不能修改。为typescript中使用。 |
public | 默认值,公共属性,谁都可以访问。 |
private | 私有属性,只能在类内部进行访问 编程规范一般私有属性都是 _ 下划线开头 |
protected | 受保护的属性,只能在当前类和当前类的子类中使用和修改。 |
6.泛型
泛型的作用场景:当我们定影函数或类时,如果遇到类型不明确的就可以使用泛型。
1.泛型在函数中的使用
1.泛型在函数中的定义:
< 自定义的名字 >
function fn < T > (a:T):T{
return a
}
2.泛型在函数中的使用
1.不指定泛型,直接调用。TS可以自动检测类型(有时不准)
let result = fn ( a:10)
2.指定泛型(推荐)
let result2=fn <srting>(a:'hello')
3.泛型在函数中可以定义多个
function fn <L,V>(a:L,B:V):L{
console.log(a)
console.log(B)
return a,B
}
fnM<number,string> (a:1,B:"憨八龟")
4.泛型实现接口
2.泛型在类中使用
class Person<T>{
name:T;
constructor(name:T){
this.name=name
}
}
const mc = new Person <string> (name:"憨八龟")