注册

TypeScript 原始类型、函数、接口、类、泛型 基础总结



原始数据类型

原始数据类型包括:

  • Boolean

  • String

  • Number

  • Null

  • undefined

类型声明是TS非常重要的一个特点,通过类型声明可以指定TS中变量、参数、形参的类型。

  • Boolean 类型

    let boolean: boolean = true
    boolean = false
    boolean = null
    // bollean = 123 报错不可以将数字 123 赋值给 boolean类型的变量
  • Number 类型

    //ES6 Number 类型 新增支持2进制和8进制
    let num: number = 123
    num = 0b1111
  • String 类型

    let str1: string = 'hello TS'
    let sre2: string = `模板字符串也支持使用 ${str1}`]
  • Null 和 Undefined

    let n: null = null
    let u: undefined = undefined
    n = undefined
    u = null
    // undefined 和 null 是所有类型的子类型 所以可以赋值给number类型的变量
    let num: number = 123
    num = undefined
    num = null

any 类型

any 表示队变量没有任何显示,编译器失去了对 TS 的检测功能与 JS 无异(不建议使用)。

let notSure: any = 4
// any类型可以随意赋值
notSure = `任意模板字符串`
notSure = true
notSure = null

// 当 notSure 为any 类型时,在any类型上访问任何属性和调用方法都是允许的, 很有可能出现错误
notSure.name // 现在调用name属性是允许的,但很明显我们定义的notSure没有name这个属性,下面的调用sayName方法也是如此
notSure.sayName()

array 类型

// 数组类型,可以指定数组的类型和使用数组的方法和属性
let arrOfNumbers: number[] = [1, 2, 3]
console.log(arrOfNumbers.length);

arrOfNumbers.push(4)

tuple 元组类型

// 元组类型  元组就是固定长度,类型的数组  
// 类型和长度必须一致
let u: [string, number] = ['12', 12]
// let U: [string, number] = ['12', 12, true]   报错信息为:不能将类型“[string, number, boolean]”分配给类型“[string, number]”。源具有 3 个元素,但目标仅允许 2 个。

// 也可以使用数组的方法,如下所示push一个值给元组u
u.push(33)

Interface 接口

  • 对对象的形状(shape)进行描述

  • Duck Typing(鸭子类型)

interface Person {
   // readonly id 表示只读属性的id不可以修改
   readonly id: number;
   name: string;
   age: number;
   // weight? 表示可选属性,可以选用也可以不选用
   weight?: number
}

let host: Person = {
   id: 1,
   name: 'host',
   age: 20,
   weight: 70
}

//host.id = 2 报错 提示信息为:无法分配到 "id" ,因为它是只读属性

function 函数类型

// 方式一:函数声明的写法   z 为可选参数 ,
function add1 (x: number, y: number, z?: number): number {
   if (typeof z === 'number') {
       return x + y + z
  } else {
       return x + y
  }
}
// 需要注意的是:可选参数必须置于所有必选参数之后,否则会报错

add1(1, 2, 3)

// 方式二:函数表达式
const add2 = (x: number, y: number, z?: number): number => {
   if (typeof z === 'number') {
       return x + y + z
  } else {
       return x + y
  }
}


// 使用interface接口 描述函数类型
interface ISum {
  (x: number, y: number, z?: number): number
}
let add3: ISum = add1

值的注意的是:可选参数必须置于所有必选参数之后,否则会报错,如下图展示的错误案例所示:·

image-20211120152558241

类型推论

当定义变量时没有指定类型,编译器会自动推论第一次赋的值为默认类型

let s = 'str'
// s = 12 本句将会报错,提示为:不能将类型“number”分配给类型“string”

联合类型

使用| 分隔可选类型

let StringOrNumber: string | number
StringOrNumber = 123
StringOrNumber = '111'

类型断言

使用 as 关键字进行类型断言

