时间:2022.07.12
环境:Windows VSCode
目的:TypeScript知识点汇总
说明:
作者:Zhong QQ交流群:121160124 欢迎加入!
目录
TypeScript
TypeScript是拥有类型的JavaScript超集 它可以编译成普通、干净、完整的JavaScript代码
安装
npm install typescript -g
简单体验
const name: string = 'KiKi'
// 类型推导 根据值推导类型
let a = 'a'
let mes: any = 'ok'
mes = 200
mes = true
// 不声明类型 那么变量隐式具有any类型 可以赋值任何类型值
let b
b = 10
b = '20'
// 声明类型
let c: number
c = 20
// number类型可以赋值十进制、二进制、八进制和十六进制等的所有数字类型
const n: number = 100
const n1: number = 0b100
const n2: number = 0o100
const n3: number = 0x100
let bool: boolean = true
const list1: string[] = [] // 推荐
const list2: Array<string> = []
// null和undefined的值都只有一个
let x: null = null
let y: undefined = undefined
const obj = {
name: 'KiKi',
age: 18
}
// 表示为一个模块 不会与其它文件/模块声明的变量冲突了
export {}
note
ts给元素指定类型称为类型注解
在ts中也可以使用类型推导 如let name = "syz" 那么name是可以推导出来为字符串类型的了
name: string与name: String是不一样的 String是JS的字符串类 string是TS的字符串类型 所以一般是使用string
ts与js一样对于数字类型是不区分整数与浮点类型的 统一为number类型(包括二进制、八进制和十六进制)
类型注解
联合类型
限定类型为两个及以上的类型
let res: string | number
res = "ok"
res = 200
// res = true // 只能赋值字符串/数字类型
// res = undefined // 只能赋值字符串/数字类型
unknown类型
unknown是ts中比较特殊的一种类型 与any的区别是any可以赋值给任何类型 unknown只能赋值给unknown和any类型
function str() {
return 'hi'
}
function int() {
return 100
}
let isFlag: boolean = true
// let result: string | number // 联合类型
// let result: any
let result: unknown
if (isFlag) {
result = str()
} else {
result = int()
}
let res: any = result // 与any的区别是any可以赋值给任何类型 unknown只能赋值给unknown和any类型
export {}
void类型
如果一个函数没有返回值(return) 那么默认它的返回值类型就是void类型 默认返回值undefined
function sum(n1: number, n2:number) {
console.log(n1 + n2)
}
// 其声明类型不为 "void" 或 "any" 的函数必须返回值。
function sum(n1: number, n2:number): number {
return n1 + n2
}
never类型
never类型意味着可能存在不会退出的循环等逻辑 不会返回值
function handMessage(message: string | number | boolean) {
switch (typeof message) {
case 'string':
console.log('string')
break
case 'number':
console.log('number')
break
case 'boolean':
console.log('boolean')
break
default:
const check: never = message
}
}
handMessage("hello")
tuple类型
元祖类型
const tupleData: [string, number, string] = ["syz", 20, "北京"]
函数类型和函数参数/返回值
() => void表示无参返回值为空的函数类型
type SumFnType = (num1: number, num2: number, freeNum?: number) => number
const Sum: SumFnType = (n1: number, n2: number, freeN?: number) => {
return n1 + n2
}
console.log(Sum(1, 1))
// Demo
function calc(
n1: number,
n2: number,
fn: (num1: number, num2: number) => number
) {
return fn(n1, n2)
}
const res1 = calc(1, 1, function(a1, a2) {
return a1 + a2
})
const res2 = calc(10, 10, function(b1, b2) {
return b1 * b2
})
console.log(res1)
console.log(res2)
字面量类型
字面量也是可以作为一种类型的 字面量类型的意义就是必须结合联合类型 限制可取值范围
let num: 123 = 123
let str: 'syz' = 'syz'
type Alignment = 'left' | 'right' | 'center'
let align: Alignment = 'center'
align = 'left'
align = 'right'
对象类型
function printPoint(point: { x: number; y: number; z?: number }) {
console.log(point.x)
console.log(point.y)
console.log(point.z)
}
// printPoint({x: 1, y: 2, z: 3})
printPoint({x: 1, y: 2}) // z为可选参数 可不填不填则是undefined
索引类型
interface IIndexType {
[index: number]: string
}
const info: IIndexType = {
0: 'a',
'1': 'b' // key其实都是视为字符串
// 'a': 'c' // IIndexType规定了key为number类型
}
console.log(info)
type alias(类型别名)
type用来定义类型别名
type mesType = string | number | boolean
function Mes(mes: mesType) {
}
as(类型断言)
对于TS无法获取具体的类型信息 可以使用类型断言 TS只允许类型断言转换为更具体或者不太具体的类型版本 此规则可防止不可能的强制转换
const el = document.getElementById('zh') as HTMLImageElement
el.src = 'url地址'
class Person {}
class Student extends Person {
studying() {}
}
function sayHello(p: Person) {
;(p as Student).studying()
}
const stu = new Student()
sayHello(stu)
!非空类型断言
!一定会有值 用于在确定有值的情况下通过编译运行
function mes(message?: string) {
console.log(message!.length)
}
mes("hello")
字面量推理
type Method = 'GET' | 'POST'
function request(url: string, method: Method) {}
// 0
/*
type Req = {
url: string,
method: Method
}
const options: Req = {
url: "",
method: "POST"
}
request(options.url, options.method)
*/
// 1
/*
const options = {
url: "",
method: "POST"
}
request(options.url, options.method as Method)
*/
// 2
const options = {
url: '',
method: 'POST'
} as const
request(options.url, options.method)
可选链
可选链操作符?. 作用是当对象的属性不存在时会短路直接返回undefined 如果存在才会继续执行
type Person = {
name: string,
friend?: {
name: string
age?: number
}
}
const info: Person = {
name: 'zh',
friend: {
name: "孙燕姿",
// age: 20
}
}
console.log(info.name)
console.log(info.friend?.name)
console.log(info.friend?.age)
??(空值合并操作符)
空值合并操作符 是一个逻辑操作符 当操作符的左侧是null或者undefined时 返回其右侧操作数 否则返回左侧操作数
其功能等价于三元运算符 可以当成语法糖
let mes: string | null = null
// let mes: string | null = "Hello"
const content = mes ?? "你好"
const text = mes ? mes : "你好"
console.log(content)
console.log(text)
!!(其它类型转布尔类型)
将一个其它类型转换为boolean类型 类似于Boolean(变量)的方式
// const mes: string = ""
const mes: string = 'Hi'
const flag: boolean = !mes // !表示非 原本mes是有值的(true) 非之后结果为false
const isFlag: boolean = !!mes // !!表示非之后再取反 结果为true 也就是原本字符串意义上的布尔值
console.log(flag)
console.log(isFlag)
Type Narrowing(类型缩小)
可以通过类似于typeof padding === "number"的判断语句 来改变TypeScript的执行路径 这种语句可以称之为类型保护(type guards)
在给定的执行路径中 我们可以缩小比声明时更小的类型 这个过程称之为缩小
常见的类型保护:typeof/平等缩小(如===/!==)/instanceof/in等等
// typeof
type IDType = number | string
function printID(id: IDType) {
if (typeof id === 'string') {
id.toUpperCase()
} else {
id.toString()
}
}
// 平等的类型缩小(=== == !== != / switch)
type Direction = 'left' | 'right' | 'center'
function printDirection(direction: Direction) {
switch (direction) {
case 'left':
console.log(direction)
break
case 'right':
console.log(direction)
break
default:
console.log(direction)
}
}
// instanceof
class Teacher {
teaching() {}
}
class Student {
studying() {}
}
function task(p: Teacher | Student) {
if (p instanceof Student) {
p.studying()
} else {
p.teaching()
}
}
let stu = new Student()
task(stu)
// in
type Fish = {
swimming: () => void
}
type Dog = {
running: () => void
}
function walk(animal: Fish | Dog) {
if ('swimming' in animal) {
animal.swimming()
} else {
animal.running()
}
}
let fish: Fish = {
swimming() {}
}
walk(fish)
函数的重载
函数的名称相同 参数不同(名称/类型/个数)的两个或多个函数就是函数的重载
function add(num1: number, num2: number): number
function add(num1: string, num2: string): string
function add(num1: any, num2: any): any {
return num1 + num2
}
console.log(add(1, 1))
console.log(add('a', 'b'))
// console.log(add('a', 1)) // 没有与此调用匹配的重载
类的使用
面向对象的三大特性:封装、继承和多态
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
singing() {
console.log(`${this.name} is singing!`)
}
}
const p = new Person('syz', 20)
console.log(p.name)
console.log(p.age)
p.singing()
readonly属性
readonly是可以在构造器中赋值 赋值之后就不可以修改
属性本身不能进行修改 不过如果它是对象类型 对象中的属性是可以修改的
class Person {
readonly name: string
age: number
readonly info: {
address: string
}
constructor(name: string, age: number, info: { address: string }) {
this.name = name
this.age = age
this.info = info
}
}
const p = new Person('syz', 20, { address: '北京' })
// p.name = "kiki"
// p.info = {address: "上海"}
p.age = 18
p.info.address = '上海'
console.log(p.info.address)
getter/setter访问器
通过getter/setter访问私有属性
class Person {
private _name: string
constructor(name: string) {
this._name = name
}
get name() {
return this._name
}
set name(newName) {
this._name = newName
}
}
const p = new Person('syz')
// p._name = "kiki"
// console.log(p._name)
p.name = 'kiki'
console.log(p.name)
static静态属性/方法
也叫类属性/方法
class Person {
static mes: string = 'this is a Person class'
static action() {
console.log('this is a Person class method')
}
}
Person.mes
Person.action()
let p = new Person()
// p.mes
// p.action()
abstract抽象类
在TS中没有具体实现的方法(没有方法体)就是抽象方法 如果无法确定方法如何具体的实现 可以使用抽象类
抽象方法必须存在于抽象类中
抽象类是使用abstract声明的类
抽象类是不能被实例化(不能通过new创建)
抽象方法必须被子类实现 否则该类也必须是一个抽象类
function calcArea(shape: Shape) {
return shape.getArea()
}
abstract class Shape {
abstract getArea()
}
class Rectangle extends Shape {
private width: number
private height: number
constructor(width: number, height: number) {
super()
this.width = width
this.height = height
}
getArea() {
return this.width * this.height
}
}
class Circle extends Shape {
private r: number
constructor(r: number) {
super()
this.r = r
}
getArea() {
return this.r * this.r * 3.14
}
}
const rectangle = new Rectangle(1, 2)
const circle = new Circle(1)
console.log(calcArea(rectangle))
console.log(calcArea(circle))
// console.log(calcArea(123))
note
类也可以作为一种类型
可以使用public、private、protected修饰符来对类成员属性/方法限定可见的范围
public修饰的是在任何地方可见、公有的属性或方法 默认编写的属性就是public的
private修饰的是仅在同一类中可见、私有的属性或方法
protected修饰的是仅在类自身及子类中可见、受保护的属性或方法
接口
接口用来定义对象类型 与type相比 目前推荐使用接口来进行开发
接口定义类型
interface IMes {
name: string
age?: number
}
const mes: IMes = {
name: '孙燕姿',
age: 20
}
console.log(mes)
接口的继承
接口支持多继承
interface ISwim {
swimming: () => void
}
interface IFly {
flying: () => void
}
interface IAction extends ISwim, IFly {}
const action: IAction = {
swimming() {
console.log('Can swimming!')
},
flying() {
console.log('Can flying!')
}
}
action.swimming()
action.flying()
交叉类型
交叉类型是所有条件都要满足
// 联合类型
type WhyType = number | string
type Direction = 'left' | 'right' | 'center'
// 交叉类型
type WType = number & string
interface ISwim {
swimming: () => void
}
interface IFly {
flying: () => void
}
type Type1 = ISwim | IFly
type Type2 = ISwim & IFly
const obj1: Type1 = {
// flying() {
// console.log('Can flying!')
// },
swimming() {
console.log('Can swimming!')
}
}
const obj2: Type2 = {
swimming() {
console.log('Can swimming!')
},
flying() {
console.log('Can flying!')
}
}
obj1.swimming()
obj2.swimming()
obj2.flying()
接口的实现
类可以实现多个接口
interface ISwim {
swimming: () => void
}
interface IFly {
flying: () => void
}
class Animal {}
class FlyFish extends Animal implements ISwim, IFly {
swimming() {
console.log('飞鱼 Can swimming!')
}
flying() {
console.log('飞鱼 Can flying!')
}
}
const flyFish = new FlyFish()
flyFish.swimming()
flyFish.flying()
interface和type的区别
如果是定义非对象类型 通常推荐使用type 如Direction、Alignment、一些Function
如果是定义对象类型 它们是有区别的
- interface可以重复的对某个接口来定义属性和方法
interface IPerson {
name: string
}
interface IPerson {
age: number
}
const p: IPerson = {
name: 'kiki',
age: 18
}
- type定义的是别名 别名是不能重复的
type IPerson = {
name: string
}
// 标识符“IPerson”重复
// type IPerson = {
// age: number
// }
字面量赋值
定义变量指定类型时 如果是直接赋值 类型检测会检测类型里面指定的所有属性/方法要和值对象一致 如果是引用对象时 那么会自动忽略其它属性/方法 只检查指定属性/方法
interface IPerson {
name: string
age: number
}
const info = {
name: 'kiki',
age: 18,
address: '北京'
}
// 不能直接赋值
// const p1:IPerson = {
// name: "kiki",
// age: 18,
// address: "北京"
// }
// 可赋值 会做freshness操作 类型检测会只检查IPerson接口包含的属性/方法
const p2: IPerson = info
console.log(p2)
function printPerson(p: IPerson) {
console.log(p)
}
printPerson(info)
printPerson(p2)
printPerson({
name: 'kiki',
age: 18
// address: "北京"
})
枚举类型
枚举类型是为数不多的TypeScript特有的特性之一
枚举就是将一组可能出现的值一个个列举出现 定义在一个类型中 这个类型就是枚举类型
枚举允许开发者定义一组命名常量 常量可以是数字、字符串等类型
enum Direction {
LEFT = '左',
RIGHT = '右',
TOP = '上',
BOTTOM = '下'
}
function printDirection(direction: Direction) {
console.log(direction)
switch (direction) {
case Direction.LEFT:
console.log(`向${Direction.LEFT}`)
break
case Direction.RIGHT:
console.log(`向${Direction.RIGHT}`)
break
case Direction.TOP:
console.log(`向${Direction.TOP}`)
break
case Direction.BOTTOM:
console.log(`向${Direction.BOTTOM}`)
break
default:
const other: never = direction
break
}
}
printDirection(Direction.LEFT)
printDirection(Direction.RIGHT)
printDirection(Direction.TOP)
printDirection(Direction.BOTTOM)
泛型
传入参数的类型 在调用者传参时动态决定形参的类型
类型参数化
// 定义一个函数 形参的类型由调用者传入
function printInfo<T>(arg: T): T {
console.log(arg, typeof arg)
return arg
}
printInfo<number>(1)
printInfo<string>('泛型')
// 推导
printInfo({ name: 'syz' })
// 多个参数
function printPerson<T1, T2>(arg1: T1, arg2: T2) {
console.log(arg1, typeof arg1)
console.log(arg2, typeof arg2)
}
printPerson<string, number>('hzy', 27)
// 推导
printPerson('kiki', 18)
泛型接口
接口也可以使用泛型 可以指定默认类型
interface IPerson<T1, T2 = number> {
name: T1
age: T2
}
const p: IPerson<string> = {
name: 'syz',
age: 20
}
console.log(p)
泛型类
类一样也可以使用泛型
class Point<T> {
x: T
y: T
z: T
constructor(x: T, y: T, z: T) {
this.x = x
this.y = y
this.z = z
}
}
const p1 = new Point(1, 2, 3)
const p2 = new Point<string>('1', '2', '3')
const p3: Point<number> = new Point(1, 2, 3)
类型的类型约束
对类型的类型进行约束
interface ILength {
length: number
}
function getLength<T extends ILength>(arg: T) {
return arg.length
}
// number没有length属性
// getLength(123)
getLength('abc')
getLength(['a', 'b', 'c'])
getLength({length: 20})
模块化开发
模块化
类型的查找
.d.ts(declare缩写)文件是用来做类型的声明(declare) 它仅仅用来做类型检测 告知ts有哪些类型
ts会在下面几个地方查找类型声明
- 内置类型声明
- 外部定义类型声明
- 自定义类型声明
内置类型声明是ts自带的 内置了js运行时的一些标准化API的声明文件 包括如Math、Date等内置类型 也包括DOM API如Window、Document等
外部类型声明通常是使用一些库如第三方库时需要的一些类型声明 这些库通常有两种类型声明方式
1、在自己库中进行类型声明(编写.d.ts文件) 如axios
2、通过社区的一个公有库Definitely Typed存放类型声明文件
自定义声明通常有两种情况
1、使用的第三方库是一个纯的js库 没有对应的声明文件如lodash
2、自己写的代码中声明一些类型 方便在其它地方直接进行使用
namespace(命名空间)
命名空间在TS早期时称之为内部模块 主要目的是将一个模块内部再进行作用域的划分 防止一些命名冲突的问题
// 外部可引用
export namespace time {
export function format(time: string) {
return '2008-08-08'
}
export let name: string = 'kiki'
let age: number = 18
}
namespace price {
export function format(price: number) {
return 9.9
}
}
time.format('2008.08.08')
time.name
// time.age // 未导出 在空间外不可使用
price.format(9.9)
↑
QQ交流群:121160124 欢迎加入!
关注微信公众号: