彻底搞懂TypeScript的类型定义

原始类型

文本

const value1 = ref<string>('我是文本')

数值

const value2 = ref<number>(100)

布尔

const value3 = ref<boolean>(false)

数组类型

两种写法:Array<string>string[](推荐写法)

const value4 = ref<Array<string>>(['213', 'aaa']) 

const value5 = ref<string[]>(['aaa', '123','bbb']) 

元组类型

[]用来约束数组的个数和指定索引对应的类型

const position = ref<[number, number]>([39.2031, 23.2302])

联合类型

|表示由两个或多个其他类型组成的类型,也可以是其中的任意一种类型

const value6 = ref<(string | number | boolean)[]>(['aaa', 111, 'bbb', true])

type类型别名

type关键字可以为任意类型起别名

type commonType = (string | number | boolean)[]
const value7 = ref<commonType>(['aaa', 111, 'bbb', true])

函数类型

指定函数参数返回值的类型

  1. 单独指定参数、返回值的类型
// 普通函数
function add(str: string, num: number): string {
  return str + num
}
// 箭头函数
const add = (str: string, num: number): string => {
  return str + num
}
  1. 同时指定参数、返回值的类型(仅适用于箭头函数),相当于在方法名和参数之间通过类似于箭头函数的写法为函数指定类型
const add: (str: string, num: number) => string = (str, num) => {
  return str + num
}

void类型

void 代表函数没有返回值

const sing= (str: string): void => {}

对象类型

直接使用{}描述对象结构,属性之间使用;(分号)分隔

const state = reactive<{ name: string; age: number; method(str: string): void }>({
  name: '张三',
  age: 18,
  method(str) {}
})

可选参数/属性

?代表可传或不传的参数/属性

// 可选参数
const add = (num1: number, num2?: number): void => { }
add(100)

// 可选属性
type commonType = {
    name: string
    age?: number
}
const val: commonType = {
    name: 'coco'
}

interface接口

interface关键字定义接口:指定一个可被多次使用的对象类型

interface commonInterface {
  name: string
  age?: number
}
const state = reactive<commonInterface>({ name: '张三' })

extends继承

extends关键字可继承接口的属性和方法

// 公共属性和方法
interface animal {
  name: string
  age: number
  say(str: string): void
}

// 特殊属性和方法
interface dog extends animal {
  leg: number
  jump(): void
}

const habaDog = reactive<dog>({
  name: '哈巴狗',
  age: 3,
  leg: 4,
  say(str) {},
  jump() {}
})

interface和type区别

相同:

  1. 都可以描述属性和方法
interface Animal {
    name: string
    say(): void
}

type Car = {
    name: string
    run(): void
}
  1. 都可以为对象指定类型
let obj1: Animal = { name: 'coco', say() { } }
let obj2: Car = { name: 'cici', run() { } }
  1. 都可以扩展
  • interface 使用 extends 实现
interface Animal {
    name: string
    say(): void
}

interface People extends Animal {
    age: number
}

let obj1: People = { name: 'coco', age: 4, say() { } }
  • type 使用 & 实现
type Car = {
    name: string
    run(): void
}

type Benz = Car & {
    wheel: number
}

let obj2: Benz = { name: 'cici', wheel: 4, run() { } }

不同:

  • interface 接口可以合并,type不能
interface Animal {
    name: string
}

interface Animal {
    age: number
}

let obj: Animal = { name: "coco", age: 18 }
  • type 可以为任意类型指定别名,联合类型、元组等,interface 不能
type anyType1 = string | number | boolean
type anyType2 = [string | number | boolean]

字面量类型

字面量类型:某个特定的字符串、数值等作为类型使用

const changeDirection = (direction: 'Up' | 'Down' | 'Left' | 'Right') => {}
const changeStatus = (status: true | false) => {}
changeDirection('Up')
changeStatus(false)

枚举类型

枚举类型:表示一组明确的可选值,类似于字面量类型+联合类型的组合
enum关键字定义一组命名常量,首字母大写,逗号分隔,成员初始值默认为从0开始递增的数值

enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT'
}
const changeDirection = (direction: Direction) => {
  console.log(direction)
}
changeDirection(Direction.Left)

typeof

typeof用来获取数据的类型,只能查询变量或者属性的类型

let arr = [1, 'aaa', 4]
let obj = {
  name: 'coco',
  age: 18
}
const value1 = ref<typeof arr>([100, 'bbb', 'aaa'])
const value2 = ref<typeof obj.name>('Tom')

class类

class的基本使用

  1. 声明成员变量
  2. 构造函数:成员初始化 ,通过this访问实例成员
  3. 实例方法
class Animal {
  name: string
  age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
  run(): void {}
}
const animal: Animal = new Animal('神秘物种', 100)

class继承(extends)

  • 通过extends关键字继承类的属性和方法
  • 通过super关键字调用父类的属性和方法
class Dog extends Animal {
  leg: number
  constructor(name: string, age: number, leg: number) {
    super(name, age)
    this.leg = leg
  }
  jump(): void {}
}
const habaDog: Dog = new Dog('哈巴狗', 3, 4)

class实现(implements)

implements关键字实现接口的属性和方法

interface Singer {
  name: string
  sing(): void
}

class Cat implements Singer {
  name: string = 'Tom'
  sing() {
    console.log('say Hi')
  }
}

class可见性修饰符

public

public关键字是默认可见性,可直接省略,表示公有的,公有属性和方法可以被任何地方访问

// 父类Animal公有属性name、公有方法say()
class Animal {
    public name: string
    constructor(name: string) {
        this.name = name
    }
    public say(str): void {
        console.log(str)
    }
}
const animal: Animal = new Animal('神秘物种')
console.log(animal.name)  // 神秘物种
console.log(animal.say('我会说话'))  // 我会说话

// 子类Dog 可以访问父类公有属性和方法
class Dog extends Animal {}
const dog: Dog = new Dog('哈巴狗')
console.log(dog.name)  // 哈巴狗
console.log(dog.say('我会汪汪汪'))  // 我会汪汪汪

protect

protect关键字表示受保护的,子类的方法内部可以通过this来访问父类的受保护的成员变量,实例对象不可访问

// 父类Animal受保护的属性name、受保护的方法say()
class Animal {
  protected name: string
  constructor(name: string) {
    this.name = name
  }
  protected say(str: string): void {
    console.log(str)
  }
}

class Dog extends Animal {
  // this关键字获取父类受保护的属性和方法
  bark(): void {
    console.log(this.name)
    this.say('汪汪汪')
  }
}
const dog: Dog = new Dog('哈巴狗')
// dog实例对象无法访问父类受保护的属性和方法
console.log(dog.bark())  

private

private关键字表示私有的,仅在当前类中可见,其实例对象和子类都不能访问

class Animal {
  private name: string
  constructor(name: string) {
    this.name = name
  }
  private say(str: string): void {
    console.log(str)
  }
}
const animal: Animal = new Animal('神秘物种')
console.log(animal.name)  // 报错,实例对象不可访问private属性
console.log(animal.say)  // 报错,实例对象不可访问private方法

readonly只读修饰符

readonly关键字修饰的属性是只读的,不可用来修饰方法,被赋值的属性值不能被修改

class Animal {
  readonly name: string
  constructor(name: string) {
    this.name = name
  }
}
interface Direction {
  readonly Up: string
}
const haba = reactive<{readonly direction:string}>({
  direction: 'Up'
})

类型兼容性

类兼容

  1. 只会比较实例成员,属性多的可以赋值给属性少
class Animal {
    public name!: string
}

class Cat {
    public name!: string
    public age!: string
}

let cat: Animal = new Cat()
console.log(cat)
  1. 不会比较类的静态成员和构造函数
class Animal {
    public name!: string
    constructor(name: string) { }
}

class Cat {
    public name!: string
    public static age: number
    constructor(name: string) { }
}

let cat: Cat = new Cat('coco')
let animal: Animal = new Animal('coco')
cat = animal
animal = cat
  1. 类的受保护属性和私有属性会影响兼容

受保护属性:

class Animal {
    protected name!: string
}

class Cat {
    protected name!: string
}

let cat: Cat = new Cat()
let animal: Animal = new Animal()
animal = cat  // 报错
cat = animal  // 报错

编译代码截图:
在这里插入图片描述

私有属性:

class Animal {
    private name!: string
}

class Cat {
    private name!: string
}

let cat: Cat = new Cat()
let animal: Animal = new Animal()
animal = cat  // 报错
cat = animal  // 报错

编译代码截图:
在这里插入图片描述

接口兼容

  1. 属性多的可以赋值给属性少的
interface Animal {
    name: string
    age: number
}
interface Dog {
    name: string
    age: number
    leg: number
}
let animal: Animal = { name: 'coco', age: 3 }
let dog: Dog = { name: 'coco', age: 3, leg: 4 }
animal = dog
  1. interfaceclass 可以相互兼容
interface Animal {
    name: string
    age: number
}
class Dog {
    name!: string
    age!: number
    leg!: number
}
let animal: Animal = new Dog()
console.log(animal)
  1. interfacetype 可以相互兼容
type Animal = {
    name: string
}

interface Car {
    name: string
}

let value1: Animal = { name: 'coco' }
let value2: Car = { name: 'cici' }
value1 = value2
value2 = value1

函数兼容

  1. 参数个数:参数少的可以赋值给参数多的,也可以将联合类型的赋值给具体类型
let f1 = (x: number) => { }
let f2 = (x: number, y: number) => { }
let f3 = (x: number | string) => { }
f2 = f1
f1 = f3
  1. 参数类型:相同位置的参数类型要相同
let f1 = (x: number) => { }
let f2 = (x: number) => { }
f2 = f1
f1 = f2
  1. 返回值类型:返回值类型要相同,也可以将具体类型的赋值给联合类型
let f1 = (): number => 123
let f2 = (): number => 456
let f3 = (): (number | string) => 'hello'
f1 = f2
f2 = f1
f3 = f1
  1. 函数重载:方法名相同,参数不同
function f1(x: number, y: number): number
function f1(x: string, y: string): string
function f1(x, y) {
    return x + y
}
f1(100, 200)
f1('aaa', 'bbb')
  1. 函数重载:重载多的的可以赋值给重载少的
function f1(x: number, y: number): number
function f1(x: string, y: string): string
function f1(x, y) {
    return x + y
}
function f2(x: number, y: number): number
function f2(x, y) {
    return x - y
}

let fn = f2
fn = f1

交叉类型

&关键字:类似于接口继承,用来组合多个类型为一个类型(常用于对象)

interface Teacher { name: string }
interface Class { no: string }
type Course = Teacher & Class
let obj: Course = {
    name: 'Tom',
    no: '301'
}

交叉类型与接口继承的区别

  • 相同: 都可以实现对象类型的组合
  • 不同:
    • 交叉类型(&):同名属性,类型不同时会合并类型
    • 接口继承(extends):同名属性,类型不同时会冲突

类型断言和类型保护

使用联合类型的变量时,通过 类型断言 或者 类型保护的方式,能够确切告诉编译器它是哪一种具体类型

类型断言

类型断言类似于类型转换,可以将一种类型强制转换成另外一种类型

<>

let value: any = "hello"
let len = (<string>value).length
console.log(len)

as

as 关键字断言变量的类型

let getValue = (): (string | number) => {
    let value = Math.random()
    return (value >= 0.5) ? 'hello' : 10.11
}

let value = getValue()
console.log(value)

if ((value as string).length) {
    console.log((value as string).length)
} else {
    console.log((value as number).toFixed())
}

类型保护

typeof

typeof 关键字用来说明变量的数据类型,返回值是一个字符串,只能使用 ===!== ,只能保护 string | number | boolean | bigint | symbol | undefined | function 类型
is 关键字一般用于函数返回值类型中,判断参数是否属于某一类型,返回值是布尔值

const getValue = (value: string | number): void => {
    if (typeof value === 'string') {
        console.log(value.length)
    } else {
        console.log(value.toFixed())
    }
}

getValue('hello')
getValue(100.11)

instanceof

instanceof 关键字用于判断一个变量是否属于某个对象的实例,返回值是布尔值

class Animal {
    name!: string
    constructor(name: string) {
        this.name = name
    }
}

class Cat {
    age!: number
    constructor(age: number) {
        this.age = age
    }

}

const getObject = (obj: Animal | Cat): void => {
    if (obj instanceof Cat) {
        console.log(obj.age)
    } else {
        console.log(obj.name)
    }
}

getObject(new Animal('coco'))
getObject(new Cat(4))

in

in 关键字检查对象是否存在一个特定的属性,使用该属性来区分不同的类型,通常返回值为布尔值

interface Animal {
    name: string
    leg: number
}

interface Car {
    name: string
    wheel: number
}

const getObject = (obj: Animal | Car): void => {
    if ('leg' in obj) {
        console.log(obj.leg)
    } else {
        console.log(obj.wheel)
    }
}
getObject({ name: 'coco', leg: 4 })

索引签名

数字索引签名

通过定义接口用来约束数组

interface Animal {
    [index: number]: string
}

let arr: Animal = ['cat', 'dog']
console.log(arr)

字符串索引签名

通过定义接口用来约束对象

interface Animal {
    [key: string]: string | number
}

let obj: Animal = {
    name: 'coco',
    age: 18,
}
console.log(obj)

never类型

never 类型表示那些永不存在的值的类型,一般用于抛出异常或不可能有返回值的函数

function error(msg: string): never {
    throw new Error(msg)
}
error('异常错误')

unknown类型

unknown 类型代表任何类型,被称作安全的 any

  1. 任何类型都可以赋值给 unknown 类型
let val: unknown
val = 100
val = 'hello'
val = [100, 'hello', false]
val = {
    name: 'coco',
    age: 18
}
  1. 不能将unknown类型赋值给其他类型,除非通过类型断言
let val: unknown = 18
let num: number
num = val  // 报错
num = <number>val
num = val as number

在这里插入图片描述

  1. 只能对 unknown 类型进行 ===!== 操作, 不能进行其它操作,除非通过类型断言
let val1: unknown = 100
let val2: unknown = 'hello'
console.log(val1 === val2)
console.log(val1 !== val2)

val1++  // 报错
(<number>val1)++
(val1 as number)++

在这里插入图片描述

  1. unknown与其他任何类型组成的交叉类型最后都是其他类型
let val: unknown = 100
type TestType1 = unknown & number
type TestType2 = unknown & string
let num: TestType1 = 123
let str: TestType2 = 'hello'
  1. unknown除了与any以外,与其他任何类型组成的联合类型最后都是unknown类型
let val: unknown = 100
type TestType1 = unknown | number | string | boolean
let obj: TestType1 = {
    name: 'coco'
}
  1. never 类型是 unknown 类型的子类型
type TestType = never extends unknown ? true : false

keyof unknown 等于 never

type TestType = keyof unknown
let val:TestType

在这里插入图片描述

  1. unknown 类型的值不能访问实例对象的属性和方法
class Animal {
    name!: string
    say(): void { console.log('hello') }
}

let a: unknown = new Animal()
a.name
a.say()

在这里插入图片描述

参考资料
https://www.bilibili.com/video/BV14Z4y1u7pi/

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值