如何为对象的this注入OtherProps,消除TypeScript的$watch属性报错?
解决TypeScript中注入扩展属性的类型提示问题
问题场景
我有一个返回对象的函数,后续该对象会被外部扩展$watch这类属性,但TypeScript会提示“Property '$watch' does not exist on type ...”的错误。代码示例如下:
export default () => { const myObject = { property1: 'string1', property2: 1, init() { console.log('property1', this.property1) this.$watch('property1', (value) => { console.log('property1 changed', value) }) }, } return myObject }
对应的扩展属性接口定义:
interface OtherProps<T> { $watch: <K extends keyof T | string, V extends K extends keyof T ? T[K] : any>( property: K, callback: (newValue: V, oldValue: V) => void, ) => void; // ... 其他扩展属性 }
我已经实现了一种类型定义方式,但需要单独编写对象类型,步骤繁琐:
type WithProps<T> = ThisType<T & OtherProps<T>> type Test = WithProps<{ property1: string property2: number init(): void }> export default () => { const myObject: Test = { property1: 'string1', property2: 1, init() {}, } return myObject }
优化方案
方案一:自动推导类型并交叉断言
直接利用typeof推导对象的原始类型,再与OtherProps交叉,不需要手动定义对象类型:
export default () => { const myObject = { property1: 'string1', property2: 1, init() { console.log('property1', this.property1) this.$watch('property1', (value) => { console.log('property1 changed', value) }) }, } type MyObjectType = typeof myObject; // 断言为原始类型与扩展属性的交叉类型 return myObject as MyObjectType & OtherProps<MyObjectType>; }
方案二:利用Object.assign隐式合并类型
通过Object.assign先声明扩展属性的类型,再合并自身对象属性,TypeScript会自动处理交叉类型:
export default () => { const myObject = Object.assign({} as OtherProps<typeof myObject>, { property1: 'string1', property2: 1, init() { console.log('property1', this.property1) this.$watch('property1', (value) => { console.log('property1 changed', value) }) }, }) return myObject; }
方案三:封装工具函数复用逻辑
把类型处理逻辑封装成工具函数,后续直接传入对象字面量即可,无需重复编写类型:
interface OtherProps<T> { $watch: <K extends keyof T | string, V extends K extends keyof T ? T[K] : any>( property: K, callback: (newValue: V, oldValue: V) => void, ) => void; // ... 其他扩展属性 } // 封装工具函数,自动推导对象类型并绑定this上下文 const createWithProps = <T extends object>(obj: T & ThisType<T & OtherProps<T>>): T & OtherProps<T> => { return obj as T & OtherProps<T>; } export default () => { return createWithProps({ property1: 'string1', property2: 1, init() { console.log('property1', this.property1) this.$watch('property1', (value) => { console.log('property1 changed', value) }) }, }) }
这三种方案都可以避免手动编写对象类型,让TypeScript正确识别扩展的$watch属性,同时保持代码简洁。
内容的提问来源于stack exchange,提问作者Mickael Chanrion
相关产品推荐
相关产品推荐

