This works for me. In callbacks I just need the element; not the mouse/touch event and not the context (don't use 'this' in callback).
pointer.ts
/**
 *  Simulate touchenter and touchleave by tracking touchmove. See https://stackoverflow.com/questions/23111671/touchenter-and-touchleave-events-support
 */
const touchEventSimulator = {
    // enterElementCallback stores element as key and callback as value
    enterElementCallback: new Map(),
    leaveElementCallback: new Map(),
    previousElement: null,
    init: function() {
        window.addEventListener('touchmove', event => {
            var currentElement = document.elementFromPoint(event.touches[0].clientX, event.touches[0].clientY)
            if (currentElement !== this.previousElement) {
                // touch leave
                const leaveCallback = this.leaveElementCallback.get(this.previousElement)
                if (leaveCallback) {
                    leaveCallback.call(null, this.previousElement)
                }
                // touch enter
                const enterCallback = this.enterElementCallback.get(currentElement)
                if (enterCallback) {
                    enterCallback.call(null, currentElement)
                }
                // Current element will be the previous one, next time we check.
                this.previousElement = currentElement;
            }
        });
    },
    onEnter(element, callback) {
        this.enterElementCallback.set(element, callback);
    },
    onLeave(element, callback) {
        this.leaveElementCallback.set(element, callback);
    }
}
const mouseAvailable = matchMedia('(pointer:fine)').matches;
/**
 * Pointer is a wrapper for mouse and (simulated) touch events
 */
export const pointer = {
    mouseAvailable,
    init() {
        if (!mouseAvailable) {
            touchEventSimulator.init()
        }
    },
    onEnter: (element, callback) => {
        if (mouseAvailable) {
            element.addEventListener('mouseenter', ()=>callback.call(null, element))
        } else {
            touchEventSimulator.onEnter(element, callback)
        }
    },
    onLeave: (element, callback) => {
        if (mouseAvailable) {
            element.addEventListener('mouseleave', ()=>callback.call(null, element))
        } else {
            touchEventSimulator.onLeave(element, callback)
        }
    }
}
example.ts
import {pointer} from './pointer';
pointer.init();
const element = document.getElementById('test');
pointer.onEnter(anchor, element=>{
    console.log('enter', element)
})
pointer.onLeave(anchor, element=>{
    console.log('leave', element)
})