1. class 类
① 基本使用
class Person {}
const p: Person
const p = new Person()
TS 中的 class,不仅提供了 class 的语法功能,同时也作为一种类型存在!
② 构造函数
class Person {
age: number
name: string
constructor(age: number, name: number) {
this.age = age
this.name = name
}
}
const p = new Person(21, '栈老师')
console.log(p.age, p.name)
③ 实例方法
class Person {
x = 10
test(n: number): void{
x *= n
}
}
④ 继承
class Animal {
move() {console.log("直走!")}
}
class Dog extends Animal {
bark() {console.log("汪汪汪!")}
}
const dog = new Dog()
子类 Dog 继承父类 Animal,则 Dog 的实例对象 dog 就同时具有了 Animal 和 Dog 的所有属性和方法!
⑤ 接口
interface Singable {
sing(): void
}
class Person implements Singable {
sing() {
console.log('sing~')
}
}
⑥ 可见性修饰符
可见性修饰符包括:公有的 public(公开)、受保护的 protected(仅对当前类及其子类可见)和私有的 private(只在当前类中可见)。
class Animal {
public move() {console.log("直走!")}
}
⑦ 只读修饰符
readonly:表示只读,用来防止在构造函数之外对属性进行赋值。
class Person {
readonly age: number = 18
constructor(age: number) {
this.age = age
}
}
只能修饰属性,不能修饰方法!
2. 类型兼容性
TS 采用的是结构化类型系统,类型检查时关注的是值所具有的形状,更准确地来说,y 的成员至少与 x 相同,则 x 兼容 y。(成员多的对象可以赋值给成员少的对象)
class Point {x: number; y: number}
class Point2D {x: number; y: number; z: number}
const p: Point = new Point2D()
接口之间的兼容性类似于 class,并且 class 和 interface 之间也是可以兼容的!
对于对象而言,成员多的对象可以赋值给成员少的对象,而对于函数来说恰好相反,它是参数少的函数可以赋值给参数多的函数。
3. 交叉类型
交叉类型,功能类似于接口继承,用于组合多个类型为一个类型。(常用于对象类型)
interface Person {name: string}
interface Contact {phone: string}
//相当于:type PersonDetail = {name: string; phone: string}
type PersonDetail = Person & Contact
let obj: PersonDetail = {
name: '栈老师',
phone: '198...'
}
交叉类型和接口继承都可以实现对象类型的组合,但是当遇到同名属性但类型不同时,接口继承会直接报错,而交叉类型不会报错。
4. 泛型
泛型是可以在保证类型安全的前提下,实现组件的复用,常用于函数、接口、class 中。
function test<Type>(value: Type): Type {
return value
}
const num: number = test<number>(10)
const str: string = test<string>('栈老师不回家')
其实,在调用泛型函数的时候,可以省略 <类型> 来简化泛型函数的调用,TS 内部会采用一种叫做类型参数推断的机制,可以根据传入的实参自动推断出类型变量 Type 的类型。
const num: number = test(10)
泛型的类型变量可以有多个,并且类型变量之间还可以约束!
function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key]
}
4.1 泛型工具类
① 可选
Partial<旧类型> 在旧类型的基础上构造出一个新类型,但该新类型的所有属性都是可选的。
interface Props {
id: number
color: number[]
}
type PartialProps = Partial<Props>
② 只读
Readonly<旧类型> 在旧类型的基础上构造出一个新类型,但该新类型的所有属性都是只读的。
type ReadonlyProps = Readonly<Props>
③ 挑选
Pick<旧类型,旧类型中的某些属性> 在旧类型的基础上构造出一个新类型,但该新类型的所有属性都是从旧类型中挑选出来的。
type PickProps = Pick<Props, 'id' | 'color'>
5. 索引签名类型
使用场景:当无法确定对象的属性名称或属性个数时,此时就会用到索引签名类型。
interface AnyObject {
//anyName可以是任意合法的变量名称,但变量名的类型已被限制
[anyName: string]: number
}
let obj: AnyObject = {
a: 1,
b: 2
}
6. 映射类型
基于旧类型创建新类型,减少重复,提升开发效率。
type PropKeys = 'x' | 'y' | 'z'
//Type1和Type2的结构完全相同
type Type1 = {x: number; y: number; z: number}
type Type2 = {[Key in PropKeys]: number}
注意映射类型只能在类型别名中使用,不能在接口中使用!
7. 索引查询类型
T[P] 用于查询属性的类型。
type Props = {a: number; b: string}
type TypeA = Props['a']
也可以同时查询多个索引类型。
//number | string
type TypeA = Props['a' | 'b']
还可以查询所有键的类型。
type TypeA = Props[keyof Props]