function getLength (rod: number | string): number {
   const str = rod as string
   //这里我们可以用 as 关键字,告诉typescript 编译器,你没法判断我的代码,但是我本人很清楚,这里我就把它看作是一个 string,你可以给他用 string 的方法。
   if (str.length) {
       return str.length
  } else {
       const num = rod as number
       return num.toString().length
  }
}

类型守卫

// 4.类型守卫 type guard     typescript 在不同的条件分支里面,智能的缩小了范围
function getLength2 (rod: number | string): number {
   if (typeof rod === 'string') {
       return rod.length
  } else {
       // else 里面的rod 会自动默认为number类型
       return rod.toString().length
       
  }
}

Class 类

面向对象编程的三大特点:

  • 封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,

  • 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性。

  • 多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。

话不多少,看代码:

class Animal {
   readonly name: string
   constructor(name: string) {
       this.name = name
       console.log(this.run())
  }
   // private run ():私有的   protected run () 受保护的
   run () {
       return `${this.name} is running`
  }

}
const animal = new Animal('elephant')
// console.log(animal.name)
animal.run() //elephant is running

// 继承
class Dog extends Animal {
   age: number
   constructor(name, age) {
       super(name)
       console.log(this.name)
       this.age = age
  }
   bark () {
       console.log(`这只在叫的狗狗叫${this.name},它今年${this.age}岁了`)
  }
}
const dog = new Dog('旺财', 5)
dog.run() // 旺财 is running
dog.bark() // 这只在叫的狗狗叫旺财,它今年5岁了


// 多态
class Cat extends Animal {
   static catAge = 2

   constructor(name) {
       super(name)
       console.log(this.name) // 布丁
  }
   run () {
       return 'Meow,' + super.run()
  }
}
const cat = new Cat('布丁')
console.log(cat.run()) // Meow,布丁 is running
console.log(Cat.catAge) // 2

class中还提供了readonly关键字,readonly为只读属性,在调用的时候不能修改。如下所示:

image-20211124155826105

类成员修饰符

  • public修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是public的。

  • private修饰的属性或方法是私有的,不能在声明它的类的外部访问。

    上述示例代码中,在父类Animalrun 方法身上加上private修饰符之后就会产生如下图的报错信息:

    image-20211124154129377

  • protected 修饰的属性或方法是受保护的,它和private类似,区别在于它在子类中也是可以访问的。

上述示例代码中,在父类Animalrun 方法身上加上protected修饰符之后就会产生如下图的报错信息:

image-20211124153823828

接口和类

类可以使用 implements来实现接口。

// interface可以用来抽象验证类的方法和方法
interface Person {
   Speak (trigger: boolean): void;
}
interface Teenagers {
   Young (sge: number): void
}
// 接口之间的继承
interface PersonAndTeenagers extends Teenagers {
   Speak (trigger: boolean): void;
}

// implements 实现接口
class Boy implements Person {
   Speak (mouth: boolean) { }
}

// class Girl implements Person, Teenagers 和 class Girl implements PersonAndTeenagers 作用相同
class Girl implements PersonAndTeenagers {
   Speak (mouth: boolean) { }
   Young (sge: number) { }
}

enum枚举

枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:

enum Color {
   red = 'red',
   blue = 'blue',
   yellow = 'yellow',
   green = 'green'
}
// 常量枚举
const enum Color {
   red = 'red',
   blue = 'blue',
   yellow = 'yellow',
   green = 'green'
}
console.log(Color.red) // 0
// 反向映射
console.log(Color[0]) // red

