TypeScript 类型查阅笔记

99 阅读7分钟

TypeScript常用类型

TS中常用基础类型细分为 1.JS已有类型;2.TS新增类型

JS已有类型

  • 原始类型:number/string/boolean/null/undefined/symbol
  • 对象类型:object(包括数组、对象、函数等)

TS新增类型

联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any等

TypeScript 类型运用

原始类型

let age : number = 18
let name: string = '小明'

对象类型

对象类型

  • 对象的类型就是在描述对象的结构(有什么类型的属性和方法)
//属性类型之间用 ; 分隔
let person = {name: string; age: number; sayHi(tip: string): void} = {
    name : 'jay',
    age  : 18,
    sayHi(tip){}
}

//可以用换行来去掉 ; 分隔
let person = {
    name: string
    age: number
    sayHi: (tip: string) => void //也可以用箭头函数
} = {
    name : 'jay',
    age  : 18,
    sayHi(tip){}
}
  • 对象可选属性
 function myAxios(config: {url: string; method? :string }) {
     console.log(config)
 }
 
 myAxios({
     url: ''
 })
 
 myAxios({
     url: '',
     method : ''
 })

数组

let numbers : number[] = [1,2,3]
let strings : string[] = ['1','2','3']
let arr : (number|string)[] = [1,2,'3','4']

函数类型

函数的类型实际上指的是:函数的参数和返回值的类型

  • 单独指定参数和返回值的数据类型
function Fun1(num1 : number,num2 : number) : number {
    return num1 + num2
}

const Fun1 = (num1 : number,num2 : number) : number => {
    return num1 + num2
}
  • 同时指定参数和返回值的数据类型
const Fun1 : (num1 : number,num2 : number) => number = (num1,num2) => {
    return num1 + num2
}
  • 函数没有返回值,用void
function Fun1(num1 : number,num2 : number) : void {
    console.log( num1 + num2 )
}
  • 函数的参数可选 可选参数:在可传可不传的参数名称后面添加 ?(问号)

注:可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数

function Fun1(num1 : number,num2? : number) : void {
    console.log( num1 + num2 )
}

Fun1(1)
Fun1(1,2)

联合类型

定义:由两个或多个其他类型组成的类型,表示可以是这些类型中的任意一种(注:中间用 | 隔开)

let arr : (number|string)[] = [1,2,'3','4']
let arr : number |string[] = 1  //注意,有无()

自定义类型(类型别名)

用type关键字自定义一种类型,可以多次被使用,简化类型的使用

type customarrary = (number|string)[]

let arr1 : customarrary = [1,'2',3]
let arr2 : customarrary = ['1','2',3]

接口(interface)

定义:当一个对象类型被多次使用时,一般会使用 接口(interface) 来描述对象的类型,达到复用的目的

interface CustomPerson {
    name : string
    age  : number
    sayHi() : void
}

