高级类型
class 类
🟢 TS 中的 class
不仅仅提供 class
语法功能,也作为一种类型存在
🟠 实例属性初始化
class Person {
age: number
gender: '男'
}
🟠 构造函数
class Person {
age: number
gender: string
constructor(age: number, gender: string) {
this.age = age
this.gender = gender
}
}
注意
成员初始化后才能通过 this.
访问实例成员
需要为构造函数指定类型注解,否则会推断为 any
构造函数不需要返回值
🔵 实例方法
class Point {
x = 1
y = 2
scale(n: number): void {
this.x *= n
this.y *= n
}
}
🟣 继承
实现继承:extends
(继承父类) impelments
(实现接口)
说明
JS 中只有 extends
, impelments
是由 TS 提供
🟡 继承父类
class Animal {
move() {
console.log('moving along !')
}
}
class Dog extends Animal {
bark() {
console.log('wang wang wang !!')
}
}
const dog = new Dog()
dog.move()
dog.bark()
🟡 实现接口
interface Singable {
sing(): void
}
class Man implements Singable {
sing(): void {
console.log('hhhhhhhh!!')
}
}
🟠 可见性修饰符
1️⃣ public
共有成员可以被任何地方访问,public
是默认的可以省略
class Animal {
public move() {
console.log('moving along !')
}
}
2️⃣ protected
受保护的,仅对声明所在类和子类可见 子类方法内部通过 this
访问
class Animal {
// 受保护的方法
protected move() {
console.log('走!')
}
run() {
this.move()
console.log('跑!')
}
}
const a = new Animal()
a.run()
// a.move() 不可访问
class Dog extends Animal {
bark() {
this.move()
console.log('狗叫!')
}
}
const d = new Dog()
d.run()
d.bark()
// d.move() 不可访问
3️⃣ private
私有的,只在当前类可见,实例对象以及子类不可见
class Animal {
private __move__() {
console.log('private 方法')
}
move() {
this.__move__() //可以访问
console.log('走!')
}
run() {
console.log('跑!')
}
}
const a = new Animal()
// a.__move__() 私有,不可在外部访问
class Dog extends Animal {
bark() {
// this.__move__() 私有,不可在外部访问
console.log('狗叫!')
}
}
const d = new Dog()
// d.__move__() 私有,不可在外部访问
4️⃣ readonly
只读 防止在构造函数之外对属性进行赋值
class Person {
readonly age: number = 18
constructor(age: number) {
this.age = age
}
setAge(age: number) {
// this.age = age age为只读属性
}
}
说明
readonly
修饰的属性,必须手动提供明确的类型
类型兼容
类型系统有:
🟢 Structural Type System (结构化类型系统)
🟢 Nominal Type System (标明类型系统)
TS 采用的是结构化类型系统,类型检查关注的是值所具有的形状
在结构系统中,如果两个对象具有相同的形状,则认为是同一类型
成员多的可以赋值给少的
class
interface
之间也可以兼容
class Point {
x: number
y: number
}
class Point2D {
x: number
y: number
}
const p: Point = new Point2D()
🟥 函数之间的兼容性
函数兼容性要考虑:参数个数、参数类型、返回值类型
1️⃣ 参数个数
参数少的可以赋值给参数多的
type F1 = (a: number) => void
type F2 = (a: number, b: number) => void
let f1: F1 = function () {}
let f2: F2 = f1
2️⃣ 参数类型
相同位置的参数类型要相同或兼容
// 原始类型 类型要保持一致
type F1 = (a: number) => String
type F2 = (a: number) => String
let f1: F1 = function () {
return 'ok'
}
let f2: F2 = f1
interface Point2D {
x: number
y: number
}
interface Point3D {
x: number
y: number
z: number
}
type F2 = (p: Point2D) => void
type F3 = (p: Point3D) => void
let f2: F2 = function () {}
let f3: F3 = f2
3️⃣ 返回值类型
多的可以给少的
总结
对象-多赋值少
函数参数个数-少赋值多
函数参数类型-原始类型必须相同,对象类型把对象拆开看成参数,少的可以赋值多的
函数返回值-多赋值少
交叉类型
使用 &
类似于接口继承,用于组合多个类型为一个类型
interface Person {
name: string
}
interface Contcat {
phone: string
}
type PersonDetail = Person & Contcat
let obj: PersonDetail = {
name: 'tom',
phone: '110'
}
& VS extends 对比
相同点:都可以实现对象类型的组合
不同:对于同名属性之间处理类型冲突不同
接口继承
// 类型不兼容
// error
interface A {
age: number
}
interface B extends A {
age: string
}
交叉类型
interface A {
age: number
}
interface B {
age: string
}
type C = A & B
// 等价于
age: string | number
keyof
泛型和 创建泛型函数
function id<type>(value: type): type {
return value
}
const num = id<number>(10)
let str = id('hello')
说明
在函数名称后面加<>
,在里面添加类型变量<T>
类型变量是特殊类型的变量
泛型约束
不添加约束无法访问值的任何属性
添加约束
interface ILength {
length: number
}
function id<T extends ILength>(value: T): T {
value.length
return value
}
// let num = id(10)
let str = id('hello')
keyof
例子:创建一个函数获取对象中属性的值
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
let person = { name: 'tom', age: 18 }
getProp(person, 'age')
说明
keyof
接收一个对象类型,生成键名称的联合类型
本例中 K 受 T 约束,K 只能是 T 所有键中的任意一个
泛型接口
interface IdFunc<T> {
id: (value: T) => T
ids: () => T[]
}
let obj: IdFunc<string> = {
id(value) {
return value
},
ids() {
return ['a']
}
}
说明
接口的类型变量对接口中所有成员可见
使用泛型接口时需要显示指定类型
泛型工具类型
🟠 Partial<Type>
用来构造一个类型,将 Type 的所有属性设置为可选
interface Props {
id: string
children: number[]
}
type PartialProps = Partial<Props>
// 所有属性都为必填
let MyProps: Props = {
id: 'aaa',
children: [1, 2]
}
// 所有属性变为可选
let MyPartialProps: PartialProps = {
id: 'aa'
}
🟠 Readonly<Type>
构造一个类型,将 Type 所有属性设置为只读
interface People {
name: string
age: number
}
type ReadonlyPeople = Readonly<People>
let Tom: ReadonlyPeople = {
name: 'Tom',
age: 20
}
// 无法分配到 "age" ,因为它是只读属性
// Tom.age = 21
🟠 Pick<Type, Keys>
从 Type 里面选择一组属性来构造新类型
interface Text {
id: number
title: string
author: string
}
type PickText = Pick<Text, 'id' | 'author'>
let MyPickText: PickText = {
id: 1,
author: 'tom'
}
说明
Type:
选择谁的属性
Keys:
选择那些属性
第二个类型变量传入的属性只能是第一个类型变量存在的属性
🟠 Record<Keys,Type>
构造一个对象类型,属性键为Keys
属性类型为Type
type RecordObj = Record<'id' | 'name' | 'age', string[]>
let Obj: RecordObj = {
id: ['1'],
name: ['1'],
age: ['1']
}
说明
创建的类型里的属性类型都是一致的
索引签名类型 和 索引查询类型
索引签名类型
使用场景:无法确定对象中有哪些属性
interface AnyObj {
[key: string]: number | string
}
let Obj: AnyObj = {
1: 1,
aaa: '111'
}
说明
使用 [key: string]
约束接口中允许出现的属性名,表示只要是string
类型的都可以
可以出现任意多个
索引查询类型
作用:查询属性的类型
type Props = {
a: number
b: string
c: boolean
}
type PropsA = Props['a']
type PropsAB = Props['a' | 'b']
type PropsAll = Props[keyof Props]
映射类型
Partial<Type>
实现原理
type Partial<T> = {
[P in keyof T]?: T[P]
}
interface Props {
id: string
children: number[]
}
type PartialProps = Partial<Props>
说明
keyof T
=> keyof Props
表示获取 Props 所有的键 'id'|'children'
[]?
,表示变为可选属性
T[P]
表示获取 T 中每个键对应的类型