const value = 'red'
if (value === Color.red) {
   console.log('Go Go Go ')
  • 常量枚举经过编译后形成的js文件如下:

image-20211124182628644

  • 非常量枚举经过编译器编译之后的js文件如下:

image-20211124182633413

Generics 泛型

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

  • 约束泛型

  • 类与泛型

  • 接口与泛

示例代码如下:

function echo (arg) {
   return arg
}

let result1 = echo(123) // 参数传递123后result1 的类型为any

// 泛型
function echo2<T> (arg: T): T {
   return arg
}
let result2 = echo2(123)  // 加上泛型之后 参数传递 123后result2的类型为number

function swap<T, U> (tuple: [T, U]): [U, T] {
   return [tuple[1], tuple[0]]
}
console.log(swap(['hero', 123]))//[ 123, 'hero' ]


// 约束泛型
interface IWithLength {
   length: number
}

function echoWithLength<T extends IWithLength> (arg: T): T {
   console.log(arg.length)
   return arg
}

const str = echoWithLength('123')
const obj = echoWithLength({ length: 3, name: 'Tom' })
const arr = echoWithLength([1, 2, 3, 4])


// 类与泛型
class Queue<T> {
   private data = []
   push (item: T) {
       return this.data.push(item)
  }
   pop (): T {
       return this.data.shift()
  }
}
const queue = new Queue<number>()

queue.push(1)
console.log(queue.pop().toFixed())// 1


// 接口与泛型
interface KeyPair<T, U> {
   key: T
   value: U
}
let kp1: KeyPair<string, number> = { key: 'str', value: 123 }
let kp2: KeyPair<number, string> = { key: 123, value: 'str' }
let arr2: Array<string> = ['1', '2'] // 使用 Array<string> 等价于 interface Array<T>

类型别名 type-alias

类型别名,就是给类型起一个别名,让它可以更方便的被重用。

let sum: (x: number, y: string) => number
const result1 = sum(1, '2')
// 将(x: number, y: string) => number类型取一个别名 为 PlusType
type PlusType = (x: number, y: string) => number
let sum2: PlusType
const result2 = sum2(2, '2')

type StrOrNum = string | number
let result3: StrOrNum = 123
result3 = '123'

字面量

let Name: 'name' = 'name'
// Name = '123' //报错信息:不能将类型“"123"”分配给类型“"name"”
let age: 19 = 19

type Directions = 'Up' | 'Down' | 'Left' | 'Right'
let up: Directions = 'Up'

交叉类型

// 交叉类型  使用 ‘&’ 符号进行类型的扩展
interface IName {
   name: string
}

type IPerson = IName & { age: number }
let person: IPerson = { name: 'Tom', age: 19 }

内置类型

  • 全局对象

// global objects 全局对象
const a: Array<string> = ['123', '456']
const time = new Date()
time.getTime()
const reg = /abc/ // 此时reg为RegExp类型
reg.test('abc')
  • build-in object 内置对象

    Math.pow(2, 2) //返回 2 的 2次幂。
    console.log(Math.pow(2, 2)) // 4
  • DOM and BOM

    // document 对象,返回的是一个 HTMLElement
    let body: HTMLElement = document.body
    // document 上面的query 方法,返回的是一个 nodeList 类型
    let allLis = document.querySelectorAll('li')

    //当然添加事件也是很重要的一部分,document 上面有 addEventListener 方法,注意这个回调函数,因为类型推断,这里面的 e 事件对象也自动获得了类型,这里是个 mouseEvent 类型,因为点击是一个鼠标事件,现在我们可以方便的使用 e 上面的方法和属性。
    document.addEventListener('click', (e) => {
       e.preventDefault()
    })
  • utility types实用类型

    interface IPerson2 {
       name: string
       age: number
    }
    let viking: IPerson2 = { name: 'viking', age: 20 }
    // partial,它可以把传入的类型都变成可选
    type IPartial = Partial<IPerson>
    let viking2: IPartial = {} // Partial 将IPerson 中的类型变成了可选类型 所以 viking2 可以等于一个空对象

    // Omit,它返回的类型可以忽略传入类型的某个属性
    type IOmit = Omit<IPerson2, 'name'> // 忽略name属性
    let viking3: IOmit = { age: 20 }

如果加上name属性将会报错:不能将类型“{ age: number; name: string; }”分配给类型“IOmit”。对象文字可以只指定已知属性,并且“name”不在类型“IOmit”中。


作者:不一213
来源:https://juejin.cn/post/7035563509882552334

0 个评论

要回复文章请先登录注册