TypeScript --- 基础
1. 简述
以 JavaScript 为基础构建的语言, 扩展并添加类型, 可以在任何支持 JavaScript 的平台中执行, TypeScript 不能被 JS解析器 直接执行, 需要编译成 JS,然后再运行
2. 环境搭建
1. Node.js
2. TypeScript
npm i -g typescript
3. 开发环境配置
1. 编译配置
1. 自动编译
1. 自动编译文件
# -w 会自动监视文件的变化,并在文件发生变化,并保存时对文件自动重新编译
tsc main.js -w
2. 自动编译项目
如果直接使用 tsc 命令, 可以自动的将当前项目下的所有 ts 文件编译为 js 文件, 但是需要在根目录下创建一个 ts 的配置文件 tsconfig.json
{
"include": [ // 需要编译的文件
"src/**/*",
"tests/**/*"
],
"exclude": [], // 不需要编译的文件
"extends": [], // 集成的配置文件 / 配置文件们
"files": [
"src/main.ts" // 指定需要被编译的文件, 一般不会用这个
],
}
执行监听命令
tsc -w
2. 编辑器配置
tsconfig.json
{
"include": [ // 需要编译的文件
"src/**/*",
"tests/**/*"
],
"compilerOptions": { // 编译器的选项
"target": "ES6", // 编译成对应的 ES 的版本, 可选值: ES3(默认值)、ES5 ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
// "lib": [], // 指定代码运行时所包含的库(宿主环境), 一般不改,可选值: ES5 ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost....
"module": "system", // 指定需要使用的模块化规范, 可选项: 'none', 'commonjs', 'amd', 'system', 'umd', es6/es2015, 'es2020', 'es2022', 'esnext', 'node16', 'nodenext', 'preserve'
"outDir": "./dist", // 指定编译后的文件存储位置
"outFile": "./dist/app.js", // 将所有js代码合并为一个文件, 必须指定 module 为 amd 或 system, 一般不用, 会使用打包工具来实现这个功能
"strict": true, // 所有严格检查的总开关,如果为true, 下面一些配置项可以不用配置
"allowJs": false, // 是否同时对 js 文件也进行编译, 一般用来将第三方的js文件一起编译
"checkJs": false, // 是否开启 检查 js 代码是否符合 ts 规范
"removeComments": true, // 是否移除注释
"noEmit": false, // 是否生成编译后的文件, 一般用于检查代码是否符合 ts 规范, 而不编译文件
"noEmitOnError": true, // 当代码发生错误时, 是否不生成编译文件
"alwaysStrict": true, // 是否设置编译后的文件开启严格模式
"noImplicitAny": true, // 是否关闭未指定的类型自动指定为any
"noImplicitThis": true, // 是否关闭使用不明确类型的this
"strictNullChecks": true, // 是否严格检查空值
}
}
2. 整合 webpack
1. 初始化
在项目根目录下生成 package.json 文件
npm init -y
2. 环境安装
cnpm i -D webpack webpack-cli typescript ts-loader html-webpack-plugin webpack-dev-server clean-webpack-plugin
3. 配置 webpack
项目根目录下创建 src/index.ts
function sum(a: number, b: number): number {
return a + b;
}
console.log(sum(2, 3));
项目根目录下创建 webpack.config.js
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
// 指定入口文件
entry: "./src/index.ts",
// 打包配置
output: {
// 指定打包后的文件所在目录
path: path.resolve(__dirname, "./dist"),
// 打包后的文件名
filename: "bundle.js",
},
// 指定 webpack 打包时要使用的模块
module: {
// 指定加载的规则
rules: [
{
// test 指定的是规则生效的文件, 正则表达式
test: /\.ts$/,
// 要使用的 loader
use: "ts-loader",
// 要排除的文件
exclude: /node_modules/,
}
]
},
// 配置 webpack 插件
plugins: [
new HTMLWebpackPlugin({
// 设置模版路径
template: path.resolve(__dirname, "./src/index.html"),
title: "自定的 title"
}), // webpack 管理 html 页面的插件
new CleanWebpackPlugin(), // 每次打包前先清除 dist 文件夹下的所有打包文件
],
// 用来配置引用模块, 哪些模块可以作为模块使用
resolve: {
extensions: [".ts", ".js"]
}
}
4. 指定 ts 的编辑规范
根目录下创建 tsconfig.json
{
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true
}
}
5. 添加自定义命令
pageage.json 文件的 scripts 配置项中添加 build start 自定义命令
{
"scripts": {
"build": "webpack", // 打包命令
"start": "webpack server --open chrome.exe" // 代码热修改
},
}
6. 执行命令打包
npm run build
npm run start
7. 配置自动生成 HTML
8. 配置 热更新 服务
9. 低版本兼容插件
1. 模块下载
cnpm i -D @babel/core @babel/preset-env babel-loader core-js
2. 配置
webpack.config.js
module.exports = {
// 指定 webpack 打包时要使用的模块
module: {
output: {
// 配置打包环境
environment: {
arrowFunction: false, // 指定不用箭头函数
const: false // 指定不使用 const 声明变量
}
},
// 指定加载的规则
rules: [
{
test: /\.ts$/,
// 要使用的 loader
use: [{
// 指定加载器
loader: "babel-loader",
// 设置 babel
options: {
presets: [
[
"@babel/preset-env", // 指定环境插件
// 配置信息
{
targets: {
"chrome": "88", // 要兼容的目标浏览器
"ie": "11"
},
"corejs": "3", // 指定 core.js 的版本
"useBuiltIns": "usage", // 使用 core.js 的方式, usage 表示按需加载
}
]
],
}
}, "ts-loader"],
// 要排除的文件
exclude: /node_modules/,
}
]
},
}
3. 整合 less / sass
1. 下载模块
npm i -D less less-loader css-loader style-loader
npm i -D sass sass-loader css-loader style-loader
2. 配置
webpack.config.js
module.exports = {
module: {
// 指定加载的规则
rules: [
// 添加关于处理 less / sass 的处理规则
{
test: /.less$/,
use: [
"style-loader",
"css-loader",
"less-loader" // loader 是从下往上执行的
]
}
]
},
}
3. 低版本兼容插件
npm i -D postcss postcss-loader postcss-preset-env
webpack.config.js
module.exports = {
module: {
// 指定加载的规则
rules: [
// 添加关于处理 less / sass 的处理规则
{
test: /.less$/,
use: [
"style-loader",
"css-loader",
// 引入 postcss 并配置
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{
browsers: "last 2 versions" // 兼容最近两个版本的浏览器
}
]
]
}
}
},
"less-loader" // loader 是从下往上执行的
]
}
]
},
}
4. hello world
main.ts
console.log("hello ts")
编译
tsc main.ts
5. 数据类型
1.类型声明
在 TS 中 类型声明是一个非常重要的特点, 可以通过类型声明指定 TS 中变量(参数、形参)的类型, 指定类型后,当为变量赋值时, TS 编辑器会自动检查值是否符合类型声明, 符合则赋值, 否则报错, 简而言之类型声明给变量设置了类型, 使得变量只能存储某种类型的值
1. 变量
先声明再赋值
let userName: string
userName = "小明"
userName = 0 // 此行代码会报错, 因为 userName 的类型是 string 无法使用 number 进行赋值
声明的同时赋值
let userName: string = "小明" // 声明变量的类型
let userAddress = "北京市" // 如果变量的声明和赋值时同时进行的, TS 会自动检测变量的类型
userAddress = 0 // 此行代码会报错, 因为 userName 的类型是 string 无法使用 number 进行赋值
2. 函数
function sum(a: number, b: number): number {
return a + b
}
sum(1, 2)
2. number
任意数字
3. string
任意字符串
4. boolean
布尔值 true 或 false
5. 字面量
限制变量的值就是该字面量的值
let s1: "male" | "female" // 可以使用 | 来连接多个类型
s1 = "male"
s1 = "female"
s1 = "hello" // s1 只能 "male" 或 "female"
let c: boolean | string // 联合类型
c = true
c = "hello"
c = 10 // c 只能是 布尔值 或 字符串
6. any(不推荐)
任意类型
let a: any
let b // 声明变量, 如果不指定类型, TS 解析器会自动给该变量指定为 any 类型
a = 10
a = "hello"
a = true
7. unknown(推荐)
类型安全的 any, 在变量的类型不确定的时候使用
let a: unknown
a = 10
a = "hello"
a = true
let d
let c: string
c = d // 不会报错, any类型可以赋值给任意类型
c = a // 会报错, unknown 类型不可以赋值给其他类型的数据
// 类型断言, 当 a 的类型是 string 时, 才会赋值给c
c = a as string
c = <string>s
8. void
没有值(或 undefined)
// 没有返回值, 默认是void
function fn():void {
console.log(1)
}
9. never
不返回任何值
function fn():never {
throw new Error("报错了")
}
10. object
任意对象, 但是 JS 中一切皆对象, 所以需要变换使用方法
let j: {name: string} & { age: number}
j = {name: "小明", age: 18}
function fn(): { name: string } {
return {
name: "小明"
}
}
function fn(): { name: string } {
return {
name: "小明",
age: 10 // 报错
}
}
// name 是必选项
// age后加了?,则表示age是可选项
function fn(): { name: string, age?: number } {
return {
name: "小明",
age: 10
}
}
// name 是必选项
// 其他都是必选项
function fn(): { name: string, [propName: string]:unknown } {
return {
name: "小明",
age: 10,
address: "北京市",
hobby: {
hobby1: "篮球"
}
}
}
// 限制返回值必须是一个对应类型的函数
function fn(): (a: number, b: number) => number {
let a = 1
let b = 2
return function (a, b) {
return a + b
}
}
11. array
任意数组
let a: string[] // 字符串数组
let b: number[] // 数值类型数组
let c: Array<number> // 数值类型数组
let d: { [propName: string]: unknown }[] // 任意对象类型数组
d = [{
name: "小明",
age: 10
}]
12. tuple
固定长度的数组
let t: [number,number]
t = [1,2]
t = [1,2,3] // 报错, 长度必须为2
13. enum
枚举类型
// 声明枚举
enum Gender {
"Male",
"Female"
}
let u: { name: string, gender: Gender }
u = {
name: "小明",
gender: Gender.Male
}
if (u.gender === Gender.Male){
console.log(1)
}
14. 类型别名
type o_t_t = 1 | 2 | 3
let a: o_t_t
let b: o_t_t
6. 面向对象
1. 类( class )
定义规则
class 类名 {
属性名: 类型;
// 构造函数
constructor(参数: 类型) {
this.属性名 = 参数
}
方法名() {
}
}
**示例: **
class Person {
// 实例属性
name: string;
age: number;
// 类属性 (静态属性), 只能通过 Person.len 来访问
static len: number = 18;
// 只读实例属性
readonly hobby: string = "篮球"
// 只读类属性
static readonly money: number = 18000
// 构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 实例方法
sayHello() {
return `${this.name} say Hello!`;
}
// 类方法
static sayHi() {
return `Person sayHi!`;
}
}
const p1 = new Person("小明", 18)
// 打印实例属性
console.log(p1.name, p1.age)
// 调用实例方法
console.log(p1.sayHello());
// 调用类属性
console.log(Person.len)
// 调用类方法
console.log(Person.sayHi)
编译
tsc index.ts
2. 属性
1. 公共属性
class Person {
// public 关键字 定义的属性或方法, 可以在任意位置访问, 默认 age 就是公共属性
public name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
const p = new Person("孙悟空", 18)
console.log(p)
// 属性是在对象中设置的, 所以属性是可以被任何的修改的
// 属性可以被修改, 会导致对象中的数据变得非常不安全
p.name = "猪八戒"
p.age = -22 // 年龄不可能会是负数
console.log(p)
上面的简写方式: 构造函数中声明公共属性
class Person {
// 不用再用 this.name = name 赋值了, 内部自动完成
constructor(public name: string, public age: number) {
}
}
const p = new Person("孙悟空", 18)
console.log(p)
// 属性是在对象中设置的, 所以属性是可以被任何的修改的
// 属性可以被修改, 会导致对象中的数据变得非常不安全
p.name = "猪八戒"
p.age = -22 // 年龄不可能会是负数
console.log(p)
2. 私有属性
class Person {
// 使用 private 关键字声明的属性 只可以被当前类的内部访问
// 一般使用 _ 来表示私有属性
private _name: string
// 使用 private 关键字声明的属性 只可以被 当前类 及其子类 的内部访问
protected _age: number
constructor(name: string, age: number) {
this._name = name
this._age = age
}
getAge(): number {
return this._age
}
setAge(num: number): void {
// 可以在逻辑中控制 age 的合法性
if (num <= 0) return
this._age = num
}
}
const p = new Person("孙悟空", 18)
// 外部无法通过 _name 或 _age 来修改私有属性
p._name = "猪八戒"
// 调用类的内部方法, 修改私有属性
p.getName()
p.setAge(20)
console.log(p)
**注意: **
TS 中有这个语法, 但是编译成 JS 后仍然会被修改, 是因为 JS 不支持私有属性, 需要修改 tsconfig.json 的配置
{
"compilerOptions": {
"noEmitOnError": true // 确保当 TS 语法有错误时, 不会编译成 JS 文件
}
}
3. getter 和 setter
class Person {
private _name: string;
private _age: number;
constructor(name: string, age: number) {
this._name = name;
this._age = age;
}
// 设置 getter
get name() {
return this._name;
}
// 设置 setter
set name(name: string) {
this._name = name;
}
}
const person = new Person("小明", 18)
// 读 name, 自动执行 getter
console.log(person.name);
// 设置 name 自动执行 setter
person.name = "孙悟空"
3. 继承
1. 未使用继承
class Dog {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log("汪汪汪!")
}
}
class Cat {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log("喵喵喵!")
}
}
const dog = new Dog("旺财", 3)
dog.sayHello()
const cat = new Cat("小白", 2)
cat.sayHello()
编译
tsc index.ts
2. 使用继承
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello(): void {
console.log('动物在叫')
}
}
// 使用 关键字 extends 来继承 Animal 父类
class Dog extends Animal {
// Dog 独有的方法
run() {
console.log(`${this.name} 在跑`)
}
// 父类方法的重写
sayHello(helloStr: string): void {
console.log(`${this.name} ${this.age} 岁,它在 ${helloStr}`)
}
}
class Cat extends Animal {
}
const dog = new Dog("旺财", 3)
dog.sayHello("汪汪汪!")
const cat = new Cat("小白", 2)
cat.sayHello("喵喵喵!")
编译
tsc index.ts
4. super 关键字
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello(): void {
console.log('动物在叫')
}
}
class Dog extends Animal {
run() {
console.log(`${this.name} 在跑`)
}
sayHello(helloStr: string): void {
console.log(`${this.name} ${this.age} 岁,它在 ${helloStr}`)
// 调用父类的 sayHello()
super.sayHello()
}
}
class Cat extends Animal {
hobby: string;
// 如果子类中定义了 constructor 构造函数, 必须手动调用父类的构造函数
constructor(name: string, age: number, hobby: string) {
super(name, age);
this.hobby = hobby
}
}
const dog = new Dog("旺财", 3)
dog.sayHello("汪汪汪!")
const cat = new Cat("小白", 2, "球球")
cat.sayHello()
5. 抽象类
// 使用关键字 abstract 声明的类,就是抽象类, 用来限制父类无法被单独实例化
// 抽象类的作用就是用来被别的子类继承的
abstract class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 通用方法, 在抽象类中是无意义的
sayHello(): void {
console.log('动物在叫')
}
// 使用 abstract 关键字定义的方法, 就是抽象方法
// 抽象方法没有方法体, 只能定义在抽象类中, 子类必须对父类的抽象方法进行重写
abstract sayHi(): void
}
class Cat extends Animal {
sayHello(): void {
console.log('小猫在喵喵喵')
}
// 子类必须对父类的抽象方法进行重写
sayHi(): void{
console.log("小猫说 Hi")
}
}
const cat = new Cat("小白", 2)
cat.sayHello()
7. 接口
1. 定义
// 描述一个对象的类型
type myType = {
name: string,
age: number
}
const obj: myType = {
name: "小明",
age: 18
}
使用接口实现
// 定义一个接口, 用来定义一个类中, 包含哪些必须定义的属性和方法
interface myInterface {
name: string
age: number
}
// 可以重复声明两个相同名字的 interface
interface myInterface {
name: string
age: number
}
const objI: myInterface = { // 必须实现 myInterface 中声明的所有属性和方法
name: "小明",
age: 18,
hobby: "篮球"
}
使用接口来限制类的结构
interface myInterface {
name: string
sayHello(): void
}
// 定义类来实现接口, 也就是使类满足接口提前定义好的要求
class Animal implements myInterface {
name: string
// 构造函数不被限制
constructor(name: string) {
this.name = name
}
sayHello() {
console.log("hello")
}
}
8. 泛型
在定义函数或类时, 如果遇到类型不明确时, 就可以使用泛型
// <T> 声明了 T 就是泛型
function fn<T>(a: T): T {
return a
}
// 不指定类型, TS 可以自动对类型进行推断
fn(10)
//指定泛型, T 就是 string 类型
fn<string>("hello")
指定多个泛型
// <T> 声明了 T 就是泛型
function fn<T, K>(a: T, b: K): T {
console.log(b)
return a
}
//指定泛型, T 就是 string 类型
fn<number, string>(10, "hello")
指定泛型必须实现某个接口
interface Inter{
length: number
}
// T 泛型, 必须实现了 length 这个接口
function fn<T extends Inter>(a: T): number {
return a.length
}
fn("hello")
fn(20)
fn({length: 20})
定义类的时候指定泛型
class Person<T> {
constructor(public firstName: T, public lastName: T) {
}
}
const p = new Person<string>("小", "明")

浙公网安备 33010602011771号