Zhong__TypeScript

时间:2022.07.12

环境:Windows VSCode

目的:TypeScript知识点汇总

说明:

作者:Zhong QQ交流群:121160124 欢迎加入!

目录

TypeScript

安装

简单体验

类型注解

联合类型

unknown类型

void类型

never类型

tuple类型

函数类型和函数参数/返回值

字面量类型

对象类型

索引类型

type alias(类型别名)

as(类型断言)

非空类型断言

字面量推理

可选链

??(空值合并操作符)

!!(其它类型转布尔类型)

Type Narrowing(类型缩小)

函数的重载

类的使用

readonly属性

getter/setter访问器

static静态属性/方法

abstract抽象类

接口

接口定义类型

接口的继承

交叉类型

接口的实现

interface和type的区别

字面量赋值

枚举类型

泛型

类型参数化

泛型接口

泛型类

类型的类型约束

模块化开发

模块化

类型的查找

namespace(命名空间)


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 欢迎加入!

关注微信公众号:

​​​​​​​

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我变了_我没变

随意 。。。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值