1.问题引入
考虑一个watch函数
javascript 代码解读复制代码const personWatcher = watch({
firstName: 'Saoirse',
lastName: 'Ronan',
age: 26,
sex: '男'
})
personWatcher.on('firstNameChanged', (oldVal, newVal)=>{})
若要对这样一个Watche函数进行类型标注,简单的标注方式即为如下代码:
javascript 代码解读复制代码type Watcher = {
on(eventName: string,
callback:( oldvalue:any, newValue: any) => void):void
}
declare function watch(obj: object): Watcher;
这样标注有很大的缺陷就是在填写eventName参数时没有智能提示以及类型约束,写了ts相当于白写。
2.eventName的类型标注
所以需要使用模板字符串增强类型标注
javascript 代码解读复制代码type Watcher = {
on( eventName:`${'firstName'|'lastName'|'age'|'sex'}Changed`,
//...
)
}
如此一来eventName就能有类型约束了。进一步的,可以将模板字符串内的值使用动态的键值改写,即可用泛型解决上文代码没有动态抽取属性名的问题。
javascript 代码解读复制代码type Watcher: = {
on( eventName:`${keyof T}Changed`,
//...
)
}
declare function watch(obj: T):Watcher
实际上,代码仍然有一段缺陷,因为泛型T有可能是Symbol类型,所以keyof Symbol会出现报错,解决方法即为提取泛型中的String类型即可,如下代码所示:
javascript 代码解读复制代码type Watcher: = {
on( eventName:`${string & keyof T}Changed`,
//...
)
}
3.callback的类型标注
解决完eventName的标注,再完善callback参数类型的标注。callback函数的参数应当为某个字段的类型,所以标注代码如下所示。
首先在进行callback标注时,应当是在调用on的时候才能确定具体属性被监听,而不是在Watcher被调用时确定具体属性被监听,也即on方法中需要一个泛型K接收这个属性。如此一来便能对callback进行标注
javascript 代码解读复制代码type Watcher = {
onextends keyof T>(eventName: string,
callback:( oldvalue:T[k], newValue: any) => void):void
}
但目前位置代码会有一个BUG,比如以下代码能出现callback参数的类型提示,但是明显不是我们需要的效果。(eventName与泛型K监听的属性不一致)。
javascript 代码解读复制代码type Watcher = {
onextends keyof T>(eventName: `${string & keyof T}Changed`,
callback:( oldvalue:T[k], newValue: any) => void):void
}
personWatcher.on<'age'>('sexChanged', (olbValue...))
所以在泛型中需要加上限定,参考以下代码:
javascript 代码解读复制代码type Watcher = {
onextends keyof T>(eventName: `${K}Changed`,
callback:( oldvalue:T[k], newValue: any) => void):void
}
personWatcher.on<'age'>('sexChanged', (olbValue...))
如此一来ts可以自动推导K的类型,而不必在on方法中填写泛型K。且实现了callback的类型标注
评论记录:
回复评论: