Personally, I believe it should be done on eslint level, however there is something you can do to make your code a little bit safer.
Consider this example:
const foo = {
    name: 'foo',
    fn(this) { // this is required if you want to make it type safe
        console.log(this.name)
    }
}
const callback = <Cb extends (this: { name: string }) => void>(cb: Cb) => {
    cb(); // expected error
    cb.call({ name: 'hello', fn: () => { } }) // ok
}
const arrowFn = () => { }
callback(arrowFn)
callback(foo.fn)// error because of contravariance
Playground
As you might have noticed, I have provided fn method with explicit this context notation. It means that context is important for this method (see docs).
Than, function callback expects a callback which is context sensitive. TS forbids you to call cb without context. You are allowed to call cb only with Function.prototype.call, see cb.call({ name: 'hello', fn: () => { } })
However, it is still very tricky. TS allows you to use arrowFn as an argument, because this function does not expect any arguments, just like cb.
See this:
declare let withContext: (this: { name: string }) => void
declare let nonContext: () => void
withContext = nonContext // ok
nonContext = withContext // ok
So, why we have an error here ?:
callback(foo.fn) // error
Consider this example:
type ThisA = { name: string }
type ThisB = { name: string, fn: () => void }
// #FIRST EXAMPLE
declare let a: ThisA
declare let b: ThisB
a = b // ok
b = a // error
// #SECOND EXAMPLE
declare let thisA: (this: ThisA) => void
declare let thisB: (this: ThisB) => void
thisA = thisB // error
thisB = thisA // ok
In #first example, b is assignable to a, and it is expected. However, is #second example, thisB is no more assignable to thisA, bit thisA is assignable to thisB. It is called contravariance. See my question about it.
Let's summarize. If you want to pass a callback which is this dependent, you need to explicitly type this dependency:
const foo = {
    name: 'foo',
    fn() {
        console.log(this)
    }
}
const callback = <
    Cb extends (this: { name: string, fn: () => void }) => void
>(cb: Cb) => {
    cb(); // expected error
    cb.call({ name: 'hello', fn: () => { } }) // ok
}
TypeScript has some interesting typings of this in s, my article or this answer
EXAMPLE WITH CALSSES
interface Base {
    name: string
}
class Bar {
    say(this: Base) {
        return this.name
    }
}
class Foo {
    constructor(public name: string) { }
    log(this: Base) {
        console.log(this.name)
    }
}
const callback = <Cb extends (this: Base) => void>(cb: Cb) => {
    cb(); // expected error
    cb.call({ name: 'hello' }) // ok
}
const foo = new Foo('Ternopil')
const bar = new Bar()
bar.say() // not safe, because `bar` don't have own `name` proeprty
// ok, because we expect a callback which requires only `name` property, see Base interface
callback(foo.log)
callback(bar.say) // ok
Playground
Assume we don't care what class it is. What we care is that class method should expect this to have a name property. I have created a Base interface with name property and explicitly defined this type on say method and log method
Please be aware that it is not safe, because bar instance does not have own name property