彻底搞懂TypeScript的类型定义
vue3+ts的类型定义
彻底搞懂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])
函数类型
指定函数参数
和返回值
的类型
- 单独指定参数、返回值的类型
// 普通函数
function add(str: string, num: number): string {
return str + num
}
// 箭头函数
const add = (str: string, num: number): string => {
return str + num
}
- 同时指定参数、返回值的类型(仅适用于箭头函数),相当于在方法名和参数之间通过类似于箭头函数的写法为函数指定类型
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区别
相同:
- 都可以描述属性和方法
interface Animal {
name: string
say(): void
}
type Car = {
name: string
run(): void
}
- 都可以为对象指定类型
let obj1: Animal = { name: 'coco', say() { } }
let obj2: Car = { name: 'cici', run() { } }
- 都可以扩展
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的基本使用
- 声明成员变量
- 构造函数:成员初始化 ,通过
this
访问实例成员 - 实例方法
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'
})
类型兼容性
类兼容
- 只会比较实例成员,属性多的可以赋值给属性少
class Animal {
public name!: string
}
class Cat {
public name!: string
public age!: string
}
let cat: Animal = new Cat()
console.log(cat)
- 不会比较类的静态成员和构造函数
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
- 类的受保护属性和私有属性会影响兼容
受保护属性:
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 // 报错
编译代码截图:
接口兼容
- 属性多的可以赋值给属性少的
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
interface
和class
可以相互兼容
interface Animal {
name: string
age: number
}
class Dog {
name!: string
age!: number
leg!: number
}
let animal: Animal = new Dog()
console.log(animal)
interface
和type
可以相互兼容
type Animal = {
name: string
}
interface Car {
name: string
}
let value1: Animal = { name: 'coco' }
let value2: Car = { name: 'cici' }
value1 = value2
value2 = value1
函数兼容
- 参数个数:参数少的可以赋值给参数多的,也可以将联合类型的赋值给具体类型
let f1 = (x: number) => { }
let f2 = (x: number, y: number) => { }
let f3 = (x: number | string) => { }
f2 = f1
f1 = f3
- 参数类型:相同位置的参数类型要相同
let f1 = (x: number) => { }
let f2 = (x: number) => { }
f2 = f1
f1 = f2
- 返回值类型:返回值类型要相同,也可以将具体类型的赋值给联合类型
let f1 = (): number => 123
let f2 = (): number => 456
let f3 = (): (number | string) => 'hello'
f1 = f2
f2 = f1
f3 = f1
- 函数重载:方法名相同,参数不同
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')
- 函数重载:重载多的的可以赋值给重载少的
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
- 任何类型都可以赋值给 unknown 类型
let val: unknown
val = 100
val = 'hello'
val = [100, 'hello', false]
val = {
name: 'coco',
age: 18
}
- 不能将unknown类型赋值给其他类型,除非通过类型断言
let val: unknown = 18
let num: number
num = val // 报错
num = <number>val
num = val as number
- 只能对 unknown 类型进行
===
或!==
操作, 不能进行其它操作,除非通过类型断言
let val1: unknown = 100
let val2: unknown = 'hello'
console.log(val1 === val2)
console.log(val1 !== val2)
val1++ // 报错
(<number>val1)++
(val1 as number)++
- unknown与其他任何类型组成的交叉类型最后都是其他类型
let val: unknown = 100
type TestType1 = unknown & number
type TestType2 = unknown & string
let num: TestType1 = 123
let str: TestType2 = 'hello'
- unknown除了与any以外,与其他任何类型组成的联合类型最后都是unknown类型
let val: unknown = 100
type TestType1 = unknown | number | string | boolean
let obj: TestType1 = {
name: 'coco'
}
- never 类型是 unknown 类型的子类型
type TestType = never extends unknown ? true : false
keyof unknown
等于 never
type TestType = keyof unknown
let val:TestType
- unknown 类型的值不能访问实例对象的属性和方法
class Animal {
name!: string
say(): void { console.log('hello') }
}
let a: unknown = new Animal()
a.name
a.say()
更多推荐
所有评论(0)