Search code examples
typescriptmapped-types

Empty Mapped Type in Typescript


If I have a generic mapped type that maps keys to functions.

type SomeMappedType<T, R> = {
    [K in keyof T]: (...args: any[]) => R
}

This gets passed to my consuming function via an options type where it itself is optional.

type Options<T = any, R = any, P extends SomeMappedType<T, R> = SomeMappedType<T, R>> = {
    prop1?: P
}

I consume this value and return the output type. In the implementation, if prop1 is undefined it is ignored from the output. However, my Output type returns a non-empty mapped type in this case.

const test2: {
    [x: string]: any;
}

My output type is as follows

type Output<T, R, P extends SomeMappedType<T, R>> = ResolveType<{ [K in keyof P]: ReturnType<P[K]> }>;

Is there a way for the default SomeMappedType<T, R> to express that it effectively contains no keys. I'm looking for the mapped type equivalent of an empty array []

Here is a typescript playground of the problem.

Thanks for any help!

EDIT:

The solution from @spender does work for my original example, which was perhaps too simple. Here is an updated example that show 2 different optional props with different types that both contribute to the Output


Solution

  • Mapping the any type results in a {[x:string]:...} mapped type, so your problem can be boiled down to this simplified example:

    type A = {
        foo: "woo"
    }
    type M<T> = { [K in keyof T]: T[K] }
    type MA = M<A>
    //   ^? {foo: "woo";}
    type MAny = M<any>
    //   ^? {[x: string]: any;}
    

    When there's no type to infer, your generic type T becomes any. Perhaps defaulting it to {} instead of any might be a way forward?

    type MEmpty = M<{}>
    //   ^? {}
    

    so...

    function someFunc<
        T = {}, 
        R = any, 
        P extends SomeMappedType<T, R> = SomeMappedType<T, R>>(
            options: Options<T, R, P>): Output<T, R, P> {
        //...
    }