zxpnet网站 zxpnet网站
首页
前端
后端服务器
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

zxpnet

一个爱学习的java开发攻城狮
首页
前端
后端服务器
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 大前端课程视频归档
  • html

  • js

  • 前端框架

  • 自动化构建

  • typescript

    • typescript快速入门
    • typescript面向对象
    • typescript语法精讲
      • JavaScript一门优秀的语言
        • 类型带来的问题
        • 类型错误
        • 类型思维的缺失
        • JavaScript添加类型约束
        • 大前端的发展趋势
      • 认识TypeScript
        • TypeScript的特点
        • TypeScript的编译环境
        • TypeScript的运行环境
        • 变量的声明
      • JS和TS的数据类型
        • 1、js类型:number类型
        • 2、js类型: boolean布尔类型
        • 3、js类型:string类型
        • 4、js类型:Array类型
        • 5、js类型:object类型
        • 6、js类型:Symbol符号类型
        • 7、js类型:null和undefined类型
        • 8、ts类型:any类型
        • 9、ts类型:unknown类型
        • 10、ts类型:void类型
        • 11、ts类型:never类型
        • 12、ts类型:tuple类型
      • 函数的参数类型
        • 函数的返回值类型
        • 匿名函数的参数
        • 对象类型
        • 可选类型
        • 联合类型
        • 使用联合类型
        • 可选类型补充
        • 类型别名type
        • 类型断言as
        • 非空类型断言!
        • 可选链的使用
        • ??和!!的作用
        • 字面量类型literal types
        • 字面量推理
        • 类型缩小
      • TypeScript函数类型
        • TypeScript函数类型解析
        • 参数的可选类型
        • 默认参数
        • 剩余参数
        • 可推导的this类型
        • 不确定的this类型
        • 指定this的类型
        • 函数的重载
        • 联合类型和重载
      • 认识类的使用
        • 类的定义
        • 类的继承
        • 多态
        • 类的成员修饰符
        • 只读属性readonly
        • getters/setters
        • 静态成员
        • 抽象类abstract
        • 类的类型
      • 接口的声明
        • 索引类型
        • 函数类型
        • 接口继承
        • 接口的实现
        • interface和type区别
        • 字面量赋值
      • TypeScript枚举类型
        • 枚举类型的值
      • 认识泛型
        • 泛型实现类型参数化
        • 泛型的基本补充
        • 泛型接口
        • 泛型类
        • 泛型约束
      • 模块化开发
        • 命名空间namespace
        • 类型的查找
        • 内置类型声明
        • 外部定义类型声明和自定义声明
        • 声明变量-函数-类
        • 声明模块
        • declare文件
        • declare命名空间
      • tsconfig.json文件
      • 常用函数
        • InstanceType
  • es6

  • bootstrap

  • layer

  • vue

  • vue3

  • vuepress

  • hexo博客

  • 文档

  • biz业务

  • frontend
  • typescript
shollin
2022-03-04
目录

typescript语法精讲

  • JavaScript一门优秀的语言
    • 类型带来的问题
    • 类型错误
    • 类型思维的缺失
    • JavaScript添加类型约束
    • 大前端的发展趋势
  • 认识TypeScript
    • TypeScript的特点
    • TypeScript的编译环境
    • TypeScript的运行环境
    • 变量的声明
  • JS和TS的数据类型
    • 1、js类型:number类型
    • 2、js类型: boolean布尔类型
    • 3、js类型:string类型
    • 4、js类型:Array类型
    • 5、js类型:object类型
    • 6、js类型:Symbol符号类型
    • 7、js类型:null和undefined类型
    • 8、ts类型:any类型
    • 9、ts类型:unknown类型
    • 10、ts类型:void类型
    • 11、ts类型:never类型
    • 12、ts类型:tuple类型
  • 函数的参数类型
    • 函数的返回值类型
    • 匿名函数的参数
    • 对象类型
    • 可选类型
    • 联合类型
    • 可选类型补充
    • 类型别名type
    • 类型断言as
    • 可选链的使用
    • ??和!!的作用
    • 字面量类型literal types
    • 字面量推理
    • 类型缩小
  • TypeScript函数类型
    • TypeScript函数类型解析
    • 参数的可选类型
    • 默认参数
    • 剩余参数
    • 可推导的this类型
    • 不确定的this类型
    • 指定this的类型
    • 函数的重载
    • 联合类型和重载
  • 认识类的使用
    • 类的定义
    • 类的继承
    • 多态
    • 类的成员修饰符
    • 抽象类abstract
    • 类的类型
  • 接口的声明
    • 索引类型
    • 函数类型
    • 接口继承
    • 接口的实现
    • interface和type区别
    • 字面量赋值
  • TypeScript枚举类型
    • 枚举类型的值
  • 认识泛型
    • 泛型实现类型参数化
    • 泛型的基本补充
    • 泛型接口
    • 泛型类
    • 泛型约束
  • 模块化开发
    • 命名空间namespace
    • 类型的查找
    • 声明变量-函数-类
    • 声明模块
    • declare文件
    • declare命名空间
  • tsconfig.json文件
  • 常用函数
    • InstanceType

# JavaScript一门优秀的语言

1、我始终相信:任何新技术的出现都是为了解决原有技术的某个痛点。

2、JavaScript是一门优秀的编程语言吗?

每个人可能观点并不完全一致,但是从很多角度来看,JavaScript是一门非常优秀的编程语言; 而且,可以说在很长一段时间内这个语言不会被代替,并且会在更多的领域被大家广泛使用;

3、著名的Atwood定律:

Stack Overflow的创立者之一的 Jeff Atwood 在2007年提出了著名的 Atwood定律。

any application that can be written in JavaScript, will eventually be written in JavaScript.

任何可以使用JavaScript来实现的应用都最终都会使用JavaScript实现。

其实我们已经看到了,这句话正在一步步被应验:

Web端的开发我们一直都是使用JavaScript;

  • 移动端开发可以借助于ReactNative、Weex、Uniapp等框架实现跨平台开发;

  • 小程序端的开发也是离不开JavaScript;

  • 桌面端应用程序我们可以借助于Electron来开发;

  • 服务器端开发可以借助于Node环境使用JavaScript来开发。

JavaScript一门优秀的语言

并且随着近几年前端领域的快速发展,让JavaScript迅速被普及和受广大开发者的喜爱,借助于JavaScript本身的强大,也让使用JavaScript开发的人员越来越多。

优秀的JavaScript没有缺点吗?

p其实上由于各种历史因素,JavaScript语言本身存在很多的缺点;

  • 比如ES5以及之前的使用的var关键字关于作用域的问题;

  • 比如最初JavaScript设计的数组类型并不是连续的内存空间;

  • 比如直到今天JavaScript也没有加入类型检测这一机制;

JavaScript正在慢慢变好

  • 不可否认的是,JavaScript正在慢慢变得越来越好,无论是从底层设计还是应用层面。

  • ES6、7、8等的推出,每次都会让这门语言更加现代、更加安全、更加方便。

  • 但是知道今天,JavaScript在类型检测上依然是毫无进展(为什么类型检测如此重要,我后面会聊到)

# 类型带来的问题

首先你需要知道,编程开发中我们有一个共识:错误出现的越早越好

  • 能在写代码的时候发现错误,就不要在代码编译时再发现(IDE的优势就是在代码编写过程中帮助我们发现错误)。

  • 能在代码编译期间发现错误,就不要在代码运行期间再发现(类型检测就可以很好的帮助我们做到这一点)。

  • 能在开发阶段发现错误,就不要在测试期间发现错误,能在测试期间发现错误,就不要在上线后发现错误。

现在我们想探究的就是如何在 代码编译期间 发现代码的错误:

  • JavaScript可以做到吗?不可以,我们来看下面这段经常可能出现的代码问题。

# 类型错误

这是我们一个非常常见的错误:

  • 这个错误很大的原因就是因为JavaScript没有对我们传入的参数进行任何的限制,只能等到运行期间才发现这个错误;

  • 并且当这个错误产生时,会影响后续代码的继续执行,也就是整个项目都因为一个小小的错误而深入崩溃;

当然,你可能会想:我怎么可能犯这样低级的错误呢?

  • 当我们写像我们上面这样的简单的demo时,这样的错误很容易避免,并且当出现错误时,也很容易检查出来;

  • 但是当我们开发一个大型项目时呢?你能保证自己一定不会出现这样的问题吗?而且如果我们是调用别人的类库,又如何知道让我们传入的到底是什么样的参数呢?

n 但是,如果我们可以给JavaScript加上很多限制,在开发中就可以很好的避免这样的问题了:

  • 比如我们的getLength函数中str是一个必传的类型,没有调用者没有传编译期间就会报错;

  • 比如我们要求它的必须是一个String类型,传入其他类型就直接报错;

  • 那么就可以知道很多的错误问题在编译期间就被发现,而不是等到运行时再去发现和修改;

# 类型思维的缺失

我们已经简单体会到没有类型检查带来的一些问题,JavaScript因为从设计之初就没有考虑类型的约束问题,所以造成了前端开发人员关于类型思维的缺失:

  • 前端开发人员通常不关心变量或者参数是什么类型的,如果在必须确定类型时,我们往往需要使用各种判断验证;

从其他方向转到前端的人员,也会因为没有类型约束,而总是担心自己的代码不安全,不够健壮;

所以我们经常会说JavaScript不适合开发大型项目,因为当项目一旦庞大起来,这种宽松的类型约束会带来非常多的安全隐患,多人员开发它们之间也没有良好的类型契约。

  • 比如当我们去实现一个核心类库时,如果没有类型约束,那么需要对别人传入的参数进行各种验证来保证我们代码的健壮性;

  • 比如我们去调用别人的函数,对方没有对函数进行任何的注释,我们只能去看里面的逻辑来理解这个函数需要传入什么参数,返回值是什么类型;

# JavaScript添加类型约束

为了弥补JavaScript类型约束上的缺陷,增加类型约束,很多公司推出了自己的方案:

  • 2014年,Facebook推出了flow来对JavaScript进行类型检查; 同年,Microsoft微软也推出了TypeScript1.0版本;

他们都致力于为JavaScript提供类型检查;

n 而现在,无疑TypeScript已经完全胜出:

  • Vue2.x的时候采用的就是flow来做类型检查;

  • Vue3.x已经全线转向TypeScript,98.3%使用TypeScript进行了重构;

  • 而Angular在很早期就使用TypeScript进行了项目重构并且需要使用TypeScript来进行开发;

  • 而甚至Facebook公司一些自己的产品也在使用TypeScript;

学习TypeScript不仅仅可以为我们的代码增加类型约束,而且可以培养我们前端程序员具备类型思维

# 大前端的发展趋势

大前端是一群最能或者说最需要折腾的开发者:

  • 客户端开发者:从Android到iOS,或者从iOS到Android,到RN,甚至现在越来越多的客户端开发者接触前端相关知识(Vue、React、Angular、小程序);

  • 前端开发者:从jQuery到AngularJS,到三大框架并行:Vue、React、Angular,还有小程序,甚至现在也要接触客户端开发(比如RN、Flutter);

  • 目前又面临着不仅仅学习ES的特性,还要学习TypeScript;

  • 新框架的出现,我们又需要学习新框架的特性,比如vue3.x、react18等等;

但是每一样技术的出现都会让惊喜,因为他必然是解决了之前技术的某一个痛点的,而TypeScript真是解决了JavaScript存在的很多设计缺陷,尤其是关于类型检测的。

并且从开发者长远的角度来看,学习TypeScript有助于我们前端程序员培养类型思维,这种思维方式对于完成大型项目尤为重要。

# 认识TypeScript

虽然我们已经知道TypeScript是干什么的了,也知道它解决了什么样的问题,但是我们还是需要全面的来认识一下TypeScript到底是什么?

我们来看一下TypeScript在GitHub和官方上对自己的定义:

  • GitHub说法:TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TypeScript官网:TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.

翻译一下:TypeScript是拥有类型的JavaScript超集,它可以编译成普通、干净、完整的JavaScript代码。

怎么理解上面的话呢?

  • 我们可以将TypeScript理解成加强版的JavaScript。

  • JavaScript所拥有的特性,TypeScript全部都是支持的,并且它紧随ECMAScript的标准,所以ES6、ES7、ES8等新语法标准,它都是

支持的;

  • 并且在语言层面上,不仅仅增加了类型约束,而且包括一些语法的扩展,比如枚举类型(Enum)、元组类型(Tuple)等;

  • TypeScript在实现新特性的同时,总是保持和ES标准的同步甚至是领先;

  • 并且TypeScript最终会被编译成JavaScript代码,所以你并不需要担心它的兼容性问题,在编译时也不需要借助于Babel这样的工具;

  • 所以,我们可以把TypeScript理解成更加强大的JavaScript,不仅让JavaScript更加安全,而且给它带来了诸多好用的好用特性;

# TypeScript的特点

官方对TypeScript有几段特点的描述,我觉得非常到位(虽然有些官方,了解一下),我们一起来分享一下:

始于JavaScript,归于JavaScript

  • TypeScript从今天数以百万计的JavaScript开发者所熟悉的语法和语义开始。使用现有的JavaScript代码,包括流行的JavaScript库,

并从JavaScript代码中调用TypeScript代码;

  • TypeScript可以编译出纯净、 简洁的JavaScript代码,并且可以运行在任何浏览器上、Node.js环境中和任何支持ECMAScript 3(或

更高版本)的JavaScript引擎中;

TypeScript是一个强大的工具,用于构建大型项目

  • 类型允许JavaScript开发者在开发JavaScript应用程序时使用高效的开发工具和常用操作比如静态检查和代码重构;

  • 类型是可选的,类型推断让一些类型的注释使你的代码的静态验证有很大的不同。类型让你定义软件组件之间的接口和洞察现有JavaScript库的行为;

拥有先进的 JavaScript

  • TypeScript提供最新的和不断发展的JavaScript特性,包括那些来自2015年的ECMAScript和未来的提案中的特性,比如异步功能和Decorators,以帮助建立健壮的组件;

  • 这些特性为高可信应用程序开发时是可用的,但是会被编译成简洁的ECMAScript3(或更新版本)的JavaScript;

参考官方文档:TypeScript: Handbook - The TypeScript Handbook (typescriptlang.org) (opens new window)

# TypeScript的编译环境

# 安装命令
npm install typescript -g
# 查看版本
tsc --version
1
2
3
4

# TypeScript的运行环境

如果我们每次为了查看TypeScript代码的运行效果,都通过经过两个步骤的话就太繁琐了:

  • 第一步:通过tsc编译TypeScript到JavaScript代码;

  • 第二步:在浏览器或者Node环境下运行JavaScript代码;

是否可以简化这样的步骤呢?

  • 比如编写了TypeScript之后可以直接运行在浏览器上?

  • 比如编写了TypeScript之后,直接通过node的命令来执行?

n 上面我提到的两种方式,可以通过两个解决方案来完成:

  • 方式一:通过webpack,配置本地的TypeScript编译环境和开启一个本地服务,可以直接运行在浏览器上;

  • 方式二:通过ts-node库,为TypeScript的运行提供执行环境;

方式一:webpack配置

  • 方式一在之前的TypeScript文章中我已经有写过,如果需要可以自行查看对应的文章;

  • https://mp.weixin.qq.com/s/wnL1l-ERjTDykWM76l4Ajw;

方式二:安装ts-node

  • 另外ts-node需要依赖 tslib 和 @types/node 两个包:

  • 现在,我们可以直接通过 ts-node 来运行TypeScript的代码:

使用ts-node

npm install ts-node -g

npm install tslib @types/node -g

ts-node math.ts
1
2
3
4
5

# 变量的声明

  • 在TypeScript中定义变量需要指定 标识符 的类型。

  • 声明了类型后TypeScript就会进行类型检测,声明的类型可以称之为类型注解 var/let/const 标识符: 数据类型 = 赋值;

  • string是TypeScript中定义的字符串类型,String是ECMAScript中定义的一个类

  • 在TypeScript中并不建议再使用var关键字了,主要原因和ES6升级后let和var的区别是一样的,var是没有块级作用域的,会引起很多的问题,

  • 在开发中,有时候为了方便起见我们并不会在声明每一个变量时都写上对应的数据类型,我们更希望可以通过TypeScript本身的特性帮助我们推断出对应的变量类型

  • 个人习惯: 默认情况下, 如果可以推导出对应的标识符的类型时, 一般情况下是不加

// 1.类型注解
// 2.var/let/const
// 3.string和String的区别
// 4.类型推导
var name: string = "why"
let age: number = 18
const height: number = 1.88

// string: TypeScript中的字符串类型
// String: JavaScript的字符串包装类的类型
const message: string = "Hello World"

// 默认情况下进行赋值时, 会将赋值的值的类型, 作为前面标识符的类型
// 这个过程称之为类型推导/推断
// foo没有添加类型注解
let foo = "foo"
// foo = 123

