Search code examples
typescripttypesmapped-types

Type declaration removing "Array" around types without losing names


I'm working on a project with a friend and we wanted to create a type where the type has the first value of the key in an interface, and if they match the rest should match the parameters of the function associated.

export default interface ClientToServerEvents {
    'authenticate': (token: string) => void;
    'update-title': (title: string, annoteId: string) => void;
}
type Partial<T> = { [P in keyof T]: [P, Parameters<T[P]>]; };
type ClientToServerEventsType = ValueOf<Partial<ClientToServerEvents>>;

This is what we have got so far which results in a type that looks like:

type ClientToServerEventsType = ["authenticate", string] | ["update-title", string, string]

This is almost what we want, but we would want the type to keep the names of the parameters as well, and not just be string. What we want is:

type ClientToServerEventsType = ["authenticate", token: string] | ["update-title", title: string, annoteId: string]

We have been at it for an hour and cannot find anything. Thank you!


Solution

  • Tuple elements must all either be named or all not named. Since your tuple does not have a name for the first element, all the other names will be erased.

    If you name the first element, you will see the names are preserved:

    type AllParams<T extends Record<keyof T, (...a: any)=> any>> = { 
      [P in keyof T]: [name: P, ...rest: Parameters<T[P]>]; 
    };
    type ClientToServerEventsType = ValueOf<AllParams<ClientToServerEvents>>;
    //  [name: "authenticate", token: string] | [name: "update-title", title: string, annoteId: string]
    

    Playground Link