以前 nf-state 是普通 js 的形式,尝试着改为 ts 的形式。
效果不太理想,目前的水平还看不懂 pinia 的源码,所以暂时采用自己的想法来实现。
Typescript 的优点
- 明确类型
- 有提示
- 代码检查
原生js没有地方写类型的定义,只能用 jsDoc 写注释,但是写来写去就乱了。ts可以明确定义对象的结构,可以更明确一些。
而编辑器(比如vscode)也可以给出提示和代码检查,这种代码检查要比 单纯的ESLint更严格和准确一些。
比如:
/**
* 内部保存状态的容器
*/
export interface Store {
[index: string | symbol] : any
}
/**
* 状态的类型,对象和数组都需要实现这个接口
* * $id —— 状态标识,string | symbol
* * _value —— 记录原值,可以是对象,也可以是 function
* * isLog —— 是否记录日志。true :记日志;false: 不记日志(默认值)
* * 内置方法
* * * $reset —— 重置
* * * $patch —— 修改部分属性
* * * set $state —— 整体赋值,会去掉原属性
* * * $toRaw —— 取原型,不包含内部方法
* * * get log() —— 获取日志
* * *
* *
*/
export interface IState {
/**
* 状态标识,string | symbol
*/
get $id(): string | symbol
/**
* 记录原值,可以是对象,也可以是 function
*/
get $_value(): any
/**
* 是否记录日志。true :记日志;false: 不记日志(默认值)
*/
$isLog: boolean
/**
* 重置
*/
$reset (): void
/**
* 修改部分属性
*/
$patch(_val: any): void
/**
* 整体赋值,会去掉原属性
*/
set $state(value: any)
/**
* 取原型,不包含内部方法
*/
$toRaw<T>(): T
/**
* 获取日志
*/
get $log(): Array<StateLogInfo>
}
/**
* 日志的类型
* * {
* * time: '时间戳',
* * kind: '', // 操作类型
* * oldValue: {},
* * newValue: {},
* * subValue: {}, // 参数
* * callFun: '' // 调用的函数名
* * }
*/
export interface StateLogInfo {
time: number,
kind: string, // 操作类型
oldValue: any,
newValue: any,
subValue: any, // 参数
callFun: string // 调用的函数名
}
/**
* 记录状态的变化日志容器,用key来区分
* * stateLog = {
* * key: {
* * log: [
* * {
* * time: '时间戳',
* * kind: '', // 操作类型
* * oldValue: {},
* * newValue: {},
* * subValue: {}, // 参数
* * callFun: '' // 调用的函数名
* * }
* * ]
* * }
* * }
*/
export interface StateLog {
[index: string | symbol] : {
log: Array<StateLogInfo>
}
}
/**
* 创建状态的选项。
* * isLocal —— true:局部状态;false:全局状态(默认属性);
* * isLog —— true:做记录;false:不用做记录(默认属性);
* * level ——
* * * 1:宽松,可以各种改变属性,适合弹窗、抽屉、多tab切换等。
* * * 2:一般,不能通过属性直接改状态,只能通过内置函数、action 改变状态
* * * 3:严格,不能通过属性、内置函数改状态,只能通过 action 改变状态
* * * 4:超严,只能在指定组件内改变状态,比如当前用户的状态,只能在登录组件改,其他组件完全只读
*/
export interface StateOption {
/**
* true:局部状态;false:全局状态(默认属性);
*/
isLocal?: boolean,
/**
* true:做记录;false:不用做记录(默认属性);
*/
isLog?: boolean, //
/**
* 1:宽松,可以各种改变属性,适合弹窗、抽屉、多tab切换等。
* 2:一般,不能通过属性直接改状态,只能通过内置函数、action 改变状态
* 3:严格,不能通过属性、内置函数改状态,只能通过 action 改变状态
* 4:超严,只能在指定组件内改变状态,比如当前用户的状态,只能在登录组件改,其他组件完全只读
*/
level?: number
}
/**
* 创建一个状态的参数类型
*/
export interface StateCreateOption {
state?: any,
getters?: any,
actions?: any
}
/**
* 创建多个状态的类型
*/
export interface StateCreateListOption {
store: {
[index: string | symbol]: StateCreateOption | any
},
init: () => void
}
好吧,还是各种any。因为状态管理,需要接收各种类型,目前还不知道如何处理,泛型可以解决一部分,剩余的以后再说。
Typescript 的思考
js 实在是太灵活了,可以有各种写法,对各种写法都规定类型,目前的水平还是比较吃力。
ts 好像只能在编写和打包时进行检查,运行时好像无能为力了。
而状态管理,主要实在运行时存入状态和取出状态,这种时候 ts 要如何做类型检查呢?或则,我的想法本身就不对?
小结
目前的水平硬改为 ts,有点痛苦,也许以后会好些。
.d.ts 文件还是不同清楚如何自动生成,所以只好手动,好在对外的函数不是太多。
另外,vite 打包的时候,并没有包括 type 文件,所以,只好手动拷贝一份过去。
满篇的爆红,很头疼。。。
网友评论