接口和类
类实现接口
这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战
基本使用
简单使用
class Person {
// 这里定义的是实例中的name和age的类型
name: string
age: number
// 这里定义的是构造函数参数的数据类型
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
继承
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
class Student extends Person {
sno: string
constructor(name: string, age: number, sno: string) {
super(name, age)
this.sno = sno
}
}
修饰符
| public | 公共的,在子类和类定义外部都可以使用 | 缺省值 |
|---|---|---|
| protected | 在子类中可以访问,在类定义外部无法访问 | |
| private | 私有的,只能在类的内部进行使用,类的外部和子类中都无法访问 | |
| readonly | 定义只读属性 |
public
class Parent {
// 不写默认就是public
name: string
constructor(name: string) {
// public属性可以在类自身被访问
this.name = name
}
}
class Child extends Parent{
constructor(name: string) {
super(name)
}
printName() {
// public属性可以在子类中被访问
console.log(this.name)
}
}
const childInstance = new Child('Klaus')
// public属性可以在类定义外部被访问
console.log(childInstance.name) // => Klaus
childInstance.printName() // => Klaus
protected
class Parent {
protected name: string
constructor(name: string) {
// private属性可以在类自身中被使用
this.name = name
}
}
class Child extends Parent{
constructor(name: string) {
super(name)
}
printName() {
// protected属性可以在子类中被访问
console.log(this.name)
}
}
const childInstance = new Child('Klaus')
// protected属性不可以在类的定义外部被访问
// console.log(childInstance.name) // error
childInstance.printName() // => Klaus
class Parent {
protected name: string
// 当使用protected修饰符限制构造函数
// 表明这个类只能被继承不能被实例化
protected constructor(name: string) {
this.name = name
}
}
class Child extends Parent{
constructor(name: string) {
super(name)
}
printName() {
console.log(this.name)
}
}
// console.log(new Parent('Alex')) // error
private
class Parent {
private name: string
constructor(name: string) {
// private属性可以在类自身中被使用
this.name = name
}
}
class Child extends Parent{
constructor(name: string) {
super(name)
}
printName() {
// private属性不可以在子类中被访问
// console.log(this.name) // error
}
}
const childInstance = new Child('Klaus')
// protected属性不可以在类的定义外部被访问
// console.log(childInstance.name) // error
class Parent {
private name = 'Klaus'
}
const per = new Parent()
// TS只是编译的时候,对代码的类型进行静态分析,并不会实际执行代码
// 所以TS中的私有属性,只是尽可能阻止你使用该属性
// 并不是将这个属性真正变成私有的了
console.log(per) // => { name: 'Klaus' }
readonly
class Parent {
// name属性是只读属性
readonly name: string
constructor(name: string) {
this.name = name
}
}
const instance = new Parent('Klaus')
// 使用readonly修饰的属性是只读属性,无法被修改
// instance.name = 'Alex' // error
参数属性
class Parent {
// 在这里对实例属性进行修饰
protected readonly name: string
constructor(name: string) {
this.name = name
}
}
const instance = new Parent('Klaus')
但是在TS中,类的属性修饰和定义其实是可以使用语法糖放置到一起的,而这个语法糖就被称之为参数属性
class Parent {
// 定义参数属性
constructor(protected readonly name: string) {
this.name = name
}
}
const instance = new Parent('Klaus')
静态属性
class Parent {
// 定义公共的静态属性username
public static username = 'Klaus'
}
console.log(Parent.username) // => Klaus
可选属性
class Parent {
name: string // name是必传属性
age?: number = 18 // age是可选属性 默认值是18
// uid属性是可选的 默认值是undefined
constructor(name: string, age?: number, public uid?: string) {
this.name = name
// 这里其实是显示的将undefined赋值给了实例属性age
// 所以在输出结果的时候,age的属性值为undefined
this.age = age
}
}
console.log(new Parent('Klaus')) // => { uid: undefined, age: undefined, name: 'Klaus' }
存取器
class Person {
private _name: string = ''
get name() {
return this._name
}
set name(value: string) {
this._name = value
}
}
const per = new Person()
per.name = 'Klaus'
console.log(per.name) // => Klaus
抽象类
抽象类只能被子类继承,不能被实例化
抽象类可以用来约束子类中必须存在的属性或方法
一个抽象类中可以有抽象属性和抽象方法,也可以同时存在存在实现的属性和方法
一个抽象类可以继承自另一个抽象类,此时父抽象类的抽象方法或抽象属性可以不在子抽象类中实现
abstract class Parent {
// 抽象方法定义格式
// abstract [属性描述符](参数列表): 返回值类型
abstract print(value?: string): void
}
// 抽象子类可以不实现也可以实现抽象父类中的抽象属性或方法
abstract class Child extends Parent {
pirntChildName() {
console.log(Child.name)
}
}
// 如果一个类继承自抽象类,则该类必须实现抽象类中的属性和方法
class Instance extends Child {
print(value: string) {
console.log(value)
}
}
const inst = new Instance()
inst.print('Hello TypeScript')
inst.pirntChildName()
abstract class Parent {
abstract print(value?: string): void
abstract age: number
// 在类中(包括抽象类)如果一个私有属性没有在构造函数中被赋值
// 那么就一定需要被初始化
private _name:string = ''
abstract get name(): string
// 特别的: 对于属性访问器在定义类型的时候
// 不可以添加返回值的类型标注
abstract set name(value: string)
}
class Child extends Parent {
name: string
age: number
constructor(name: string, age: number) {
super()
this.name = name
this.age = age
}
print(value: string) {
console.log(value)
}
}
类类型
class Person {
name: string
constructor(name: string) {
this.name = name
}
}
// 此时per的类型就是Person
// 即Person即是类型又是值
let per = new Person('Klaus')
class Animal extends Person {
age: number
constructor(name: string, age: number) {
super(name)
this.age = age
}
}
// per的类型是Person
// Animal是Person子类的类型
// 所以符合类型兼容性,可以被赋值
per = new Animal('Dog', 8)
类实现接口
我们可以让一个类实现某个接口,从而通过该接口来约束对应的实例结构
interface IPerson {
name: string
}
class Person implements IPerson {
name: string = ''
}
接口继承类
class Person {
name: string = ''
}
interface IFoo extends Person {}
// 等价于
/*
interface IFoo {
name: string
}
*/
const foo: IFoo = {
name: 'Klaus'
}
class Person {
protected name: string = ''
}
// 类中的受保护属性也会被类继承实现
// 但此时这个接口就只能给这个类本身或该类的子类所使用
interface IFoo extends Person {}
class Foo extends Person implements IFoo {}