let person1 : CustomPerson = {
    name : 'person1',
    age  : 18,
    sayHi('你好'){}
}
let person2 : CustomPerson = {
    name : 'person2',
    age  : 20,
    sayHi('你好2){}
}

接口继承(extends)

如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用

interface Point1 {
    x : number
    y : number
}

interface Ponit2 {
    x : number
    y : number
    z : number
}

//用继承
interface Point1 {
    x : number
    y : number
}

interface Ponit2 extends Point1 {z : number} // Ponit2继承了Ponit1的所有属性和方法,且拥有z属性

类型别名(type)和 接口(interface)的对比

  • 相同点: 都可以为对象指定类型
  • 不同点:
    • 接口,只能为对象指定类型
    • 类型别名,不仅可以为对象指定类型,还可以为任意类型指定别名
    • 类型别名的声明方式是赋值,用=
    • 接口的声明方式直接跟 {}

元组(Tuple)

定义: 是另一种类型的数组,它可以确切地知道包含多少个元素,以及特定索引对应的类型。

//例如表示确切经纬度
let position : [number, number] = [39.5427, 116.2317]

类型断言(as)

使用 as 关键字,后面跟一个更加具体的类型,使变量类型变得更加具体

const alink = document.getElementById('link') as HTMLAnchorElement

技巧:在浏览器控制台,通过console.dir()打印DOM元素,在属性列表的最后面,即可看到该元素的类型。

字面量类型

使用模式:字面量类型配合联合类型一起使用。

使用场景:用来表示一组明确的可选值列表。

优势: 相比于string类型,使用字面量类型更加精确、严谨。

function changeDirection( direction: 'up'|'down'|'left'|'right' ) {
  console.log(direction)
}

枚举类型(enum)

定义: 定义一组命名常量。枚举不仅用作类型,还提供值(枚举成员都是有值的)

使用规范: 约定枚举名称、枚举中的值以大写字母开头,用 ,(逗号)分隔

引用枚举: 直接通过点(.)语法访问枚举成员

enum Direction { Up, Down, Left, Right }
function changeDirection( direction: Direction ) {}

changeDirection( Direction.Up )

数字枚举:枚举成员为数字的枚举

注意: 枚举成员是有值的,默认为: 从0开始自增的数值

// Up=0;Down=1Left=2Right=3;
enum Direction { Up, Down, Left, Right }

// Down=11Left=12Right=13;
enum Direction { Up=10, Down, Left, Right }

// Right=17;
enum Direction { Up=10, Down=14, Left=16, Right }

字符串枚举:枚举成员为字符串的枚举

注意: 字符串枚举没有自增长行为,字符串枚举的每个成员必须有初始值

enum Direction { 
    Up = 'UP', 
    Down = 'DOWN', 
    Left = 'LEFT', 
    Right = 'RIGHT' 
}

TS中的typeof运算符

  • TS中的typeof与JS中的typeof是不一样的
  • TS中的typeof可以用来获取上下文中的变量类型
let p={ x: 1,y: 2 }
let a = typeof p.x //number
  • TS中的typeof只能用来查询变量或属性的类型,无法查询其他形式的类型(比如:函数调用的类型)

TypeScript 高级类型

TS中的高级类型有:class类、类型兼容性、交叉类型、泛型和keyof、索引签名类型和索引查询类型、映射类型

class类

class Person {
    age : number
    gender = '男'
}
const p = new Person() //创建一个实例
p.age
p.gender

构造函数(注:构造函数无返回值)

class Person {
    age : number
    gender = '男'
    
    // 构造函数
    constructor(age: number, gender: string) {
        this.age = age
        this.gender = gender
    }
}

const p = new Person(18,'男') //创建一个实例

p.age
p.gender

类的实例方法

class Ponit {
    x = 1
    y = 2
    
    //实例方法
    scale(n: number): void {
       this.x *= n
       this.y *= n
    }
}
const p = new Ponit()
p.scale(2)

console.log(p.x,p.y)  // x=2,y=4

类的继承

类的继承有两种方式:1.extends(继承父类);2.implements(实现接口)

  • extends(继承父类)
class A {
    move () {console.log('a')}
}

// B继承了A,也拥有了A.move()
class B extends A {
    bark() {console.log('b')}
}

const b = new B()
b.move()
b.bark()
  • implements(实现接口)
interface A {
    sing(): void
    name: string
}

// B类实现接口A意味着:B类中必须要提供接口A中指定的所有方法和属性
class B implements A {
    name: 'b'
    sing() {
        console.log('a')
    }
}

类成员可见性

类里面的属性和方法对外部分可见

可见性修饰符:

  1. public(公有的),默认的,可省略
  2. protected(受保护的),仅对其声明所在类和子类中(非实例对象)可见
class A {
   // 受保护的方法
   protected move () {console.log('a')}
   
   sing() {
       this.move() //可调用
   }
}

// B继承了A,也拥有了A.move()
class B extends A {
    bark() {console.log('b')}
    
    this.move() //可调用
}

const b = new B()
b.move() //不可调用
  1. private(私有的),只在当前类中可见,对实例对象以及子类均不可见
  2. readonly(只读),表示只读,用来防止在构造函数之外对属性进行赋值
//类
class Person {
    readonly age: number =18
    constructor(age: number) {
        this.age = age
    }
}

//接口
interface A {
    readonly name: string
}

//对象类型
let obj = { readonly name: string} = {
    name = 'a'
}

注:

  1. 属性age后面的类型注解(比如:此处的number)如果不加,则age的类型为18(字面量类型)。
  2. readonly修饰符修饰的类型必须要有明确的类型注解。
  3. readonly只修饰属性,不修饰方法。
  4. readonly可以修饰接口或者{}表示的对象类型。

类型兼容性

TS是结构化类型系统(Structural Type System):类型检查关注的是值所具有的形状。

对象类型的兼容性

注:成员多的赋值给成员少的

class Ponit{x: number; y: number}
class Ponit2D {x: number; y: number}
class Ponit3D {x: number; y: number; z: number}

const Point = new Ponit2D
const Point = new Ponit3D

//错误赋值
const Ponit3D = new Ponit2D

接口的兼容性

接口之间的兼容性和class类似。并且,class 和interface之间也可以兼容

interface Ponit{x: number; y: number}
interface Ponit2D {x: number; y: number}
interface Ponit3D {x: number; y: number; z: number}

let p1: Ponit
let p2: Ponit2D
let p3: Ponit2D

p1= p2
p1= p3

//错误赋值
// p3 = p1

//接口与类class之间也可以兼容
class Point4D{x: number; y: number; z: number}
p1 = new Point4D()

函数的兼容性

函数的兼容性比较复杂,需要考虑以下几个因素:

  1. 参数的个数 (参数少的可以赋值给参数多的,与对象和接口相反)
  2. 参数的类型
  3. 返回值类型
type F1 = (a: number)=> void
type F2 = (a: number, b: number)=> void
let f1: F1
let f2: F2

f2 = f1
// 错误示范
// f1 = f2