const Interceptor = Symbol ( 'Interceptor for programmatical calls' ) ; interface Interceptable { [ Interceptor ] ? : typeof Interceptor ; } type anyFunc = ( ... a : any [ ] ) => any ; type Params < Prop > = Prop extends anyFunc ? Parameters < Prop > : [ Prop ] ; type ImplReturn < Prop > = Prop extends anyFunc ? Parameters < Prop > : Prop ; export function prepareInterceptor < ElementType extends Node , PropName extends keyof ElementType > ( element , propName , interceptorImpl ) { const prototypeDescriptor = Object . getOwnPropertyDescriptor ( element . constructor . prototype , propName ) ; const objectDescriptor = Object . getOwnPropertyDescriptor ( element , propName ) ; const target = prototypeDescriptor ?. set ? 'set' : 'value' ; if ( typeof prototypeDescriptor ?. [ target ] !== 'function' || ( prototypeDescriptor [ target ] as Interceptable ) [ Interceptor ] ) { return ; } function intercept ( this , ... args ) { const { applyNative = true , realArgs } = interceptorImpl . call ( this , ... args ) ; const realFunc = ( ( ! applyNative && objectDescriptor ) || ( prototypeDescriptor as PropertyDescriptor ) ) [ target ] as ( this : ElementType , ... a : unknown [ ] ) => unknown ; if ( target === 'set' ) { realFunc . call ( this , realArgs ) ; } else { realFunc . call ( this , ... realArgs ) ; } } ; ( intercept as Interceptable ) [ Interceptor ] = Interceptor ; Object . defineProperty ( element , propName , { ... ( objectDescriptor ?? prototypeDescriptor ) , [ target ] : intercept , } ) ; }