1、环境搭建
- 安装Node.js
- 使用npm包管理器全局安装typescript
npm i -g typescript
- 创建ts文件
% touch helloTS.ts
- ts文件不能直接被浏览器识别,因此先使用
tsc命令对ts文件进行编译% tsc helloTS.ts 执行完毕文件夹中生成同名js文件
2、TS类型
2.1、函数返回
: number 表示返回值类型
function sum(a: number, b: any): number {
return a + b;
}
2.2、number、string、boolean、字面量
let c:number;
let d:string;
// 赋值字面量,联合类型,只允许输入后边规定的
let e: boolean | string;
e = true;
e = '10';
e = 5 // 报错:不能将类型"5"分配给类型"string | boolean"
// 只可以赋值'male'与'female'
let f: 'male' | 'female';
f = 'male';
f = 10; // 报错:不能将类型"10"分配给类型"male | female"
2.3、any、unknown
any类型变量在给其他变量赋值时会将其也变成像any一样什么类型都能接收,(因此尽量不用);unknown只有经过类型判断或者类型断言才能给其他变量赋值
// unknown是类型安全的any,可以赋值为任意类型
// 给其他变量赋值时any会改变被赋值变量类型,但unknown会报错,除非经过类型检测或类型断言
let g: unknown;
g = true;
if(typeof g === 'boolean' || typeof g === 'string'){
e = g;
}
// 类型断言
e = g as boolean;
2.4、void、never
void返回undefined,never直接拒绝返回
function mixNum(a: string, b:boolean): never {
throw new Error();
}
2.5、object
2.5.1、对象
索引类型,约定了属性的key与value类型,具体属性名与值在调用时随意填写
// 索引类型,规定属性的key为string类型,值为unknown类型(有一个属性规定为name,值为string类型了)
let h: {name?: string, [propName: string]: unknown};
h = {name: 'lz',age: 18, isMale: true};
注意:如果将unknown换成number,则前边定义的name?:string类型不符合报错;若换成string,则因name为可选类型有可能为undefined,所以也不符合
2.5.2、函数对象
// 函数的结构: (形参:类型, 形参:类型...) => 返回值
let i: (a: number, b: number) => number;
i = function(n1: number, n2: number): number {
return 10;
}
2.5.3、& 与 |
// &:需要同时赋值
let m: {name: string} & {age: number};
m = {
name: '猪八戒',
age: 20
}
2.6、Array、元组
元组:固定长度的数组
// 普通数组
let j: Array<string>;
// 元组
let k: [string, number, boolean];
k = ['hello', 18, true];
2.7、枚举
enum Gender {
Male = 0,
Female = 1
}
// 创建对象
let l: {name: string, gender: Gender};
l = {
name: '孙悟空',
gender: Gender.Male
}
console.log(l.gender === Gender.Male);
2.8、别名
// 将取值范围1、2、3、4、5的类型取别名为myType
type myType = 1 | 2 | 3 | 4 | 5 ;
let n: myType;
n = 6; // 取值6时报错
3、编译选项
3.1、自动监测生成js文件
- 首先生成
tsconfig.json文件% tsc --init
- 执行监测所有ts文件
% tsc -w
3.2、tsconfig.json
include、exclude:指定哪些ts文件需要被编译和忽略compilerOptions:比较重要的为target(ES版本)、module(模块化规范)、outDir(编译后文件路径)、removeComments(移除注释)、noEmitOnError报错不生成编译文件)- **:表示
任意目录、*:表示任意文件
{
// 用来指定哪些ts文件需要被编译
"include": ["./**/*"],
// 指定哪些ts文件不需要编译,有默认值,偶尔使用
"exclude": ["./ts/02_basis.ts"],
"compilerOptions": {
// 指定ts被编译为的ES版本
"target": "es2016",
// 指定要使用的模块化规范
"module": "commonjs",
// 指定项目中要使用的库,默认不用使用
"lib": ["ES6", "DOM"],
// 指定编译后文件所在目录
"outDir": "./dist",
// 将代码合并为一个文件,module项只能是amd或者system
"outFile": "./dist/ts/01_helloTS.js",
/* JavaScript Support */
// 是否对JS文件进行编译,默认为false
"allowJs": false,
// 检查JS代码是否符合语法规范 /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
"checkJs": false,
// 是否移除注释 /* Specify an output folder for all emitted files. */
"removeComments": true,
// 当有错误时不生成编译文件
"noEmitOnError": true,
/* Interop Constraints */
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
/* Type Checking */
// 严格检查总开关,这个开启后剩余的严格检查都可以注释掉
"strict": true,
// 不允许隐式的any类型
"noImplicitAny": true,
// 严格检查空值
"strictNullChecks": true,
// 不允许不明确类型的this
"noImplicitThis": true,
// 指定编译后的文件是否使用严格模式
"alwaysStrict": true,
/* Completeness */
"skipLibCheck": true
}
}
4、webpack打包
4.1、配置
- 生成
package.json,里边是包的配置信息% npm init -y
- 通过npm下载4个webpage所需的包
% npm i -D webpack webpack-cli typescript ts-loader
- 创建并修改
webpack.config.js文件// 引入一个包 const path = require('path'); // webpage中所有的配置信息都要写在module.exports中 module.exports = { // 指定入口文件 entry : "./src/index.ts", // 指定打包文件所在目录 output : { // 指定打包文件路径 path: path.resolve(__dirname, 'dist'), // 打包后文件的名字 filename: "bundle.js" }, // webpack4.0对语法要求更加严格,webpack 时必须在 "开发或者生产" 中选择一种模式,否则报错 mode: 'development', module : { // 指定要加载的规则 rules: [ { // 指定规则生效的文件(正则匹配以.ts结尾的文件) test: /\.ts$/, // 要使用的loader use: 'ts-loader', // 排除node_modules文件夹 exclude: /node_modules/ } ] } } - 修改 tsconfig.json 文件,参考3.2
- 修改 package.json,增加webpack方法
{ "name": "tstest", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", // 新增build方法 "build": "webpack" }, "keywords": [], "author": "", "license": "ISC", // npm安装的4个包 "devDependencies": { "ts-loader": "^9.4.1", "typescript": "^4.8.4", "webpack": "^5.75.0", "webpack-cli": "^4.10.0" } } - 执行build方法
% npm run build
4.2、集成实用插件
4.2.1、自动生成html插件
自动生成html文件并将编译后的js文件引入
- 安装 html-webpack-plugin 插件
% npm i -D html-webpack-plugin
- 修改 webpack.config.js 文件,先引入插件,再调用
// 引入一个包 const path = require('path'); // 引入HTML插件 const HTMLWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry : "./src/index.ts", ... // 配置webpack插件 plugins : [ new HTMLWebpackPlugin({ title:"自定义html名称" // 以自定义的一个html文件为模板创建新html文件 template: "./xx/template.html" }), ] }
4.2.2、自动删除dict目录
- 安装 clean-webpack-plugin 插件
% npm i -D clean-webpack-plugin
- 修改 webpack.config.js 文件,先引入插件,再调用
// 引入一个包 const path = require('path'); // 引入HTML插件 const HTMLWebpackPlugin = require('html-webpack-plugin'); // 不是默认暴露的,加{} const { CleanWebpackPlugin } = require('clean-webpack-plugin') module.exports = { entry : "./src/index.ts", ... // 配置webpack插件 plugins : [ new CleanWebpackPlugin(), new HTMLWebpackPlugin({ title:"自定义html名称" // 以自定义的一个html文件为模板创建新html文件 template: "./xx/template.html" }), ] }
4.3、设置引用模块
- 在另一个TS文件中写入可以被其他文件引入的模块 m.ts
export const hi = '你好'; - 在index.ts文件中引入
import { hi } from "./m"; - 此时运行会报
Module not found的错 - 在 webpack.config.js 文件中增加
resolve配置module.exports = { ... // 用来设置引用模块 resolve: { extensions: ['.ts', '.js'] } } - 再次运行即可正常
4.4、babel
兼容旧版本的代码,将新语法按照功能等价,转换成旧语法
-
安装babel插件
% npm i -D @babel/core @babel/preset-env babel-loader core-js
// babel核心库 @babel/core // babel设置兼容不同浏览器环境 @babel/preset-env // 将babel与webpack进行结合 babel-loader // 模拟JS运行环境,让老版本浏览器体验新版本的技术 core-js -
修改 webpack配置
// 引入一个包 const path = require('path'); // 引入HTML插件 const HTMLWebpackPlugin = require('html-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin') // webpage中所有的配置信息都要写在module.exports中 module.exports = { // 指定入口文件 entry : "./src/index.ts", output : { // 指定打包文件路径 path: path.resolve(__dirname, 'dist'), // 打包后文件的名字 filename: "bundle.js", // 修改1: 告诉webpack不使用箭头函数 environment: { arrowFunction : false } }, mode: 'development', module : { // 指定要加载的规则 rules: [ { // 指定规则生效的文件(正则匹配以.ts结尾的文件) test: /\.ts$/, // 修改2: 要使用的loader use: [ { // 指定加载器 loader: "babel-loader", // 设置babel options: { // 设置预定义的环境 presets: [ [ // 指定环境的插件 "@babel/preset-env", // 配置信息 { // 要兼容的目标浏览器,谷歌浏览器 --> 帮助 --> 关于 可查看 targets: { "chrome" : "107", "ie" : "11" }, // 指定corejs版本,与package.json中corejs版本号有关 "corejs":"3", // 使用corejs的方式, usage为按需加载 "useBuiltIns":"usage" } ] ] } }, // 两个loader,写到后边的先执行,先将ts代码转为js,再由新版js转为旧版js 'ts-loader' ], // 排除node_modules文件夹 exclude: /node_modules/ } ] }, // 配置webpack插件 plugins : [ new CleanWebpackPlugin(), new HTMLWebpackPlugin({ // title:"自定义html名称" // template: "./dist/index.html" }), ], // 用来设置引用模块 resolve: { extensions: ['.ts', '.js'] } }修改1:output 内增加 environment: { arrowFunction : false },输出文件不使用箭头函数
修改2:module --> rules --> use 内改为使用的 loader数组,且
写到后边的先执行,先将ts代码转为js,再由新版js转为旧版js;其中可以配置环境插件的兼容浏览器、corejs版本
4.5、less
- 安装 less 插件,以及
postcss兼容插件(类似babel)npm i -D less less-loader style-loader css-loader postcss postcss-loader postcss-preset-env
- 修改webpack.config.js文件
module.exports = { ...... module : { // 指定要加载的规则 rules: [ { ...... } // 设置less文件的处理 { test: /\.less$/, use: [ "style-loader", "css-loader", // 引入postcss,做兼容 { // 指定加载器 loader: "postcss-loader", options: { postcssOptions: { // 此处写成plugins会报错 plugin: [ // 指定环境的插件 "postcss-preset-env", { // 2个最新版本的浏览器 browser: 'last 2 versions' } ] } } }, "less-loader" ] } ] }, ...... } - 创建 index.less 文件
body { background-color: #bbb; display: flex; } - 在 index.ts 文件中引入
import './style/index.less';
5、类、对象
-
类可以定义
属性、方法与构造函数:constructor,属性分为 实例属性(用new出的对象调用)与 类属性(类直接调用),实例方法与类方法与之类似 -
类被继承,如果构造函数 constructor 不重写则系统默认调用super构造函数,如果重写则必须对构造函数进行实现:
constructor()改为super() -
实例方法中,this表示当前被调用的这个实例(可能new了一堆的实例);但在 类方法中this表示当前类;箭头函数中还可能会表示成Windows -
使用关键字
extends进行继承
5.1、抽象类、抽象方法
- 使用关键字
abstract - 抽象类:专门用来被继承的,
被禁止用于创建对象 - 抽象方法:专门用来被继承的,
被禁止添加具体实现
// 抽象类,专门用来被继承,被禁止用于创建对象
abstract class Animal {
name: string;
// 实例属性
age: number;
// 类属性、静态属性,通过类直接调用,设置了只读属性
static readonly country: string = 'China';
// 构造函数
constructor(name: string, age: number) {
// 在实例方法中,this表示当前被使用的实例;类方法中可不是
this.name = name;
this.age = age;
}
// 实例方法
run() {
console.log(`${this.name} is run`);
}
// 类方法
static bark() {
console.log(`${this.country}在叫`);
}
// 抽象方法
abstract play():void;
}
// 继承抽象类
class Cat extends Animal {
sex: string;
// 如果重写了constructor方法就必须调用父类的构造函数
constructor(name: string, age: number, sex: string) {
super(name, age);
this.sex = sex;
}
run(): void {
super.run();
console.log('jump');
}
play(): void {
console.log('play');
}
}
const cat = new Cat('小白', 18, '男');
console.log(Cat.country , cat.age);
Cat.bark();
cat.run();
5.2、接口:interface
-
使用关键字
interface定义 -
使用关键字
implements实现接口内容 -
用于定义一个标准,让某个类去符合这个标准
-
接口与抽象类很相似,都是通过 被其他类继承 / 实现来完成功能,不同是 抽象类中可以有析构函数、抽象的和非抽象的内容,而
接口中只定义对象结构,属性不能有值,方法不能有实现;所有方法都是抽象方法
// 描述一个对象的类型,与接口结构相似
type myType = {
name: string,
age: number
};
// 接口用来定义一个类结构,同时也能当做类型声明去使用
// 接口中只定义对象结构,属性不能有值,方法不能有实现;所有方法都是抽象方法
interface myInterface {
name: string;
age: number;
}
// 同名接口内容会进行合并扩展
interface myInterface {
sex: string;
run(): void;
}
// 实现接口
class MyClass implements myInterface {
name: string;
age: number;
sex: string;
constructor(name: string, age: number, sex: string) {
this.name = name;
this.age = age;
this.sex = sex;
}
run():void {
console.log(`${this.name} is running`);
}
}
6、属性
权限关键字:
public:任意位置 访问修改默认值protected:只能在 当前类及其子类 中访问private:只能在 当前类内部 进行访问修改;通过类中添加方法使私有属性被外界访问
class Person {
// 任意位置访问修改默认值
public _name:string;
// 只能在当前类内部进行访问修改;通过类中添加方法使私有属性被外界访问
private _age:number;
// 只能在当前类及其子类中访问
protected _sex:string;
constructor(name: string, age: number){
this._name = name;
this._age = age;
}
getAge() {
return this._age;
}
// 自定义set方法修改私有属性
setAge(newValue: number) {
if (newValue >= 0 ) {
this._age = newValue;
}
}
}
const per = new Person('lz', 18);
per.setAge(20);
7、泛型
在定义函数或类时,如果遇到类型不明确的就可以使用泛型
function fn<T, K>(a: T, b:K): T{
return a;
}
// 推断泛型
let result = fn('lz', 18);
// 指定泛型
let result2 = fn<string, number>('lz', 18);
// 约束泛型范围
interface Inter {
length: number;
}
// 规定泛型K必须是接口Inter的实现类,用extends
function fn2<T, K extends Inter>(a: T, b:K): number{
return b.length;
}
class AA implements Inter {
length: number = 18;
}
const aa = new AA();
// 此时传的就不能是number而是实现了Infer接口的类
let result3 = fn<string, Inter>('lz', aa);
-
泛型与Any有些类似,但同时用Any作为形参类型与返回值类型,这两者可能是不同类型,但用泛型则肯定是 同一类型 只是不知道具体是哪种类型
-
调用时可以指定泛型类型
-
可以通过继承interface或者类来约束泛型范围,但 传入的实参就需要是实现了Infer接口的类了(注:
这里用 interface 进行约束也要用 extends 而非 implements)