不太一样的前端开发之TypeScript装饰器和面向对象

1、前言

早前的一些文章中提到的我们在前端使用TypeScript装饰器和面向对象设计的方案作为日常的业务开发方式,引来了不少的争议和讨论,虽然我们也使用了Hooks来实现一些视图层公共代码的抽离,但我们依然还是坚持在项目中使用一些强面向对象的设计思维, 今天我们来仔细聊聊。

2、面向对象

我们使用面向对象的开发方式主要体现在以下几个方面:

2.1 公共代码的继承

在日常开发中经常存在一些公共代码或属性,如数据转换、数据拷贝、数据过滤、公共的属性(ID、创建时间)等,我们需要对它们进行抽离,虽然像 interface type 等都能完成一些公共属性的声明和继承,使用一些方法类可以将一些公共的方法进行封装,但从抽象上来说,放到 class 中也许更合适:

类的对象更抽象

使用 interfacetype 定义数据结构虽然没问题,但实际传递的参数还是个简单类型的对象Object,无法包含一些自定义的方法,而且无法通过数据取得对应的定义类型,无法实现类似 反射 获取一些特性数据。

typescript 复制代码
interface IBase{
	id: number
}
interface IUser extends IBase{
	nickname: string
}

const user: IUser = {nickname: "Hamm"}

使用 class 定义数据类型,可以解决上面的问题。

typescript 复制代码
class Base {
	id!: number
}
class User extends Base{
	nickname!: string
}

const user = new User()
user.id = 1
user.nickname = "Hamm"

// 当然 也可以使用一些构造或自定义方法来快速初始化数据 如
class BaseData{
	id!: number
	setId(id: number):this{
		this.id = id
		return this
	}
}
class User extends BaseData{
	nickname!: string
	setNickname(nickname: string): this{
		this.nickname = nickname
		return this
	}
	
	userType!: number
	
	isAdmin():boolean{
		if(this.userType === 1){
			return true
		}
		return false
	}
}

const user = new User().setId(1).setNickname("Hamm")

上面的代码是不是看起来很多? 其实使用 TypeScriptvscode 写的时候,很多都是直接用 . 给选出来的,类的声明也可以使用一些工具来自动生成,如 Json转TS代码工具

无需将方法和属性分开

上面的示例中,传递的 user 对象就是正经的一个用户对象了,包含了用户的一些属性和方法,方便了下面的使用:

typescript 复制代码
user.isAdmin() // 直接返回是否管理员的 `true` `false`

2.2 相似代码的抽象

相似代码的抽象,在后端会经常用到,在前端的也是如此,大部分业务都相同,有部分相似但又有一些小区别,为了对这种场景进行封装,我们可以使用抽象类来处理。比如 声明了一个基础的 curd 接口请求方法:

typescript 复制代码
abstract class AbstractCurdApi<D extends BaseData>{
	// 获取请求的 baseUrl 每个子类不一样的地方
	abstract getBaseUrl(): string
	
	delete(): void{
		// 删除
	}
	
	add(data: D): D{
		// 新增一条
	}
	
	getById(id: number): D{
		// 查询指定ID的一个数据
	}
	
	// 其他curd方法
}

接下来需要使用的子类中就可以将需要自己实现的方法实现后即可继承父类的所有方法。

typescript 复制代码
class UserApi extends AbstractCurdApi<User>{
	getBaseUrl(){
		return 'user'
	}
}

当然,TypeScript 还有一个 Java 不服的地方,就是它竟然支持将属性抽象掉:

typescript 复制代码
abstract class AbstractCurdApi<D extends BaseData>{
	abstract baseUrl: string
}

2.3 类和属性可以挂载装饰器

因为类和属性都支持挂载装饰器,所以我们可以选择 class 类来封装数据结构,既可以为它实现一些方法,也可以对类和属性进行装饰,然后后续使用这些装饰配置来实现更多的功能。

请接着阅读下面关于装饰器的部分。

3. 装饰器

TypeScript 的装饰器和 Java 的注解类似,以 @ 开头,写在属性、方法、类的前面,关于装饰器的基础知识,可以参考官方文档,我们这里只讲如何使用:

typescript 复制代码
@Class("用户")
@Enable(CURD.ADD,CURD.DELETE)
class User{
	@Field("昵称")
	@Form({
		required:true,
		placeholder:" 请输入一个牛逼的名字"
		// ...
	})
	@Table({
		copy: true, //表格中显示为一个可复制的单元格
		align: "left",
		// ...
	})
	nickname!: string
	
	@Field("性别")
	@Dict(SexDictionary)
	@Search()
	sex!: Sex
}

如上,我们声明了一个 User 类,并装饰了一大堆的配置,比如表格、表单、搜索等等。

其他在使用的组件中,就可以直接传入这个类,然后获取类中配置的一些信息,来渲染不同的表格、表单、搜索等状态。

如此使用之后,可以直接在类中完成集中化的配置。装饰器的玩法还有很多,听舒服的。

4. 最后

文中说到的一些东西,目前都可以在我们的开源仓库中看到所有代码:

Github:github.com/HammCn/AirP...

你也可以查看我的专栏: 用TypeScript写前端

相关推荐
NoloveisGod6 分钟前
Vue的基础使用
前端·javascript·vue.js
GISer_Jing8 分钟前
前端系统设计面试题(二)Javascript\Vue
前端·javascript·vue.js
海上彼尚37 分钟前
实现3D热力图
前端·javascript·3d
杨过姑父37 分钟前
org.springframework.context.support.ApplicationListenerDetector 详细介绍
java·前端·spring
理想不理想v1 小时前
使用JS实现文件流转换excel?
java·前端·javascript·css·vue.js·spring·面试
惜.己1 小时前
Jmeter中的配置原件(四)
java·前端·功能测试·jmeter·1024程序员节
EasyNTS1 小时前
无插件H5播放器EasyPlayer.js网页web无插件播放器vue和react详细介绍
前端·javascript·vue.js
poloma1 小时前
五千字长文搞清楚 Blob File ArrayBuffer TypedArray 到底是什么
前端·javascript·ecmascript 6
guokanglun2 小时前
Vue.js动态组件使用
前端·javascript·vue.js
Go4doom2 小时前
vue-cli3+qiankun迁移至rsbuild
前端