typescript:5、接口
1、typescript接口
1、typescript接口概念
用于描述一个类型
1.2、typescript语法
定义接口
interface Employee {
readonly name: string //只读字段,定义值之后不能更改
salary: number
bonus?: number //可选字段
}
const emp1: Employee = {
name: 'john',
salary: 8000,
}
可选字段串联/非空断言
interface Employee {
name? : {
first?: string
last: strign
}
salary: number
bonus?: number
}
//返回boolean或undefined
function hasBadName(e: Empoyee){
//可选字段串联用法
return e.name?.first?.startsWith('AAA')
//非空断言用法
//下方的!表示的是告诉编译器e.name一定有值,不需要去管,后果自负
//return e.name!.first!.startsWith('AAA')
}
hasBadName({
name: {
last: 'smith',
},
salary: 8000
})
接口扩展
interface HasName {
name?: {
first?: string
last: string
}
}
//使用extends之后,Employee就有name字段了
interface Employee extends HasName{
salary: number
bonus?: number
}
类型的并和类型断言
interface WxButton {
visible: boolean
enabled: boolean
onClick(): void
}
interface WxImage {
visiable: boolean
src: string,
width: number
height: number
}
//processElement(e: WxButton | WxImage),此时的e的类型是WxButton和WxImage并出来的
function processElement(e: WxButton | WxImage){
if(isButton(e)) {
e.onClick()
}else{
console.log(e.src)
}
}
/*
processElement函数的普通写法
function processElement(e: WxButton | WxImage) {
if( (e as any).onClick){
const btn = e as WxButton
btn.onClick()
}else{
const img = e as WxImage
console.log(img.src)
}
}
*/
//类型判断
function isButton(e: WxButton | WxImage): e is WxButton {
//e as WxButton为类型断言
return (e as WxButton).onClick !== undefined
}
processElement({
visiable: true,
enabled: true,
onClick(){
console.log('clicked')
}
})
2、类
class Employee {
name: string = '' //1、类属性定义后一定要初始化值
salary: number //2、若属性没有在定义时初始化,那么可以在构造函数中赋值
private bonus: number = 0
//3、构造函数
constructor(salary: number) {
this.salary = salary
}
updateSalary(){}
}
const emp1 = new Employee(8000)
//所有的属性和方法默认都是public的,外面都可以调用
emp1.updateSalary()
emp1.name
属性简易定义的方法
class Employee{
//可选字段
private bonus?: number
//在构造方法中的参数添加public关键字
//相当于定义了字段,并赋值
constructor (public name: string, public salary: number) {}
/*
//上方的未注释的构造函数与下方代码等价
name: string
salary: number
constructor(name: string, salary: number){
this.name = name
this.salary = salary
}
*/
}
getter/setter
class Employee{
private allocatedBonus?: number
//setter
set bonus(v: number) {
this.allocatedBonus = v
}
//getter
get bonus(){
return this.allocatedBonus || 0
}
}
const emp1 = new Employee()
emp1.bonus = 20000 //使用setter,跟属性的用法一样
console.log(emp1.bonus)
继承
class Employee{
private allocatedBonus?: number
constructor(public name: string, public salary: number){}
set bonus(v: number){
this.allocatedBonus = v
}
get bonus(){
return this.allocatedBonus || 0
}
}
class Manager extends Employee{
private reporters: Employee[]
constructor (name: string, salary: number){
super( name, salary)
this.reporters = []
}
addReporter(e: Employee){
this.reporters.push(e)
}
}
const emp1 = new Employee('john', 8000)
emp1.bonus = 20000
const manager1 = new Manager('mary', 18000)
manager1.addReporter(emp1)
manager1.bonus = 50000
console.log(manager1)
3、用类来实现接口
3.1、隐式实现
//定义接口
interface Service {
login():void
}
//实现接口(隐式实现)
class PRCService{
login(): void {
//do something
}
}
//file: login.ts
// 使用接口
const page = {
service: new PRCService() as Service,
onLoginButtonClicked(){
//使用接口
this.service.login()
}
}
3.2、显式实现
下方会导致接口特别大(里面的方法特别多),所以不是特别推荐
//定义接口
//file: service.ts
interface Service {
login(): void
getTrips(): string
getLic(): string
startTrip(): void
updateLic(lic: string): void
}
//实现接口
//file: service.ts
class PRCService implements Service {
login(): void {
throw new Error("Method not implemented.");
}
getTrips(): string {
throw new Error("Method not implemented.");
}
getLic(): string {
throw new Error("Method not implemented.");
}
startTrip(): void {
throw new Error("Method not implemented.");
}
updateLic(lic: string): void {
throw new Error("Method not implemented.");
}
}
// 使用接口
//file: login.ts
const page = {
service: new PRCService() as Service,
onLoginButtonClicked(){
//使用接口
this.service.login()
}
}
3.3、如何选择显式实现和隐式实现
如果一个接口过大,方法特别多,这样并不是很推荐。一般都建议使用隐式实现接口,可以让接口的方法少一些