TypeScript
TypeScript是什么
- 以JavaScript为基础构建的语言
- 一个JavaScript的超集
- 可以在任何支持JavaScript的平台中执行 (TS不能被JS解析器直接执行)
- TypeScript扩展了JavaScript,并添加了类型
TypeScript增加了什么
- 类型
- 支持ES的新特性
- 添加ES不具备的新特性
- 丰富的配置选项
- 强大的开发工具
TypeScript开发环境搭建
- 下载Node.js
- 安装Node.js
- 使用npm全局安装typescript npm i -g typescript
- 创建一个ts文件
- 使用tsc对ts文件进行编译
- 进入命令行
- 进入ts文件所在目录
- 执行命令:tsc xxx.ts
TS的类型声明
基本类型
-
类型声明
-
类型声明式TS非常重要的一个特点
-
通过类型声明可以指定TS中变量(参数,形参)的类型
-
指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则会报错
-
简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值
-
语法
let 变量:类型 let 变量:类型 = 值 function fn(参数:类型,参数:类型):类型 { ... }
-
-
自动类型判断
- TS拥有自动的类型判断机制
- 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
- 所以如果你的变量的声明和赋值是同时进行的,可以省略掉类型声明
-
类型
| 类型 | 例子 | 描述 |
|---|---|---|
| number | 1,-33,2.5 | 任意数字 |
| string | "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中新增类型 |
number
let decimal:number = 6
let hex:number = 0xf00d
let binary:number = 0o744
let big:bigint = 100n
boolean
let isDone:boolean = false
string
let color:string = 'blur'
color = 'red'
let fullName:string = `Bob Bobbington`
let age:number = 37
let sentence:string = `Hello,my name is ${fullName}`
字面量
// 也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围
let color: 'red' | 'blue' | 'black'
let num: 1 | 2 | 3
any
let d:any = 4
d = 'hello'
d = true
unknown
let notSure:unknown = 4
notSure = 'hello'
void
function fn(message:string):void {
xxx
}
let unusable:void = undefined
never
function error(message:string):never {
throw new Error(message)
}
object(没什么用)
let obj:object = {}
array
let array:number[] = [1,2]
let array: Array<number> = [1,2]
tuple
let x :[string,number]
x = ['hello',10]
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
类型断言
有些情况下,变量的类型对于我们来说是很明确,但是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
TS编译选项
自动编译文件
编译文件时, 使用-w 指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译
示例
tsc xxx.ts -w
自动编译整个项目
-
如果直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件
-
但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置tsconfig.json
-
tsconfig.json是一个JSON文件,添加配置文件后,只需tsc命令即可完成对整个项目的编译
-
配置选项
-
include
- 定义希望被编译文件所在目录
- 默认值:["* * /*"]
- 示例
// 上述示例中,所有src目录和tests目录下的文件都会被编译 **表示任意目录 *表示任意文件 "include":["src/**/*","tests/**/*"] -
exclude
-
定义需要排除在外的目录
-
默认值["node_modules","bower_components","jspm_packages"]
-
示例
"exclude":["./src/hello/**/*"]上述示例中,src下hello目录下的文件都不会被编译
-
-
extends
-
定义被继承的配置文件
-
示例
"extends":"./configs/base"上述示例中,当前配置文件中会自动包含config目录下base.json中的所有配置信息
-
-
files
-
指定被编译文件的列表,只有 需要编译的文件少时才会用到
-
示例
// 列表中的文件都会被TS编译器所编译 "files":[ "core.ts", "sys.ts", "types.ts", "scanner.ts", ]
-
-
compilerOption
-
编译选项是配置文件中非常重要也比较复杂的配置选项
-
在compilerOptions中包含多个子选项,用来完成对编译的配置
"compilerOptions":{ // target 用来指定ts被编译为的ES版本 // es3 es5 es6 es2015 es2016 es2017 es2018 es2109 es2020 esnext "target":"es2015", // module 指定要使用模块化的规范 // 'none''commonjs''amd''system''umd''es6' 'es2015' 'es2109' 'es2020' "module":"es2015", // lib用来指定项目中要使用的库 一般默认值 到Node 根据实际在改 "lib":["dom"], // outDir 用来指定编译文件所在的目录 "outDir":'./dist', // outFile 将代码合并为一个文件 设置outFile后,所有的全局作用域中的代码会合并到同一个文件 要注意模块化 "outFile":"./dist/app.js", // 是否对js文件进行编译,默认是false "allowJs":false, // 是否检查JS 符合语法规范,默认是false "checkJs":false, // 是否移除注释 "removeComments":false, // 不生成编译后的文件 "noEmit":false, // 当有错误时不生成编译后的文件 "noEmitOnError":true, // 所有的严格检查的总开关 "strict":true, // 用来设置编译后的文件是否使用严格模式,默认false "alwaysStrict":false, // 是否允许隐式的any "noImplicitAny": false, // 是否允许隐式的this "noImplicitThis":false, // 严格的检查空值 "strictNullChecks":false, }
-
-
使用webpack打包ts代码
-
安装依赖
-
npm i -D ts-loader typescript webpack webpack-cli webpack-dev-server @babel/core @babel/preset-env babel-loader clean-webpack-plugin core-js html-webpack-plugin
-
创建tsconfig.json webpack.config.js 文件
// webpack.config.js // 引入一个包 const path = require('path') // 引入html插件 const HTMLWebpackPlugin = require("html-webpack-plugin") // 引入clean插件 const {CleanWebpackPlugin} = require('clean-webpack-plugin') //webpack中的所有的配置信息都应该写在module.exports中 module.exports = { // 指定入口文件 entry:"./src/index.ts", // 指定打包文件所在的目录 output:{ // 指定打包文件的目录 path:path.resolve(__dirname,'dist'), // 打包后文件的文件 filename: "bundle.js", // 告诉webpack 不使用箭头 environment:{ arrowFunction: false } }, // 指定webpack打包时要使用模块 module:{ // 指定要加载的规则 rules:[ { // test指定的是规则生效的文件 test:/\.ts$/, // 要使用的loader use:[ // 配置babel { //指定加载器 loader:"babel-loader", // 设置babel options:{ // 设置预定义的环境 presets:[ [ // 指定环境的插件 "@babel/preset-env", //配置信息 { // 要兼容的目标浏览器 targets:{ "chrome":"58", "ie":"11" }, // 指定corejs的版本 "corejs":"3", // 使用corejs的方式"usage" 表示按需加载 "useBuiltIns":"usage" } ] ] } }, "ts-loader"], // 要排除的文件 exclude: /node-module/ } ], }, // 配置webpack插件 plugins:[ // 每次清除dist new CleanWebpackPlugin(), new HTMLWebpackPlugin({ //title:"这是一个自定义的title" template:"./src/index.html" }), ], // 用来设置引用模块 resolve:{ extensions:['.ts','.js'] } }tsconfig.json { "compilerOptions":{ "target":"es2015", "module":"es2015", "strict":true } }package.json { "name": "part3", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack", "start": "webpack serve --open --mode=development" }, "author": "", "license": "ISC", "devDependencies": { "@babel/core": "^7.16.0", "@babel/preset-env": "^7.16.4", "babel-loader": "^8.2.3", "clean-webpack-plugin": "^4.0.0", "core-js": "^3.19.3", "html-webpack-plugin": "^5.5.0", "ts-loader": "^9.2.6", "typescript": "^4.5.3", "webpack": "^5.65.0", "webpack-cli": "^4.9.1", "webpack-dev-server": "^4.6.0" }, "dependencies": {} }
-
面向对象
面向对象是程序中一个非常重要的思想,面向对象,简而言之就是程序之中所有的操作都要通过对象来完成。
举例来说:
操作浏览器要使用window对象
操作网页要使用document对象
操作控制台要使用console对象
一切操作都要通过对象,也就是所谓的面向对象,那么对象到底是什么呢?这就要先说到程序是什么,计算机程序的本质就是对现实事物的抽象,抽象的反义词是具体,比如:照片是对一个具体的人的抽象,汽车模型是对具体汽车的抽象等等。程序也是对事物的抽象,在程序中我们可以表示一个人,一条狗等等所有的事物。一个事物到了程序中就变成了一个对象。
在程序中所有的对象都被分成了两个部分数据和功能,以人为例,人的姓名、性别、年龄、身高、体重等属于数据,人可以说话、走路、吃饭、睡觉属于人的功能。数据在对象中被称为属性,而功能被称为方法,简而言之,在程序中一切皆是对象
类
class 类名 {
属性名:类型
constructor(参数:类型) {
this.属性名 = 参数
}
方法名() {}
}
class Person {
static readonly name:string //静态 只读
age:number
constructor(name:string,age:number) {
this.name = name
this.age = age
}
sayHello() {
console.log(213)
}
}
// 简写方式
class Person {
constructor(public name:string, public age:number) {}
sayHello() {
console.log(213)
}
}
接口
// 描述一个对象的类型 type 不可以重复定义
type myType = {
name:string,
age:number
}
// 接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法
// 同时接口也可以当成类型声明去使用
// 接口是所有同名的合并
interface myInterface {
name:string;
age:number
}
interface myInterface {
gender:string
}
/*
接口可以在定义类的时候去限制类的结构
接口中的所有属性都不能有实际的值
接口只定义对象的结构,而不是考虑实际值
在接口中所有的方法都是抽象方法
*/
interface myInter {
name: string
sayHello() :void
}
/*
定义类时,可以使类去实现一个接口
实现接口就是使类满足接口的要求
*/
class Myclass implements myInter {
name:string
constructor(name:string) {
this.name = name
}
sayHello() :void {
console.log("hello world")
}
}
属性的封装
class Person {
/*
public 修饰的属性可以在任意位置访问(修改)默认值
private 私有属性,私有属性只能在类内部进行访问(修改)
通过类中添加方法使得私有属性可以被外部访问
protected 受包含的属性,只能在当前类和继承类访问
*/
private name:string
age:number
constructor(name:string,age:number) {
this.name = name
this.age = age
}
// 定义方法,用来获取name属性
getName() {
return this.name
}
// 定义方法,用来设置name
setName(name:string) {
this.name = name
}
/*
getter 用来读取属性
setter 用来设置属性
他们被称为属性的存取器
*/
get age() {
return this.age
}
set age(value:number) {
this.age = value
}
}
const per = new Person("孙悟空",18)
/*
现在属性是在对象中设置的,属性可以任意的被修改
属性可以任意被修改将会导致对象中的数据变得非常不安全
*/
泛型
// 在定义函数或是类时,如果遇到类型不明确就可以使用泛型
function fn<T>(a:T):T {
return a
}
// 可以直接调用具有泛型的函数
fn(10) // 不指定泛型,TS可以自动对类型进行推断 但不一定能推断出来
fn<string>("hello") // 指定泛型
// 泛型可以同时指定多个
function fn2<T,K> (a:T,b:K):T {
console.log(b)
return a
}
fn2<number,string>(2,"hello world")
interface Inter {
length:number;
}
// T extends Inter 表示泛型T必须实现Inter实现类(子类)
function fn3<T extends Inter>(a:T):number {
return a.length
}
fn3({length:10})
class MyClass<T> {
name:T
construcctor(name:T) {
this.name = name
}
}
const xx = new MyClass<string>("sunwukong")