目录
1.type
type 可以为任意类型创建别名,让代码更简洁,可读性更强,同时能更方便的进行类型复用和扩展。
1.基本用法
type num = number;
let price: num
price = 100
2.联合类型
type Status = number | string
type Gender = '男' | '⼥'
function printStatus(status: Status) {
console.log(status)
}
function logGender(str: Gender) {
console.log(str)
}
printStatus(404)
printStatus('200')
printStatus('501')
logGender('男')
logGender('⼥')
3.交叉类型
//⾯积
type Area = {
height: number //⾼
width: number //宽
}
//地址
type Address = {
num: number //楼号
cell: number //单元号
room: string //房间号
}
// 定义类型House,且House是Area和Address组成的交叉类型
type House = Area & Address
const house: House = {
height: 180,
width: 75,
num: 6,
cell: 3,
room: '702'
}
2.属性修饰符
1.public 属性修饰符
class Person {
// name写了public修饰符,age没写修饰符,最终都是public修饰符
public name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
speak() {
// 类的【内部】可以访问public修饰的name和age
console.log(`我叫:${this.name},今年${this.age}岁`)
}
}
const p1 = new Person('张三', 18)
// 类的【外部】可以访问public修饰的属性
console.log(p1.name)
class Student extends Person {
constructor(name: string, age: number) {
super(name, age)
}
study() {
// 【⼦类中】可以访问⽗类中public修饰的:name属性、age属性
console.log(`${this.age}岁的${this.name}正在努⼒学习`)
}
}
属性的简写形式
class Person {
constructor(
public name: string,
public age: number
) {}
}
2.proteced 属性修饰符
class Person {
// name和age是受保护属性,不能在类外部访问,但可以在【类】与【⼦类】中访问
constructor(
protected name: string,
protected age: number
) {}
// getDetails是受保护⽅法,不能在类外部访问,但可以在【类】与【⼦类】中访问
protected getDetails(): string {
// 类中能访问受保护的name和age属性
return `我叫:${this.name},年龄是:${this.age}`
}
// introduce是公开⽅法,类、⼦类、类外部都能使⽤
introduce() {
// 类中能访问受保护的getDetails⽅法
console.log(this.getDetails())
}
}
const p1 = new Person('杨超越', 18)
// 可以在类外部访问introduce
p1.introduce()
// 以下代码均报错
// p1.getDetails()
// p1.name
// p1.age
class Student extends Person {
constructor(name: string, age: number) {
super(name, age)
}
study() {
// ⼦类中可以访问introduce
this.introduce()
// ⼦类中可以访问name
console.log(`${this.name}正在努⼒学习`)
}
}
const s1 = new Student('tom', 17)
s1.introduce()
3.private 属性修饰符
class Person {
constructor(
public name: string,
public age: number,
// IDCard属性为私有的(private)属性,只能在【类内部】使⽤
private IDCard: string
) {}
private getPrivateInfo() {
// 类内部可以访问私有的(private)属性 —— IDCard
return `身份证号码为:${this.IDCard}`
}
getInfo() {
// 类内部可以访问受保护的(protected)属性 —— name和age
return `我叫: ${this.name}, 今年刚满${this.age}岁`
}
getFullInfo() {
// 类内部可以访问公开的getInfo⽅法,也可以访问私有的getPrivateInfo⽅法
return this.getInfo() + ',' + this.getPrivateInfo()
}
}
const p1 = new Person('张三', 18, '110114198702034432')
console.log(p1.getFullInfo())
console.log(p1.getInfo())
// 以下代码均报错
// p1.name
// p1.age
// p1.IDCard
// p1.getPrivateInfo()
4.readonly 属性修饰符
class Car {
constructor(
public readonly vin: string, //⻋辆识别码,为只读属性
public readonly year: number, //出⼚年份,为只读属性
public color: string,
public sound: string
) {}
// 打印⻋辆信息
displayInfo() {
console.log(`
识别码:${this.vin},
出⼚年份:${this.year},
颜⾊:${this.color},
⾳响:${this.sound}
`)
}
}
const car = new Car('1HGCM82633A123456', 2018, '⿊⾊', 'Bose⾳响')
car.displayInfo()
// 以下代码均错误:不能修改 readonly 属性
// car.vin = '897WYE87HA8SGDD8SDGHF';
// car.year = 2020;
3.抽象类
简记:抽象类不能被实例化,其意义是可以被继承,抽象类里可以有普通方法,也可以有抽象方法。
通过以下场景,理解抽象类:
我们定义一个抽象类
Package
,表示所有包裹的基本结构,任何包裹都有重量属性weight
,包裹需要计算费用。但不同类型的包裹(如:标准速度,特快专递)都有不同的计算方式,因此用于计算费用的calculate
方法是一个抽象方法,必须由具体的子类来实现。
abstract class Package {
constructor(public weight: number) {}
// 抽象⽅法:⽤来计算运费,不同类型包裹有不同的计算⽅式
abstract calculate(): number
// 通⽤⽅法:打印包裹详情
printPackage() {
console.log(`包裹重量为: ${this.weight}kg,运费为: ${this.calculate()}元`)
}
}
// 标准包裹
class StandardPackage extends Package {
constructor(
weight: number,
public unitPrice: number // 每公⽄的固定费率
) {
super(weight)
}
// 实现抽象⽅法:计算运费
calculate(): number {
return this.weight * this.unitPrice
}
}
// 创建标准包裹实例
const s1 = new StandardPackage(10, 5)
s1.printPackage()
class ExpressPackage extends Package {
constructor(
weight: number,
private unitPrice: number, // 每公⽄的固定费率(快速包裹更⾼)
private additional: number // 超出10kg以后的附加费
) {
super(weight)
}
// 实现抽象⽅法:计算运费
calculate(): number {
if (this.weight > 10) {
// 超出10kg的部分,每公⽄多收additional对应的价格
return 10 * this.unitPrice + (this.weight - 10) * this.additional
} else {
return this.weight * this.unitPrice
}
}
}
// 创建特快包裹实例
const e1 = new ExpressPackage(13, 8, 2)
e1.printPackage()
像是这样的形式我自己有自己的理解形式:
好比如我们走路,起点都是一样的,终点也是一样的,唯独我们的过程是不一样的,有的骑车,有的走路等等,但是这多种方式我们就可以写成继承的方式,那么我们总共花费的时间就可以写在这个抽象类里面。
4.interface
1.定义类结构
interface
是一种定义结构的方式,主要作用是为:类,对象,函数等规定一种契约,这样可以确保代码的一致性和类型安全,但要注意interface
只能定义格式,不能包含任何实现!
// PersonInterface接⼝,⽤与限制Person类的格式
interface PersonInterface {
name: string
age: number
speak(n: number): void
}
// 定义⼀个类 Person,实现 PersonInterface 接⼝
class Person implements PersonInterface {
constructor(
public name: string,
public age: number
) {}
// 实现接⼝中的 speak ⽅法
speak(n: number): void {
for (let i = 0; i < n; i++) {
// 打印出包含名字和年龄的问候语句
console.log(`你好,我叫${this.name},我的年龄是${this.age}`)
}
}
}
// 创建⼀个 Person 类的实例 p1,传⼊名字 'tom' 和年龄 18
const p1 = new Person('tom', 18)
p1.speak(3)
2.定义对象结构
interface UserInterface {
name: string
readonly gender: string // 只读属性
age?: number // 可选属性
run: (n: number) => void
}
const user: UserInterface = {
name: '张三',
gender: '男',
age: 18,
run(n) {
console.log(`奔跑了${n}⽶`)
}
}
3.定义函数结构
interface CountInterface {
(a: number, b: number): number
}
const count: CountInterface = (x, y) => {
return x + y
}
4.接口之间的继承
interface PersonInterface {
name: string // 姓名
age: number // 年龄
}
interface StudentInterface extends PersonInterface {
grade: string // 年级
}
const stu: StudentInterface = {
name: '张三',
age: 25,
grade: '⾼三'
}
5.接口自动合并
// PersonInterface接⼝
interface PersonInterface {
// 属性声明
name: string
age: number
}
// 给PersonInterface接⼝添加新属性
interface PersonInterface {
// ⽅法声明
speak(): void
}
// Person类实现PersonInterface
class Person implements PersonInterface {
name: string
age: number
// 构造器
constructor(name: string, age: number) {
this.name = name
this.age = age
}
// ⽅法
speak() {
console.log('你好!我是⽼师:', this.name)
}
}
5. interface和type的区别
- 相同点:
interface
和type
都可以定义对象结构,在定义对象结构时两者可以互换。 - 不同点:
interface
:更专注于定义对象和类的结构,支持继承,合并。type
:可以定义类型别名,联合类型,交叉类型,但不支持继承和自动合并。
6. interface与抽象类的区别
- 相同点:都能定义一个类的格式(定义类应遵循的契约)
- 不同点:
- 接口:只能描述结构,不能有任何代码实现,一个类可以实现多个接口
- 抽象类:既可以包含抽象方法,也可以包含具体方法,一个类只能继承一个抽象类