// 这段代码看看怎么标注
declare function watch(obj: Object): Watcher;
// 函数watch,传入一个对象,得到新对象
const personWatcher = watch({
firstName: 'John',
lastName: 'Doe',
age: 25,
});
// 新对象的on方法可以监听属性的变化
// 这里 on 的泛型参数类型需要和监听的属性的类型一致
personWatcher.on('ageChanged', (oldValue, newValue) => {
// 相关逻辑
});
第一种方式
约束力小,比如说:监听的字段可以写任何值,也没有提示
//首先
type Watcher = {
on(
eventName: string,
callback: (oldValue: any, newValue: any) => void): void;
};
第二种方式
TS中可以使用模板字符串,TS的模板字符串是在编译时来确定类型的
type Watcher<T> = {
on(
// 这样写过后,有了TS类型提示,但是将类型写死了,改进一下
// eventName: `${'firstName' | 'lastName' | 'age'}Changed`,
// keyof 可以动态取出某一个类型中的所有字段名,形成联合类型
// 对象的字段名类型包括:string 和 symbol,而symbol无法完成这种拼接
// 需要使用 string & 约束一下
eventName: `${string & keyof T}Changed`,
callback: (oldValue: any, newValue: any) => void
): void;
};
declare function watch<T>(obj: T): Watcher<T>;
第三种方式
type Watcher<T> = {
on<K extends string & keyof T>(
// eventName: `${string & keyof T}Changed`,
// 为了保证 on 的泛型参数的类型和监听的字段类型一致,直接改为 K
eventName: `${K}Changed`,
// 这里参数是 any 类型肯定不可以,也需要动态知道你读取的是哪个字段
// callback: (oldValue: any, newValue: any) => void
// K 从哪里来呢,可以从 on 方法的泛型上获取到
callback: (oldValue: T[K], newValue: T[K]) => void
): void;
};
declare function watch<T>(obj: T): Watcher<T>;
const personWatcher = watch({
firstName: 'John',
lastName: 'Doe',
age: 25,
});
// 这里 on 的泛型参数类型需要和监听的属性的类型一致
personWatcher.on<'age'>('ageChanged', (oldValue, newValue) => {
// 相关逻辑
});