export {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# JS和TS的数据类型

ts的变量注释用小写,js的大写数据类型为包装类; TypeScript是JavaScript的一个超级

image-20220304161548533

# 1、js类型:number类型

数字类型是我们开发中经常使用的类型,TypeScript和JavaScript一样,不区分整数类型(int)和浮点型(double),统一为number类型。

如果你学习过ES6应该知道,ES6新增了二进制和八进制的表示方法,而TypeScript也是支持二进制、八进制、十 六进制的表示:

let num1: number = 100 
let num2: number = 0b100 //二进制 4
let num3: number = 0o100 //八进制 64
let num4: number = 0x100 //十六进制 256
1
2
3
4

# 2、js类型: boolean布尔类型

boolean类型只有两个取值:true和false,非常简单

# 3、js类型:string类型

string类型是字符串类型,可以使用单引号或者双引号表示:

同时也支持ES6的模板字符串来拼接变量和字符串:

# 4、js类型:Array类型

// 确定一个事实: names是一个数组类型, 但是数组中存放的是什么类型的元素呢?
// 不好的习惯: 一个数组中在TypeScript开发中, 最好存放的数据类型是固定的(string)
// 类型注解: type annotation
const names1: Array<string> = [] // 不推荐(react jsx中是有冲突   <div></div>)
const names2: string[] = [] // 推荐
1
2
3
4
5

# 5、js类型:object类型

object对象类型可以用于描述一个对象,但是从 myinfo:object中我们不能获取数据,也不能设置数据,这是因为ts会先进行编译。 object类型,一般使用类型推导, 也可以使用as

image-20220305092057825

# 6、js类型:Symbol符号类型

在ES5中,如果我们是不可以在对象中添加相同的属性名称的,通常我们的做法是定义两个不同的属性名字:比如identity1和identity2。

但是我们也可以通过symbol来定义相同的名称,因为Symbol函数返回的是不同的值:

const title1 = Symbol("title") // 符号
const title2 = Symbol('title')

const info = {
  [title1]: "程序员",
  [title2]: "老师"
}

export {}
1
2
3
4
5
6
7
8
9

# 7、js类型:null和undefined类型

JavaScript 中,undefined 和 null 是两个基本数据类型,在TypeScript中,它们各自的类型也是undefined和null,也就意味着它们既是实际的值,也是自己的类型

let n1: null = null
let n2: undefined = undefined
1
2

# 8、ts类型:any类型

1、在某些情况下,我们确实无法确定一个变量的类型,并且可能它会发生一些变化,这个时候我们可以使用any类型(类似于Dart语言中的dynamic类型)。

2、any类型有点像一种讨巧的TypeScript手段:

  • 我们可以对any类型的变量进行任何的操作,包括获取不存在的属性、方法;

  • 我们给一个any类型的变量赋值任何的值,比如数字、字符串的值;

3、如果对于某些情况的处理过于繁琐不希望添加规定的类型注解,或者在引入一些第三方库时,缺失了类型注解,这个时候我们可以使用any:

  • 包括在Vue源码中,也会使用到any来进行某些类型的适配

# 9、ts类型:unknown类型

unknown是TypeScript中比较特殊的一种类型,它用于描述类型不确定的变量

  • unknown类型只能赋值给any和unknown类型
  • any类型可以赋值给任意类型

# 10、ts类型:void类型

void通常用来指定一个函数是没有返回值的,那么它的返回值就是void类型:

  • 我们可以将null和undefined赋值给void类型,也就是函数可以返回null或者undefined

这个函数我们没有写任何类型,那么它默认返回值的类型就是void的,我们也可以显示的来指定返回值是void:

# 11、ts类型:never类型

never 表示永远不会发生值的类型,比如一个函数:

  • 如果一个函数中是一个死循环或者抛出一个异常,那么这个函数会返回东西吗?

  • 不会,那么写void类型或者其他类型作为返回值类型都不合适,我们就可以使用never类型;

never有什么样的应用场景呢?

// 封装一个核心函数
function handleMessage(message: string | number | boolean) {
  switch (typeof message) {
    case 'string':
      console.log("string处理方式处理message")
      break
    case 'number':
      console.log("number处理方式处理message")
      break
    case 'boolean':
      console.log("boolean处理方式处理message")
      break
    default: //因为message定义了三个类型,所以程序不可能会进入这一个分支,可以使用never
      const check: never = message
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 12、ts类型:tuple类型

tuple是元组类型,很多语言中也有这种数据类型,比如Python、Swift等。

那么tuple和数组有什么区别呢?

  • 首先,数组中通常建议存放相同类型的元素,不同类型的元素是不推荐放在数组中。(可以放在对象或者元组中)

  • 其次,元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型;

Tuples的应用场景

tuple通常可以作为返回的值,在使用的时候会非常的方便;

1.数组的弊端
const info: any[] = ["why", 18, 1.88]

// 2.元组的特点
const info: [string, number, number] = ["why", 18, 1.88]
1
2
3
4
5

# 函数的参数类型

函数是JavaScript非常重要的组成部分,TypeScript允许我们指定函数的参数和返回值的类型。

参数的类型注解

  • 声明函数时,可以在每个参数后添加类型注解,以声明函数接受的参数类型

# 函数的返回值类型

我们也可以添加返回值的类型注解,这个注解出现在函数列表的后面:

和变量的类型注解一样,我们通常情况下不需要返回类型注解,因为TypeScript会根据 return 返回值推断函数的返回类型:

  • 某些第三方库处于方便理解,会明确指定返回类型,但是这个看个人喜好

# 匿名函数的参数

匿名函数与函数声明会有一些不同:

  • 当一个函数出现在TypeScript可以确定该函数会被如何调用的地方时;

  • 该函数的参数会自动指定类型;

我们并没有指定item的类型,但是item是一个string类型:

  • 这是因为TypeScript会根据forEach函数的类型以及数组的类型推断出item的类型;

  • 这个过程称之为上下文类型(contextual typing),因为函数执行的上下文可以帮助确定参数和返回值的类型

// 通常情况下, 在定义一个函数时, 都会给参数加上类型注解的
function foo(message: string) {

}

const names = ["abc", "cba", "nba"]
// item根据上下文的环境推导出来的, 这个时候可以不添加的类型注解
// 上下文中的函数: 可以不添加类型注解
names.forEach(function(item) {
  console.log(item.split(""))
})
1
2
3
4
5
6
7
8
9
10
11

# 对象类型

如果我们希望限定一个函数接受的参数是一个对象,这个时候要如何限定呢?

  • 我们可以使用对象类型;

在这里我们使用了一个对象来作为类型:

  • 在对象我们可以添加属性,并且告知TypeScript该属性需要是什么类型;

  • 属性之间可以使用 , 或者 ;来分割,最后一个分隔符是可选的;

  • 每个属性的类型部分也是可选的,如果不指定,那么就是any类型;

// Point: x/y -> 对象类型
// {x: number, y: number}
function printPoint(point: {x: number, y: number, z?: number}) {
  console.log(point.x);
  console.log(point.y)
}

printPoint({x: 123, y: 321})

export {}
1
2
3
4
5
6
7
8
9
10

# 可选类型

对象类型也可以指定哪些属性是可选的,可以在属性的后面添加一个?

# 联合类型

TypeScript的类型系统允许我们使用多种运算符,从现有类型中构建新类型。我们来使用第一种组合类型的方法:联合类型(Union Type)

  • 联合类型是由两个或者多个其他类型组成的类型;

  • 表示可以是这些类型中的任何一个值;

  • 联合类型中的每一个类型被称之为联合成员(union's members);

# 使用联合类型

传入给一个联合类型的值是非常简单的:只要保证是联合类型中的某一个类型的值即可 ,

  • 但是我们拿到这个值之后,我们应该如何使用它呢?因为它可能是任何一种类型。

  • 比如我们拿到的值可能是string或者number,我们就不能对其调用string上的一些方法;

那么我们怎么处理这样的问题呢?

  • 我们需要使用缩小(narrow)联合(后续我们还会专门讲解缩小相关的功能);

  • TypeScript可以根据我们缩小的代码结构,推断出更加具体的类型;

// number|string 联合类型
function printID(id: number|string|boolean) {
  // 使用联合类型的值时, 需要特别的小心
  // narrow: 缩小,联合类型缩小
  if (typeof id === 'string') {
    // TypeScript帮助确定id一定是string类型
    console.log(id.toUpperCase())
  } else {
    console.log(id)
  }
}
1
2
3
4
5
6
7
8
9
10
11

# 可选类型补充

  • 一个参数一个可选类型的时候, 它其实类似于是这个参数是 类型|undefined 的联合类型

# 类型别名type

// type用于定义类型别名(type alias)
type IDType = string | number | boolean
type PointType = {
  x: number
  y: number
  z?: number
}

function printId(id: IDType) {}

function printPoint(point: PointType) {}
1
2
3
4
5
6
7
8
9
10
11

# 类型断言as

有时候TypeScript无法获取具体的类型信息,这个我们需要使用类型断言Type Assertions。

  • 比如我们通过 document.getElementById,TypeScript只知道该函数会返回 HTMLElement ,但并不知道它具体的类型:

TypeScript只允许类型断言转换为 更具体 或者 不太具体 的类型版本,此规则可防止不可能的强制转换, 相当于强制类型转换

// 1.类型断言 as
const el = document.getElementById("why") as HTMLImageElement
el.src = "url地址"

// 3.了解: as any/unknown
const message = "Hello World"
// const num: number = (message as unknown) as number
1
2
3
4
5
6
7

# 非空类型断言!

我们确定传入的参数是有值的,这个时候我们可以使用非空类型断言:

  • 非空断言使用的是!,表示可以确定某个标识符是有值的,跳过ts在编译阶段对它的检测;

# 可选链的使用

可选链事实上并不是TypeScript独有的特性,它是ES11(ES2020)中增加的特性:

可选链使用可选链操作符 ?.;

  • 它的作用是当对象的属性不存在时,会短路,直接返回undefined,如果存在,那么才会继续执行;
  • 虽然可选链操作是ECMAScript提出的特性,但是和TypeScript一起使用更版本;
type Person = {
  name: string
  friend?: {
    name: string
    age?: number,
    girlFriend?: {
      name: string
    }
  }
}

const info: Person = {
  name: "why",
  friend: {
    name: "kobe",
    girlFriend: {
      name: "lily"
    }
  }
}

console.log(info.name)
// console.log(info.friend!.name)
console.log(info.friend?.name)
console.log(info.friend?.age)
console.log(info.friend?.girlFriend?.name)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# ??和!!的作用

!!操作符:

  • 将一个其他类型转换成boolean类型;

  • 类似于Boolean(变量)的方式;

??操作符:

  • 它是ES11增加的新特性;

  • 空值合并操作符**(**??)是一个逻辑操作符,当操作符的左侧是 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数

const message:string|null = "Hello World"

// const flag = Boolean(message)
// console.log(flag)

const flag = !!message
console.log(flag)

const content = message ?? "你好啊, 李银河"
// const content = message ? message: "你好啊, 李银河"
1
2
3
4
5
6
7
8
9
10

# 字面量类型literal types

默认情况下这么做是没有太大的意义的,但是我们可以将多个类型联合在一起

// "Hello World"也是可以作为类型的, 叫做字面量类型
const message: "Hello World" = "Hello World"

// let num: 123 = 123
// num = 321


// 字面量类型的意义, 就是必须结合联合类型
type Alignment = 'left' | 'right' | 'center'

let align: Alignment = 'left'
align = 'right'
align = 'center'

// align = 'hehehehe'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 字面量推理


type Method = 'GET' | 'POST'
function request(url: string, method: Method) {}

type Request = {
  url: string,
  method: Method
}

const options = {
  url: "https://www.coderwhy.org/abc",
  method: "POST"
} as const

request(options.url, options.method)

export {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 类型缩小

什么是类型缩小呢?

  • 类型缩小的英文是 Type Narrowing;

  • 我们可以通过类似于 typeof padding === "number"的判断语句,来改变TypeScript的执行路径;

  • 在给定的执行路径中,我们可以缩小比声明时更小的类型,这个过程称之为缩小;

  • 而我们编写的 typeof padding === "number 可以称之为 类型保护(type guards);

n 常见的类型保护有如下几种:

  • typeof:在 TypeScript 中,检查返回的值typeof是一种类型保护:因为 TypeScript 对如何typeof操作不同的值进行编码。

  • 平等缩小(比如===、!== , ==, and !=) :可以使用Switch或者相等的一些运算符来表达相等性

  • instanceof : JavaScript 有一个运算符来检查一个值是否是另一个值的“实例”

  • in:用于确定对象是否具有带名称的属性,如果指定的属性在指定的对象或其原型链中,则in 运算符返回true

  • 等等

// 1.typeof的类型缩小
type IDType = number | string
function printID(id: IDType) {
  if (typeof id === 'string') {
    console.log(id.toUpperCase())
  } else {
    console.log(id)
  }
}

// 2.平等的类型缩小(=== == !== !=/switch)
type Direction = "left" | "right" | "top" | "bottom"
function printDirection(direction: Direction) {
  // 1.if判断
  // if (direction === 'left') {
  //   console.log(direction)
  // } else if ()

  // 2.switch判断
  // switch (direction) {
  //   case 'left':
  //     console.log(direction)
  //     break;
  //   case ...
  // }
}

// 3.instanceof
function printTime(time: string | Date) {
  if (time instanceof Date) {
    console.log(time.toUTCString())
  } else {
    console.log(time)
  }
}

class Student {  studying() {} }

class Teacher {  teaching() {} }

function work(p: Student | Teacher) {
  if (p instanceof Student) {
    p.studying()
  } else {
    p.teaching()
  }
}

const stu = new Student()
work(stu)

// 4. in
type Fish = {  swimming: () => void }

type Dog = {  running: () => void }

function walk(animal: Fish | Dog) {
  if ('swimming' in animal) {
    animal.swimming()
  } else {
    animal.running()
  }
}

const fish: Fish = {
  swimming() {
    console.log("swimming")
  }
}

walk(fish)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

# TypeScript函数类型

在JavaScript开发中,函数是重要的组成部分,并且函数可以作为一等公民(可以作为参数,也可以作为返回值进行传递)。

那么在使用函数的过程中,函数是否也可以有自己的类型呢?

  • 我们可以编写函数类型的表达式(Function Type Expressions),来表示函数类型;
// 1.函数作为参数时, 在参数中如何编写类型
function foo() {}

type FooFnType = () => void
function bar(fn: FooFnType) {
  fn()
}

bar(foo)

// 2.定义常量时, 编写函数的类型
type AddFnType = (num1: number, num2: number) => number
const add: AddFnType = (a1: number, a2: number) => {
  return a1 + a2
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# TypeScript函数类型解析

在语法中(num1: number, num2: number) => void,代表的就是一个函数类型:

  • 接收两个参数的函数:num1和num2,并且都是number类型;

  • 并且这个函数是没有返回值的,所以是void;

  • void是比较宽泛的类型,返回number、空值都不会报错

在某些语言中,可能参数名称num1和num2是可以省略,但是TypeScript是不可以的:

# 参数的可选类型

# 默认参数

函数参数的书写顺序: 必选参数-- 默认参数-- 可选参数

// 必传参数 - 有默认值的参数 - 可选参数
function foo(y: number, x: number = 20) {
  console.log(x, y)
}
1
2
3
4

# 剩余参数

从ES6开始,JavaScript也支持剩余参数,剩余参数语法允许我们将一个不定数量的参数放到一个数组中

image-20220309102734806

# 可推导的this类型

this是JavaScript中一个比较难以理解和把握的知识点:

  • 我在公众号也有一篇文章专门讲解this:https://mp.weixin.qq.com/s/hYm0JgBI25grNG_2sCRlTA;

  • 因为this在不同的情况下会绑定不同的值,所以对于它的类型就更难把握了;

那么,TypeScript是如何处理this呢?我们先来看一个例子:

上面的代码是可以正常运行的,也就是TypeScript在编译时,认为我们的this是可以正确去使用的:

  • TypeScript认为函数 sayHello 有一个对应的this的外部对象 info,所以在使用时,就会把this当做该对象。
// this是可以被推导出来 info对象(TypeScript推导出来)
const info = {
  name: "why",
  sayHello () {
    console.log(this.name + " sayHello ")
  }
}

info.sayHello ()

export {}
1
2
3
4
5
6
7
8
9
10
11

# 不确定的this类型

image-20220309110401066

# 指定this的类型

type ThisType = { name: string };

function eating(this: ThisType, message: string) {
  console.log(this.name + " eating", message);
}

const info = {
  name: "why",
  eating: eating,
};

// 隐式绑定
info.eating("哈哈哈");

// 显示绑定
eating.call({name: "kobe"}, "呵呵呵")
eating.apply({name: "james"}, ["嘿嘿嘿"])

export {};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 函数的重载

# 联合类型和重载

我们现在有一个需求:定义一个函数,可以传入字符串或者数组,获取它们的长度。

n 这里有两种实现方案:

  • 方案一:使用联合类型来实现;

  • 方案二:实现函数重载来实现;

n 在开发中我们选择使用哪一种呢?

  • 在可能的情况下,尽量选择使用联合类型来实现;

# 认识类的使用

在早期的JavaScript开发中(ES5)我们需要通过函数和原型链来实现类和继承,从ES6开始,引入了class关键字,可以更加方便的定义和使用类。

n TypeScript作为JavaScript的超集,也是支持使用class关键字的,并且还可以对类的属性和方法等进行静态类型检测。

n 实际上在JavaScript的开发过程中,我们更加习惯于函数式编程:

  • 比如React开发中,目前更多使用的函数组件以及结合Hook的开发模式;

  • 比如在Vue3开发中,目前也更加推崇使用 Composition API;

但是在封装某些业务的时候,类具有更强大封装性,所以我们也需要掌握它们。

n 类的定义我们通常会使用class关键字:

  • 在面向对象的世界里,任何事物都可以使用类的结构来描述;

  • 类中包含特有的属性和方法;

# 类的定义

1、使用class关键字来定义一个类;

2、我们可以声明一些类的属性:在类的内部声明类的属性以及对应的类型

  • 如果类型没有声明,那么它们默认是any的;

  • 我们也可以给属性设置初始化值;

  • 在默认的strictPropertyInitialization模式下面我们的属性是必须初始化的,如果没有初始化,那么编译时就会报错;如果我们在strictPropertyInitialization模式下确实不希望给属性初始化,可以使用 name!: string语法;

3、类可以有自己的构造函数constructor,当我们通过new关键字创建一个实例时,构造函数会被调用;

  • 构造函数不需要返回任何值,默认返回当前创建出来的实例;

4、类中可以有自己的函数,定义的函数称之为方法;

# 类的继承

面向对象的其中一大特性就是继承,继承不仅仅可以减少我们的代码量,也是多态的使用前提。

我们使用extends关键字来实现继承,子类中使用super来访问父类。

我们来看一下Student类继承自Person:

  • Student类可以有自己的属性和方法,并且会继承Person的属性和方法;

  • 在构造函数中,我们可以通过super来调用父类的构造方法,对父类中的属性进行初始化;

# 多态

# 类的成员修饰符

在TypeScript中,类的属性和方法支持三种修饰符: public、private、protected

  • public 修饰的是在任何地方可见、公有的属性或方法,默认编写的属性就是public的;

  • private 修饰的是仅在同一类中可见、私有的属性或方法;

  • protected 修饰的是仅在类自身及子类中可见、受保护的属性或方法;

public是默认的修饰符,也是可以直接访问的,我们这里来演示一下protected和private。

# 只读属性readonly

如果有一个属性我们不希望外界可以任意的修改,只希望确定值后直接使用,那么可以使用readonly

  • 只读属性是可以在构造器中赋值, 赋值之后就不可以修改

  • 只读属性本身不能进行修改, 但是如果它是对象类型, 对象中的属性是可以修改

# getters/setters

在前面一些私有属性我们是不能直接访问的,或者某些属性我们想要监听它的获取(getter)和设置(setter)的过程,这个时候我们可以使用存取器。

  • 私有属性一般以_开始,并设置它们的get set方法
class Person {
  private _name: string
  constructor(name: string) {
    this._name = name
  }

  // 访问器setter/getter
  // setter
  set name(newName) {
    this._name = newName
  }
  // getter
  get name() {
    return this._name
  }
}

const p = new Person("why")
p.name = "coderwhy"
console.log(p.name)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 静态成员

前面我们在类中定义的成员和方法都属于对象级别的, 在开发中, 我们有时候也需要定义类级别的成员和方法。

在TypeScript中通过关键字static来定义:

# 抽象类abstract

我们知道,继承是多态使用的前提。

  • 所以在定义很多通用的调用接口时, 我们通常会让调用者传入父类,通过多态来实现更加灵活的调用方式。

  • 但是,父类本身可能并不需要对某些方法进行具体的实现,所以父类中定义的方法,,我们可以定义为抽象方法。

什么是 抽象方法? 在TypeScript中没有具体实现的方法(没有方法体),就是抽象方法。

  • 抽象方法,必须存在于抽象类中;

  • 抽象类是使用abstract声明的类;

抽象类有如下的特点:

  • 抽象类是不能被实例的话(也就是不能通过new创建)

  • 抽象方法必须被子类实现,否则该类必须是一个抽象类

# 类的类型

类本身也是可以作为一种数据类型的

# 接口的声明

在前面我们通过type可以用来声明一个对象类型:

对象的另外一种声明方式就是通过接口来声明:

  • 可以定义两个名称相同的接口,里面的属性会进行合并
// 通过类型(type)别名来声明对象类型
// type InfoType = {name: string, age: number}

// 另外一种方式声明对象类型: 接口interface
// 在其中可以定义可选类型
// 也可以定义只读属性
interface IInfoType {
  readonly name: string
  age: number
  friend?: {
    name: string
  }
}

const info: IInfoType = {
  name: "why",
  age: 18,
  friend: {
    name: "kobe"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 索引类型

前面我们使用interface来定义对象类型,这个时候其中的属性名、类型、方法都是确定的,但是有时候我们会遇到类似下面的对象:

interface ILanguageYear {
  [name: string]: number
}
1
2
3

# 函数类型

// type CalcFn = (n1: number, n2: number) => number
// 可调用的接口
interface CalcFn {
  (n1: number, n2: number): number
}
1
2
3
4
5

# 接口继承

接口和类一样是可以进行继承的,也是使用extends关键字:

  • 并且我们会发现,接口是支持多实现的(类不支持多继承)

# 接口的实现

接口定义后,也是可以被类实现的:

  • 如果被一个类实现,那么在之后需要传入接口的地方,都可以将这个类传入;

  • 这就是面向接口开发

# interface和type区别

我们会发现interface和type都可以用来定义对象类型,那么在开发中定义对象类型时,到底选择哪一个呢?

  • 如果是定义非对象类型,通常推荐使用type,比如Direction、Alignment、一些Function;

如果是定义对象类型,那么他们是有区别的:

  • interface 可以重复的对某个接口来定义属性和方法,会进行合并;

  • 而type定义的是别名,别名是不能重复的;

# 字面量赋值

TypeScript在字面量直接赋值的过程中,为了进行类型推导会进行严格的类型限制。

  • 但是之后如果我们是将一个 变量标识符 赋值给其他的变量时,会进行freshness擦除操作
interface IPerson {
  name: string
  age: number
  height: number
}

// const info:IPerson 代码会报错,不能直接赋值,会进行类型推导,和IPerson不一致
// const info = {  
//   name: "why",
//   age: 18,
//   height: 1.88,
//   address: "广州市"
// }

// // freshness擦除
// const p: IPerson = info
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# TypeScript枚举类型

枚举类型是为数不多的TypeScript特性有的特性之一:

  • 枚举其实就是将一组可能出现的值,一个个列举出来,定义在一个类型中,这个类型就是枚举类型;

  • 枚举允许开发者定义一组命名常量,常量可以是数字、字符串类型;

# 枚举类型的值

枚举类型默认是有值的,从0开始,比如上面的枚举,默认值是这样的:

当然,我们也可以给枚举其他值:

  • 这个时候会从100进行递增;

n 我们也可以给他们赋值其他的类型:

// type Direction = "left" | "Right" | "Top" | "Bottom"

enum Direction {
  LEFT=100,
  RIGHT,
  TOP,
  BOTTOM
}
1
2
3
4
5
6
7
8

# 认识泛型

软件工程的主要目的是构建不仅仅明确和一致的API,还要让你的代码具有很强的可重用性:

  • 比如我们可以通过函数来封装一些API,通过传入不同的函数参数,让函数帮助我们完成不同的操作;

  • 但是对于参数的类型是否也可以参数化呢?

什么是类型的参数化?

  • 我们来提一个需求:封装一个函数,传入一个参数,并且返回这个参数;

n 如果我们是TypeScript的思维方式,要考虑这个参数和返回值的类型需要一致:

上面的代码虽然实现了,但是不适用于其他类型,比如string、boolean、Person等类型

# 泛型实现类型参数化

虽然any是可以的,但是定义为any的时候,我们其实已经丢失了类型信息:

  • 比如我们传入的是一个number,那么我们希望返回的可不是any类型,而是number类型;

  • 所以,我们需要在函数中可以捕获到参数的类型是number,并且同时使用它来作为返回值的类型;

我们需要在这里使用一种特性的变量 - 类型变量(type variable),它作用于类型,而不是值:

这里我们可以使用两种方式来调用它:

  • 方式一:通过 <类型> 的方式将类型传递给函数;

  • 方式二:通过类型推到,自动推到出我们传入变量的类型:

    • 在这里会推导出它们是 字面量类型的,因为字面量类型对于我们的函数也是适用的
// 类型的参数化

// 在定义这个函数时, 我不决定这些参数的类型
// 而是让调用者以参数的形式告知,我这里的函数参数应该是什么类型
function foo<T, E, O>(arg1: T, arg2: E, arg3?: O, ...args: T[]) {}

foo<number, string, boolean>(10, "abc", true)
1
2
3
4
5
6
7

# 泛型的基本补充

平时在开发中我们可能会看到一些常用的名称:

  • T:Type的缩写,类型

  • K、V:key和value的缩写,键值对

  • E:Element的缩写,元素

  • O:Object的缩写,对象

# 泛型接口

# 泛型类

# 泛型约束

有时候我们希望传入的类型有某些共性,但是这些共性可能不是在同一种类型中:

  • 比如string和array都是有length的,或者某些对象也是会有length属性的;

  • 那么只要是拥有length的属性都可以作为我们的参数类型,那么应该如何操作呢

interface ILength {
  length: number
}

function getLength<T extends ILength>(arg: T) {
  return arg.length
}

getLength("abc")
getLength(["abc", "cba"])
getLength({length: 100})
1
2
3
4
5
6
7
8
9
10
11

# 模块化开发

TypeScript支持两种方式来控制我们的作用域:

  • 模块化:每个文件可以是一个独立的模块,支持ES Module,也支持CommonJS;

  • 命名空间:通过namespace来声明一个命名空间

# 命名空间namespace

命名空间在TypeScript早期时,称之为内部模块,主要目的是将一个模块内部再进行作用域的划分,防止一些命名冲突的问题。

export namespace time {  // 命名空间也需要导出
  export function format(time: string) {
    return "2222-02-22"
  }

  export function foo() {  }

  export let name: string = "abc"
}

export namespace price {
  export function format(price: number) { // 不同命名空间里面的函数名可以一样
    return "99.99"
  }
}

// 使用: time.format
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 类型的查找

之前我们所有的typescript中的类型,几乎都是我们自己编写的,但是我们也有用到一些其他的类型:

大家是否会奇怪,我们的HTMLImageElement类型来自哪里呢?甚至是document为什么可以有getElementById的方法呢?

  • 其实这里就涉及到typescript对类型的管理和查找规则了。

我们这里先给大家介绍另外的一种typescript文件:.d.ts文件

  • 我们之前编写的typescript文件都是 .ts 文件,这些文件最终会输出 .js 文件,也是我们通常编写代码的地方;

  • 还有另外一种文件 .d.ts 文件,它是用来做类型的声明(declare)。 它仅仅用来做类型检测,告知typescript我们有哪些类型;

那么typescript会在哪里查找我们的类型声明呢?

  • 内置类型声明;

  • 外部定义类型声明;

  • 自己定义类型声明;

# 内置类型声明

内置类型声明是typescript自带的、帮助我们内置了JavaScript运行时的一些标准化API的声明文件;

  • 包括比如Math、Date等内置类型,也包括DOM API,比如Window、Document等;

n 内置类型声明通常在我们安装typescript的环境中会带有的;

  • https://github.com/microsoft/TypeScript/tree/main/lib

image-20220311104938049

# 外部定义类型声明和自定义声明

外部类型声明通常是我们使用一些库(比如第三方库)时,需要的一些类型声明。

这些库通常有两种类型声明方式:

  • 方式一:在自己库中进行类型声明(编写.d.ts文件),比如axios

  • 方式二:通过社区的一个公有库DefinitelyTyped存放类型声明文件

    • 该库的GitHub地址:https://github.com/DefinitelyTyped/DefinitelyTyped/
    • 该库查找声明安装方式的地址: TypeScript: Search for typed packages (typescriptlang.org) (opens new window)
    • 比如我们安装react的类型声明: npm i @types/react --save-dev

image-20220311105155543

什么情况下需要自定义声明文件呢?

  • 情况一:我们使用的第三方库是一个纯的JavaScript库,没有对应的声明文件;比如lodash
  • 情况二:我们给自己的代码中声明一些类型,方便在其他地方直接进行使用;
npm i jquery
npm i @types/jquery --save-dev

npm i lodash
npm i @types/lodash --save-dev
1
2
3
4
5

# 声明变量-函数-类

image-20220311110828186

# 声明模块

我们也可以声明模块,比如lodash模块默认不能使用的情况,可以自己来声明这个模块:

n 声明模块的语法: declare module '模块名' {}。

  • 在声明模块的内部,我们可以通过 export 导出对应库的类、函数等;

# declare文件

在某些情况下,我们也可以声明文件:

  • 比如在开发vue的过程中,默认是不识别我们的.vue文件的,那么我们就需要对其进行文件的声明;

  • 比如在开发中我们使用了 jpg 这类图片文件,默认typescript也是不支持的,也需要对其进行声明;

# declare命名空间

比如我们在index.html中直接引入了jQuery:

  • CDN地址: https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js

我们可以进行命名空间的声明:

在main.ts中就可以使用了:

// 声明模块
declare module 'lodash' {
  export function join(arr: any[]): void
}

// 声明变量/函数/类
declare let whyName: string
declare let whyAge: number
declare let whyHeight: number

declare function whyFoo(): void

declare class Person {
  name: string
  age: number
  constructor(name: string, age: number)
}

// 声明文件
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.png'
declare module '*.svg'
declare module '*.gif'

// 声明命名空间
declare namespace $ {
  export function ajax(settings: any): any
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# tsconfig.json文件

tsconfig.json是用于配置TypeScript编译时的配置选项:

  • https://www.typescriptlang.org/tsconfig

我们这里讲解几个比较常见的:

# 常用函数

# InstanceType

返回T的实例类型,

参考: 为vue3学点typescript, 解读高级类型 - 简书 (jianshu.com) (opens new window)

TypeScript: instancetype(typescriptlang.org) (opens new window)

typescript面向对象
es6基础

← typescript面向对象 es6基础→

最近更新
01
国际象棋
09-15
02
成语
09-15
03
自然拼读
09-15
更多文章>
Theme by Vdoing | Copyright © 2019-2023 zxpnet | 粤ICP备14079330号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式