目录
简介
以JavaScript为基础构建的语言,一个JavaScript的超集。扩展了JavaScript并添加了类型
可以在任何支持JavaScript的平台执行,不能直接被JavaScript解析器直接执行(需要进行编译)
一:环境搭建
1: 下载并安装Node.js:下载 | Node.js 中文网
2: npm全局安装typescript
命令行输入:npm i -g typescript3: 验证typescript安装成功(部分截图)
命令行输入:tsc
4: 创建一个ts文件5: 使用tsc命令对ts文件进行编译
进入命令行 => 进入ts文件所在目录 => 执行命令:tsc xxx.ts
二:基本类型
通过类型声明可以指定TS中变量(参数、形参)的类型,指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错
let 变量: 类型; let 变量: 类型 = 值; //最后一个是指定返回值类型 function fn(参数: 类型, 参数: 类型): 类型{ ... }
常见类型
类型 例子 描述 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:number//a 的类型设置为了number,在以后的使用过程中a的值只能是数字 let a: number = 6; //a = 'hello'; // 此行代码会报错
2:string
let b: string; b = 'hello'; // b = 123; // 此行代码会报错
3:boolean
let c: boolean = false; // 如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测 let c = false; c = true;
4:字面量
//通过字面量可以确定变量的取值范围 //可以使用 | 来连接多个类型(联合类型) let color: 'red' | 'blue' | 'black'; let num: 1 | 2 | 3 | 4 | 5;
5:any
//any 表示的是任意类型,一个变量设置类型为any后相当于对该变量关闭了TS的类型检测 // 使用TS时,不建议使用any类型 let d: any = 4;(显式的any) d = 'hello'; d = true; // 声明变量如果不指定类型,则TS解析器会自动判断变量的类型为any let d;(隐式的any)
6:unknown
// unknown 表示未知类型的值 let e: unknown; e = 10; e = "hello"; e = true; // unknown 实际上就是一个类型安全的any,不能直接赋值给其他变量 //s = e; //报错 if(typeof e === "string"){ s = e; }
7:void
// void 用来表示空,以函数为例,就表示:没有返回值的函数 function fn(): void{ }
8:never
// never 表示永远不会返回结果 function fn2(): never{ throw new Error('报错了!'); }
9:object
// object表示一个js对象 let a: object; a = {}; a = function () { }; // 语法:{属性名:属性值,属性名:属性值} // 在属性名后边加上?,表示属性是可选的 let b: {name: string, age?: number}; b = {name: '石昊', age: 18}; // [propName: string]: any 表示任意类型的属性。必须包含name属性,其余的可有可无 let c: {name: string, [propName: string]: any}; c = {name: '火灵儿', age: 18, gender: '女'}; /* * 设置函数结构的类型声明: * 语法:(形参:类型, 形参:类型 ...) => 返回值 * */ let d: (a: number ,b: number)=>number; //等价于 《 === 》 // d = function (n1: string, n2: string): number{ // return 10; // }
10:array
/* * 数组的类型声明: * 类型[] * Array<类型> * */ // string[] 表示字符串数组 let e: string[]; e = ['a', 'b', 'c']; // number[] 表示数值数值 let f: number[]; let g: Array<number>; g = [1, 2, 3];
11:tuple
/* * tuple元组,元组就是固定长度的数组 * 语法:[类型, 类型, 类型] * */ let h: [string, number]; h = ['hello', 123];
12:enum
/* * enum 枚举 * * */ enum Gender{ Male, Female } let i: {name: string, gender: Gender}; i = { name: '石昊', gender: Gender.Male // 'male' }
13:类型断言 & 类型别名
//可以用来告诉解析器变量的实际类型 /* * 语法: * 1:变量 as 类型 * 2:<类型>变量 * * */ let e: unknown; let s: string; s = e as string; s = <string>e; // 类型的别名 type myType = 1 | 2 | 3 | 4 | 5; let k: myType; k = 2;
三:Ts配置与编译
(一):自动编译文件
使用 -w 指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。
命令行: tac xxx.ts(编译)
tsc xxx.ts -w(编译并监视)
(二):自动编译整个项目
第一步:在项目根目录下创建一个ts的配置文件 tsconfig.json
第二步:在tsconfig.json文件中,添加配置项
配置选项如下:
1:include - 希望被编译文件所在的目录
默认值:["\*\*/\*"]
例如:"include":["src/**/*", "tests/**/*"] <所有src目录和tests目录下的文件都会被编译>
2:exclude - 需要排除在外的目录
默认值:["node_modules", "bower_components", "jspm_packages"]
例如:"exclude": ["./src/hello/**/*"] <src下hello目录下的文件都不会被编译>
3:extends - 被继承的配置文件
例如: "extends": "./configs/base" <当前配置文件中会自动包含config目录下base.json中的所有配置信息>
4:files - 指定被编译文件的列表,只有需要编译的文件少时才会用到
例如: "files": [
"core.ts",
"sys.ts",...
] <列表中的文件都会被TS编译器所编译>5:compilerOptions - 包含多个子选项,用来完成对编译的配置
{ "extends": "@tsconfig/node20/tsconfig.json",//自动包含tsconfig.json中的所有配置信息 "include": ["vite.config.*"],//所有src目录和tests目录下的文件都会被编译 "exclude": ["/node_modules"],//node_modules目录下的文件不会被编译 "files": ["core.ts","sys.ts"], //列表中的文件都会被TS编译器所编译 "compilerOptions": { "target": "ES6", //所编写的ts代码将会被编译为ES6版本的js代码 "lib": ["ES6", "DOM"], "module": "CommonJS", "outDir": "dist", //设置后编译后的js文件将会生成到dist目录 "outFile": "dist/a.js", // 所有js文件合并为一个a.js文件 "rootDir": "./src", //指定src为根目录 "allowJs": true, //对js文件进行编译 "checkJs": true, //对js文件进行检查 "removeComments": true, //删除注释 "noEmit": true, //不对代码进行编译 "sourceMap": true, //生成sourceMap } }
(1):target - 设置ts代码编译的目标版本
可选值:ES3(默认)、ES5、ES6/ES2015、ESNext等
(2):lib - 指定代码运行时所包含的库(宿主环境)
可选值:ES3(默认)、ES5、ES6/ES2015、ESNext、DOM、WebWorker、ScriptHost等
(3):module - 编译后代码使用的模块化系统
可选值:CommonJS、UMD、AMD、System、ES2020、ESNext、None
(4):outDir - 编译后文件的所在目录
默认情况下,编译后的js文件会和ts文件位于相同的目录,设置outDir后可以改变编译后文件的位置
(5):outFile - 将所有的文件编译为一个js文件
默认会将所有的编写在全局作用域中的代码合并为一个js文件,如果module制定了None、System或AMD则会将模块一起合并到文件之中
(6):rootDir - 指定代码的根目录
默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过rootDir可以手动指定根目录
(7):allowJs - 是否对js文件编译
(8):checkJs - 是否对js文件进行检查
(9):removeComments - 是否删除注释
默认值:false
(10):noEmit - 不对代码进行编译
默认值:false
(11):sourceMap - 是否生成sourceMap
默认值:false
6:严格检查
strict: 启用所有的严格检查,默认值为true,设置后相当于开启了所有的严格检查
alwaysStrict: 总是以严格模式对代码进行编译
noImplicitAny: 禁止隐式的any类型
noImplicitThis: 禁止类型不明确的this
strictBindCallApply: 严格检查bind、call和apply的参数列表
strictFunctionTypes: 严格检查函数的类型
strictNullChecks: 严格的空值检查
strictPropertyInitialization: 严格检查属性是否初始化
7:额外检查
noFallthroughCasesInSwitch: 检查switch语句包含正确的break
noImplicitReturns: 检查函数没有隐式的返回值
noUnusedLocals: 检查未使用的局部变量
noUnusedParameters: 检查未使用的参数
8:高级
allowUnreachableCode: 检查不可达代码
可选值:
true - 忽略不可达代码
false - 不可达代码将引起错误
noEmitOnError: 有错误的情况下不进行编译
默认值 - false
四:webpack - ts
TS同样结合构建工具Webpack一起使用
1: 初始化项目
进入项目根目录,执行命令 npm init -y , 创建package.json文件。
2: 下载构建工具, 共安装7个包npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin 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中的清除插件,每次构建都会先清除目录
3: 根目录下创建webpack的配置文件webpack.config.js
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = { optimization:{ minimize: false // 关闭代码压缩,可选 }, entry: "./src/index.ts", devtool: "inline-source-map", devServer: { contentBase: './dist' }, output: { path: path.resolve(__dirname, "dist"), filename: "bundle.js", environment: { arrowFunction: false // 关闭webpack的箭头函数,可选 } }, resolve: { extensions: [".ts", ".js"] }, module: { rules: [ { test: /\.ts$/, use: { loader: "ts-loader" }, exclude: /node_modules/ } ] }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ title:'TS测试' }), ] }
4: 根目录下创建tsconfig.json,配置可以根据自己需要
{ "compilerOptions": { "target": "ES2015", "module": "ES2015", "strict": true } }
5: 修改package.json添加如下配置
{ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack", "start": "webpack serve --open chrome.exe" }, }
6:在src下创建ts文件,并在并命令行执行 npm run build 对代码进行编译,或者执行 npm start 来启动开发服务器
五:webpack - babel
结合babel来对代码进行转换以使其可以兼容到更多的浏览器
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: 用来使老版本的浏览器支持新版ES语法
2: 修改webpack.config.js配置文件
... module: { rules: [ { test: /\.ts$/, use: [ { loader: "babel-loader", options:{ presets: [ [ "@babel/preset-env", { "targets":{ "chrome": "58", "ie": "11" }, "corejs":"3", "useBuiltIns": "usage" } ] ] } }, { loader: "ts-loader", } ], exclude: /node_modules/ } ] } ...
如此一来,ts编译后的文件会再次被babel处理,使得代码可以在大部分浏览器中直接使用,可以在配置选项的targets中指定要兼容的浏览器版本。
六:面向对象 - 类
在程序中一切皆是对象
在程序中所有的对象都被分成了两个部分 - 数据和功能,以人为例:
人的姓名、性别、年龄、身高、体重等属于数据,
人可以说话、走路、吃饭、睡觉这些属于人的功能。
数据在对象中被成为属性,而功能就被称为方法。
使用class关键字来定义类
对象中主要包含两个部分
- 属性
- 方法
直接定义的属性是实例属性,需要通过对象的实例去访问
let person = new Person();
person.name
使用static关键字开头的是静态属性(类属性),可以直接通过类访问
Person.agereadonly 表示只读属性不能修改
直接定义的方法是实例方法,需要通过对象的实例去访问
person.upLevel();
使用static关键字开头的是静态方法(类方法),可以直接通过类访问
Person.upLevel();<script setup lang="ts" name="theTsClass"> class Person{ //实例属性 name:string = '石昊'; //静态属性 在属性前使用static关键字可以定义类属性 //readonly 只读属性不能修改 static readonly age:number = 18; // 定义方法 static upLevel(){ console.log('升级神火境'); } } let person = new Person(); //实例属性 通过实例来访问 console.log('person.name=',person.name); //静态属性 通过类来访问 console.log('Person.name=',Person.age); //静态方法 通过类来访问 Person.upLevel(); </script>
七:构造函数- constructor
constructor 就是构造函数
调用时机:在对象创建的时候调用,即new的时候调用<script setup lang="ts" name="theConstroctor"> class Person{ // 一:定义属性 name: string; age: number; constructor(name:string, age:number){ // 实例方法中,this指代当前的实例(新建的那个对象) // 可以通过this向新建的对象中添加属性 // 二:属性赋值 this.name = name; this.age = age; } upLevel(){ // 可以通过this来代表当前调用方法的对象 console.log(this); } } let person = new Person('石昊',18); let person1 = new Person('火灵儿',18); person.upLevel(); person1.upLevel(); </script>
八:继承 - extends & super
extends - 继承
继承父类的所有属性和方法 (Person父类|超类 ---- codePeople子类)
方法重写 : 重新写父类中的方法(会覆盖),为子类单独所有
super - 调用父类的构造函数
子类中如果写了构造函数,则必须在子类的构造函数中对父类进行调用
需要传参:父类中的属性名,数量及名称保持完全一致
子类的构造函数会 覆盖 父类的构造函数
class Person{ name: string; age: number; constructor(name:string, age:number){ this.name = name; this.age = age; } upLevel(){ console.log('提升技能'); } } /* extends 继承父类的所有属性和方法 (Person父类|超类 - codePeople子类) 方法重写 : 重新写父类中的方法(会覆盖),为子类单独所有 */ class codePeople extends Person{ hobby: string /* 在子类中写了构造函数,则必须在子类的构造函数中对父类进行调用 子类的构造函数 会覆盖父类的构造函数 */ constructor(name: string, age: number, hobby:string){ //调用父类的构造函数 super(name, age); this.hobby = hobby } upLevel(): void { console.log('敲代码呀敲代吗') } } class testPeople extends Person{ // upLevel(): void { // console.log('自动化测测测') // } } let person = new codePeople('码农',18,'弹吉他'); let person1 = new testPeople('测试',18); console.log('person',person) //{name: '码农', age: 18, hobby: '弹吉他'} person.upLevel(); //敲代码呀敲代吗 person1.upLevel(); //提升技能
九:抽象类 - abstract
抽象类 - 以关键字 <abstract> 开头
与其他类区别不大,只是不能用来创建对象
专门用来被继承
抽象方法 - 以关键字 <abstract> 开头
没有方法体,只能定义在抽象类中
子类 必须 对抽象方法进行重写
只能定义在抽象类中
//抽象类 - 以关键字-abstract开头 abstract class Person{ name:string constructor(name:string){ this.name = name; } //抽象方法 - 以关键字-abstract开头 abstract upLevel():void } class codePeople extends Person{ age:number constructor(name:string, age:number){ super(name); this.age = age; } upLevel(): void { console.log('敲代码呀敲代码') } } let person = new codePeople('章三',18); console.log('person==',person);
十:接口 - interface
interface:接口用来定义一个类的结构,包含哪些属性和方法
也可以当做类型去使用
可以同时定义多个相同的interface,属性和方法会进行加和
接口中所有的属性和方法 都不能有具体的值
方法都是抽象方法
只定义结构,不考虑值
implements: 实现接口,定义类时,可以去实现接口
实现接口:让类满足接口的要求 - 所有的属性和方法
/* 接口 用来定义一个类的结构,包含哪些属性和方法 接口也可以当做类型去使用 可以同时定义多个相同的interface,属性和方法会进行加和 接口中所有的属性和方法 都不能有具体的值 方法都是抽象方法 只定义结构,不考虑值 */ interface myInterface { name: string; age: number; singsong(): void; } /* 定义类时,可以去实现一个接口 实现接口:让类满足接口的要求 - 所有的属性和方法 */ class myInter implements myInterface { name: string; age: number; constructor(name: string, age: number){ this.name = name; this.age = age; } singsong(){ console.log('唱歌') } } let inter = new myInter('石昊',12); console.log('inter===',inter) //myInter{name: '石昊', age: 12}
十一:类属性的访问权限
1: public:(默认值) 共有属性, 可以在任意位置访问/修改
2: private: 私有属性, 只能在当前类内部访问/修改
通过在类中添加方法, 让私有属性可以在外部被访问
确保数据的安全
3: protected:受保护的属性,只能在当前类、子类中访问/修改
属性可以借助getter / setter方法来访问 ,他们被称为属性读取器
getter 方法用来读取属性
setter 方法用来修改属性class Person { private name: string; private age: number; constructor(name: string, age: number){ this.name = name; this.age = age; } getName(){ return this.name; } setName(val:string){ this.name = val; } } let person = new Person('石昊', 18) person.getName(); //石昊 person.setName('火灵儿') //火灵儿 console.log('person=',person)
声明类的简易写法
class Person { name: string; age: number; constructor(name: string, age: number){ this.name = name; this.age = age; } } // <!-- 写法 等价于 --> class Person { //可以直接将属性定义在构造函数中 constructor(public name: string, public age: number){ } }
十二:范型
范型:在类型不明确的时候,使用变量来表示类型
FName...范型的名称,可以定义任意类型的名称
不指定范型,TS会自动对类型进行推断
指定范型:使用尖括号<>
//FName 范型的名称,可以定义任意类型的名称 //类型一 function fn<FName>(a:FName):FName{ console.log('a==',a) return a; } // 可以直接调用使用范型的函数 fn(123); // 不指定范型,TS会自动对类型进行推断 fn<string>('456'); //指定范型 fn<boolean>(true);
//类型二 function fn2<FName,FName2>(a:FName, b:FName2):FName{ console.log('a=',a,'----b=',b); return a; } fn2<string, number>('123',456);
//类型三 interface inter{ length: number } //FanName extends inter 必须是inter实现类/子类 function fn3<FanName extends inter>(a:FanName):number{ console.log('a.length=',a.length) return a.length; } fn3('kfjsdka')
//类型四 class MyClass<Fan>{ name:Fan; constructor(name:Fan){ this.name = name; } } let sh = new MyClass<String>('石昊') console.log('sh==',sh)