How do I call method from generic in typescript?

Viewed 40

I'm trying to create function that calls specified method on some generic object.

This is what I came up with:

type MethodName<S extends Object, M extends keyof S> = S[M] extends Function ? M : never 

const callMethod = <S, M extends keyof S>(obj: S, method: MethodName<S, M>) =>
    obj[method]()

But I get error this expression is not callable. Even though if I change this function to just returning specified method I can call it later:

const getMethod = <S, M extends keyof S>(obj: S, method: MethodName<S, M>) =>
    obj[method]

const obj = {
    a: 'hi',
    call: () => console.log('hi')
}

getMethod(obj, 'call')

How do I get rid of error in the first case?

1 Answers
type MethodName<S extends Object, M extends keyof S> = S[M] extends Function ? M : never;

const getMethod = <S, M extends keyof S>(obj: S, methodName: MethodName<S, M>) => obj[methodName];

const callMethod = <S, M extends keyof S>(obj: S, methodName: MethodName<S, M>) => {
    const method = getMethod(obj, methodName);

    // typeof here is not just checking types in runtime but to hints TS within the if clause method must be callable
    if (typeof method === 'function') {
        method();
    } else {
        throw new Error('This is not supposed to throw if TS does check things for you');
    }
};

const obj = {
    a: 'hi',
    call: () => console.log('hi')
};

callMethod(obj, 'call');

https://www.typescriptlang.org/play?#code/C4TwDgpgBAshwAsD2ATAcgQwLYQDwGUoIAPYCAOxQGcoB5AIwCsIBjYAGliNIuqgGsIIJADMo+AHxQAvOIDaMALrcylGgDEAruTYBLJOSgB+LgC4o5CADcIAJwDcAWABQLlgarAoAc3hxEqDJQBJwwKrw0gsJikgAUSEzm+Jw4AejYEOb+yOk4IbASAJQyUgmMcqk5mDiKTq7O7uSeUCwYADZt2YGy+WEkqnxRouIS8YniKfBVGVlTqNV4yQXF0lIA3i5QWy0eXpXdPn5zKGOMk2kLhXWb27pisaCQw-soMtKyAOQi2noGH8UbZzbYFQF6xK43LYAXyIbSo0EBIO2iFsSAA7hYIBiAKK2VG2WIfAAqCF0NDJFiQXiomjAYCQ8NewCQUBR6KgdygRMIKCQEBoLAQrH4rNJ5G8NBESFsUGEmn+dWBUJcUOuDV2UDKQUR2ww5g+pI+7EhLXabXM4JKOyaSDaEAAdG0kN5CYbCiq1a0Ol0TmVOB8vW0FUA

Related