TypeScript(一)
- TypeScript简介
- TypeScript 开发环境搭建
- 基本类型
- 1、类型声明
- 2、自动类型判断
- 3、类型
- 编译选项
- webpack
- Babel
TypeScript简介
- TypeScript是JavaScript的超集。
- 它对JS进行了扩展,向JS中引入了类型的概念,并添加了许多新的特性。
- TS代码需要通过编译器编译为JS,然后再交由JS解析器执行。
- TS完全兼容JS,换言之,任何的JS代码都可以直接当成JS使用。
- 相较于JS而言,TS拥有了静态类型,更加严格的语法,更强大的功能;TS可以在代码执行前就完成代码的检查,减小了运行时异常的出现的几率;TS代码可以编译为任意版本的JS代码,可有效解决不同JS运行环境的兼容问题;同样的功能,TS的代码量要大于JS,但由于TS的代码结构更加清晰,变量类型更加明确,在后期代码的维护中TS却远远胜于JS。
TypeScript 开发环境搭建
-
下载Node.js
-
安装Node.js
-
使用npm全局安装typescript
(1)进入命令行
(2)输入:npm i -g typescript -
创建一个ts文件
-
使用tsc对ts文件进行编译
(1)进入命令行
(2)进入ts文件所在目录
(3)执行命令:tsc xxx.ts(会将ts文件转换成js文件,添加到目录中)
基本类型
1、类型声明
-
类型声明是TS非常重要的一个特点
-
通过类型声明可以指定TS中变量(参数、形参)的类型
-
指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错
-
简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值
-
语法:
let 变量: 类型;
let 变量: 类型 = 值;
function fn(参数: 类型, 参数: 类型): 类型{
...
}
2、自动类型判断
- TS拥有自动的类型判断机制
- 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
- 所以如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明
栗子:
(1)声明一个变量并指定它的类型
// 声明一个变量a,同时指定它的类型为number
let a: number
// a类型为number,在以后的使用中a的值只能是数字
a = 10
a = 'hello' //报错,不能赋字符串
let b: string
b = 'hello'
(2)声明完变量直接赋值(但这种方法不常用,原因见(3))
let c: boolean = true
(3)如果变量的声明与赋值是同时进行的,TS可以自动对变量进行类型检测(此时就不用像上一步那样指定类型)
let c = true //相当于声明了 c 是 Boolean类型
c = false
c = 123 //此行会报错
(4)类型声明的优势主要体现在对函数参数的类型声明上 !
js中对于函数的声明:
// js函数是不考虑参数的类型和个数的
function sum(a,b) {
return a + b
}
sum(22, '88', 12) //js当参数是字符串,或者 有多个参数时都不会报错
console.log(sum);
ts 中对于函数的声明:
// ts
function sum(a:number, b:number){
return a + b
}
sum(123,'456') //报错
// 指定函数返回值的类型
function sum(a:number, b:number): number{
return a + b
}
3、类型
类型 | 例子 | 描述 |
---|---|---|
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)字面量
// 可以直接使用 字面量 进行类型声明
let num: 10;
// 但此时 num的值只能为10,不能改成其他的
num = 10 //不报错
num = 11 //报错
(2)可以使用 | 来连接多个类型(联合类型)
let str: 'male' | 'female'
str = 'male'
str = 'female'
str = 'hello' //报错
// 也可以直接指定类型
let s: boolean | string
s= true
s= 'hello'
(3)any 任意类型,一个变量设置为any,相当于对该变量关闭了类型检测
(与js一样了,所以在开发中不建议使用)
let d:any
//d 可以被赋值为任意的数据类型
d = 10
d = 'hello'
d = true
// 声明变量如果不指定类型,TS解析器会自动判断变量的类型为any(隐私any,也要避免使用)
//let d
注:声明变量如果不指定类型,TS解析器会自动判断变量的类型为any(隐式any,也要避免使用)
(4)unknown
如果变量的类型不确定用unknown。unknown表示未知类型的值
let e: unknown
e = 20
e = 'hello'
e = true
与any的区别:
- any类型的值 可以赋值给任意变量并且不会报错
let d
d = true
let st: string
// d 的类型是any(此时的值为true--Boolean类型),它可以赋值给任意变量并且不会报错。
// 这就会导致此时st的值会受到影响。本来应该是string却变成了Boolean类型,并且没有报错
st = d //这里不会报错,但实际上这样赋值是不对的
- unknown类型的值 不能直接赋值给其他变量
let e: unknown
e = 'hello'
let st: string
st = e //会报错
将unknown类型的值 赋值给其他变量,有两种方式:
- 先进行类型检测再赋值
if(typeof e === 'string'){
st = e
}
- 类型断言–用来告诉解析器 变量的实际类型
断言有两种声明方式:
st = e as string //告诉解析器,这个 e 是string类型。这样就可以赋值了
st = <string>e
(5)指定函数的返回值
function fn(): number{}
function fn(): string{}
function fn(): void{}
function fn(): never{}
- void
void用来表示空,以函数为例,表示没有返回值的函数
不写返回值,或者返回的是 null / undefined 均不会报错
function fn(): void{
// return null
//return undefined
}
- never
表示永远不会返回结果(用于抛出异常,不常用)
function fn2(): never{
throw new Error('报错了')
}
(6)object
- object表示一个js对象(不常使用),
let o: object
因为 js 对象有更简单的表示方式:o = {}
或者o = function(){}
- 在声明对象时 常用于 指定对象中属性的类型:
// 指定对象中可以包含哪些属性
let o1: {name: string, age?: number}
o1 = {name:'sunwukong',age:18}
- 语法:{属性名:属性值,属性名:属性值}
- 在属性名后加上 ?,表示属性是可选的。(在后续赋值时可以不指定 age。但必须指定name)
-
如果想在 一个对象中 增加多个可选的属性,可以使用:
[propName: string]: any 表示任意类型的属性
// [propName: string]: any 表示任意类型的属性
let o2: {name:string, [propName: string]: any}
o2 = {name:'猪八戒', age:18, gender:'男'}
- 函数结构的类型声明
- 语法:(形参:类型,形参:类型…) => 返回值
let o3: (a:number,b: number) => number
o3 = function(n1,n2): number{
return n1 + n2
}
指定 形参以及返回值 的类型
(7)数组的类型声明
两种方式:
- 类型[]
// string[] 表示字符串数组
let arr: string[]
arr = ['a','b','c']
// arr = ['a','b','c',1,2] //报错
// number[] 表示数值数组
let f: number[]
- Array<类型>
let g: Array<number>
g = [1,2,3]
(8)tuple(元组):固定长度的数组
- 语法: [类型,类型,类型…]
let h: [string,string]
// h = ['hello', 'hi', 123] //报错
h = ['hello', 'hi']
(9)enum (枚举)
- 适用于像性别这种值固定的情况,不用再指定 男为0,女为1。直接使用 Gender.xxx
// 定义枚举
enum Gender{
Male,
Female
}
let i: {name:string, gender:Gender}
i = {
name:'孙悟空',
gender:Gender.Male
}
console.log(i.gender === Gender.Male);
(10)&表示同时
let j: {name:string} & {age:number}
// j = {name:'孙悟空'} //报错
j = {name:'孙悟空', age:80}
(11)类型的别名
- 可以将需要反复用到的类型给他起个别名,方便后续使用
// 类型的别名
type myType = 1|2|3|4|5
let k: myType
let l: myType
k = 1
//k = 9 //报错
编译选项
1、自动编译文件
(1)编译文件时,使用 -w 指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。
(2)示例:tsc xxx.ts -w
2、自动编译整个项目
(1)如果直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件。
(2)但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置文件 tsconfig.json(创建方式:在终端执行 tsc --init
)
(3)tsconfig.json是一个JSON文件,添加配置文件后,只需 在终端 输入 tsc
命令即可完成对整个项目的编译(将ts 转换成 js)。也可使用 tsc -w
来对监视所有文件的变化。
(4)tsconfig.json的配置选项:
- include:定义希望被编译文件所在的目录(指定哪些 ts 文件需要被编译)
- 默认值:[“**/*”] ,
**
表示任意目录,*
表示任意文件 - 示例:
"include":["src/**/*", "tests/**/*"]
- 上述示例中,所有src目录和tests目录下的文件都会被编译
- exclude:定义需要排除在外的目录
- 默认值:
["node_modules", "bower_components", "jspm_packages"]
- 示例:
"exclude": ["./src/hello/**/*"]
- 上述示例中,src下hello目录下的文件都不会被编译
- extends:定义被继承的配置文件
- 示例:
"extends": "./configs/base"
- 上述示例中,当前配置文件中会自动包含config目录下base.json中的所有配置信息
- files:指定被编译文件的列表,只有需要编译的文件少时才会用到
- 示例:
"files": [
"core.ts",
"sys.ts",
"types.ts",
]
- 列表中的文件都会被TS编译器所编译
- compilerOptions
- 编译选项是配置文件中非常重要也比较复杂的配置选项
- 在compilerOptions中包含多个子选项,用来完成对编译的配置:
{
"include": ["./src/**/*"],
// 编译器选项
"compilerOptions": {
// target 用来指定ts 被编译的 js 版本
// 可选值:"ES3"(默认), "ES5", "ES6", "ES2015", "ES2016", "ES2017", "ES2018", "ES2019", "ES2020", "ES2021", "ES2022", "ESNext"
"target": "es6",
// module 指定要使用的模块化规范
// 可选值:"CommonJS", "AMD", "System", "UMD", "ES6", "ES2015", "ES2020", "ESNext", "None", "ES2022", "Node16", "NodeNext"
"module": "system",
// lib 用来指定项目中所使用的库(一般不需要设置,有默认值)
// 可选值:ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost ......
"lib": ["ES6"],
//outDir 指定编译后 js文件所在的目录
"outDir": "./dist",
// outFile 将代码 合并成一个文件(将所有ts文件编译后的代码都放到 app.js中)
"outFile": "./dist/app.js",
// allowJs 是否对js文件进行编译,默认为false
"allowJs": true,
// checkJs 是否检查js代码是否符合语法规范,默认是false
"checkJs": true,
// removeComments 是否移除注释,默认false不移除
"removeComments": true,
// noEmit ,默认false不生成编译后的文件
"noEmit": true
// noEmitOnError,当有错误时不生成编译后的文件(false)
"noEmitOnError": true
}
}
与语法检查相关的配置:
{
......
// strict 所有严格检查的总开关。为true时后面的几个配置项都默认为true,可以不写。(一般都设为true)
"strict": true,
// js文件设置严格模式方式:在文件的开头添加 "Use Strict"
// alwaysStrict 设置编译后的文件是否使用严格模式,默认false
"alwaysStrict": true,
// noImplicitAny 不允许隐式的any类型,默认false
"noImplicitAny": true,
// noImplicitThis 不允许不明确类型的this,默认false
"noImplicitThis": true,
// strictNullChecks 严格地检查空值,默认false
"strictNullChecks": true
}
}
webpack
1、通常情况下,实际开发中我们都需要使用构建工具对代码进行打包,TS同样也可以结合构建工具一起使用,下边以webpack为例介绍一下如何结合构建工具使用TS。
2、步骤:
(1)初始化项目
- 进入项目根目录,执行命令
npm init -y
- 主要作用:创建package.json文件
(2)下载构建工具
在终端执行:npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin
工具名 | 作用 |
---|---|
webpack | 构建工具webpack |
webpack-cli | webpack的命令行工具 |
webpack-dev-server | webpack的开发服务器(内容改变时会自动重新编译并执行) |
typescript | ts编译器 |
ts-loader | ts加载器,用于在webpack中编译ts文件 |
html-webpack-plugin | webpack中html插件,用来自动创建html文件 |
clean-webpack-plugin | webpack中的清除插件,每次构建都会先清除目录 (清除以前生成的文件) |
注:
-
安装 webpack 后,需要在package.json中添加
"build":"webpack"
-
安装 webpack-dev-server 后,需要在package.json中添加
"start": "webpack serve --open chrome.exe"
(表示 启动webpack服务器并使用谷歌浏览器去打开网页。通过 npm start 调用)
如果使用VSCode 会报404. 使用"start": "webpack serve --open --mode development"
解决 -
新版的webpack 不需要使用清除插件,在 output 中 添加
clean:true
就行
(3)基础配置
webpack.config.js:
// 引入包,帮助拼接路径
const path = require('path')
// 引入html插件,用于生成html文件
const HTMLWebpackPlugin = require('html-webpack-plugin')
// 引入清除插件
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
// webpack中的所有配置信息都应该写在module.exports中
module.exports = {
// 指定入口文件
entry:'./src/index.ts',
// 指定打包文件所在的目录
output:{
// 指定打包文件的目录(利用path 将路径拼接起来)
path:path.resolve(__dirname,'dist'),
// 打包后文件的名字
filename:'bundle.js'
},
// 指定webpack打包时要使用的模块
module:{
// 指定要加载(loader)的规则
rules:[
{
// test 指定规则生效的文件(对谁进行编译--这里是以.ts结尾的文件)
test: /\.ts$/,
// 使用什么加载器来处理上面的文件。ts文件对应的就是 ts-loader
use:'ts-loader',
// 要排除的文件(不进行处理的文件,通常是node-modules)
exclude: /node-modules/
}
]
},
// plugins 配置 webpack 的插件
plugins:[
// 执行 npm run build 后,webpack会自动生成一个导入了 转译后的js文件的 html文件
// new HTMLWebpackPlugin(), //()不写东西,会使用默认的html配置
// 给它指定配置
new HTMLWebpackPlugin({
// title:'这里定义html文件的title', 这种方式适用于单个文件
// 如果想让多个html文件的结构一致,可以自己在某个目录下新建一个html文件并写好结构,将其作为模板
template:"./src/index.html"
}),
// 使用清除插件。注:新版的webpack 可以直接在 output中设置 clean:true 就行
new CleanWebpackPlugin()
],
// 用来设置引用模块(哪些文件可以作为模块使用)
resolve:{
extensions:['.ts','.js'] //以.ts 和.js 结尾的文件
}
}
备注:__dirname 可以用来动态获取当前文件所属目录的绝对路径。
新建 tsconfig.json:
{
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true
}
}
在package.json添加如下配置:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack serve --open --mode development"
},
(4)在src下创建ts文件,并在并命令行执行npm run build
对代码进行编译,或者执行npm start
来启动开发服务器
Babel
1、经过一系列的配置,使得TS和webpack已经结合到了一起,除了webpack,开发中还经常需要结合babel来对代码进行转换以使其可以兼容到更多的浏览器,在上述步骤的基础上,通过以下步骤再将babel引入到项目中。
注:上一节中tsconfig.json的配置是将ts代码转换成了es6的语法,兼容性较差。使用Babel可以将其转换成更多浏览器可以兼容的低版本代码。
2、步骤
(1)安装依赖包:
npm i -D @babel/core @babel/preset-env babel-loader core-js
- 共安装了4个包,分别是:
- @babel/core : babel的核心工具
- @babel/preset-env:babel的预定义环境
- @babel-loader:babel在webpack中的加载器
- core-js:core-js用来使老版本的浏览器支持新版ES语法
(2)修改webpack.config.js配置文件
......
module:{
// 指定要加载(loader)的规则
rules:[
{
// test 指定规则生效的文件(对谁进行编译--这里是以.ts结尾的文件)
test: /\.ts$/,
// 使用什么加载器来处理上面的文件。ts文件对应的就是 ts-loader
use:[
// 加载器的执行时从后往前执行,所以把 ts-loader 放到后面。先让ts-loader将ts代码转成js,然后再用babel把新版本的js转换成旧版本的js
// 配置babel
{
// 指定加载器
loader:"babel-loader",
// 设置babel 要兼容的浏览器
options:{
// 设置预定义的环境
presets:[
[
// 指定环境的插件
"@babel/preset-env",
// 配置信息
{
// 指定浏览器的版本
targets:{
"chrome": "58",
"ie":"11"
},
// core-js的版本,在package.json中可以找到
"corejs":"3",
// 使用core-js的方式. "usage"表示按需加载
"useBuiltIns":"usage"
}
]
]
}
},
'ts-loader',
],
// 要排除的文件(不进行处理的文件,通常是node-modules)
exclude: /node-modules/
}
]
},
......
如此一来,使用ts编译后的文件将会再次被babel处理,使得代码可以在大部分浏览器中直接使用,可以在配置选项的targets中指定要兼容的浏览器版本。
更多推荐
TypeScript学习笔记(一)
发布评论