named-urls icon indicating copy to clipboard operation
named-urls copied to clipboard

Typescript support

Open AmirTugi opened this issue 5 years ago • 9 comments

Hi, Is there any plan or option to give types for the methods? I'm using the package, and working on routes' structure enforcement.

AmirTugi avatar Jan 06 '19 16:01 AmirTugi

Hi, I use this declaration:

declare module 'named-urls' {
    interface Routes { [path: string]: string | Routes };
    interface ReverseParams { [path: string]: number | string };

    function include(base: string, routes: Routes): Routes;
    function reverse(pattern: string, params?: ReverseParams): string;
    function reverseForce(pattern: string, params?: ReverseParams): string;
}

azixMcAze avatar Mar 13 '19 13:03 azixMcAze

I'm very shaky on Typescript, but I think the above include declaration can be improved with generics:

  function include<B, R>(base: B, routes: R): { toString(): B } & { [K in keyof R]: string | any }

That at least lets the Typescript follow 1 level deeper and autocomplete the first levels of include() calls.

const routes = {
  dog: include('/dog', {
    cat: include('cat', { mouse: 'mouse' }),
  })
}

// Typescript will follow/autocomplete the following:
// routes.dog (toString() or cat)
// routes.dog.cat (string)

The string | any at the 2nd level is obviously wrong, because instead of any you would want to recurse the type (like the function is recursing). This might just take someone with faaaar more Typescript skills than me to come in and bop how you follow the recursing logic, but thought I'd add my contribution!

max-barry avatar Apr 02 '19 16:04 max-barry

Hey @max-barry (or anyone visiting this thread), feel free to send a PR with TS declarations 👍

tricoder42 avatar May 11 '20 04:05 tricoder42

For anyone interested - I believe here's the typing for include. I'd make a PR, but the best way to make this typed would be to rewrite everything with TS, and I'm not sure I have enough free time on my hands

function include<Routes>(base: string, routes: Routes): { [P in keyof Routes]: Routes[P] } & { toString(): string };

Faithfinder avatar Jul 07 '20 01:07 Faithfinder

The typing for include can further be simplified to:

interface Include {
  <Routes>(path: string, routes: Routes): Routes & { toString(): string };
}

Together with the typings provided by @azixMcAze , we get the following declaration:

declare module "named-urls" {
    export interface Include {
        <Routes>(path: string, routes: Routes): Routes & { toString(): string };
    }

    export interface Reverse {
        (pattern: string, params?: ReverseParams): string;
    }

    export interface ReverseParams {
        [path: string]: number | string;
    }

    export interface Routes {
        [path: string]: string | Routes;
    }

    export type ReverseForce = Reverse;

    export const include: Include;

    export const reverse: Reverse;

    export const reverseForce: ReverseForce;
}

kennedykori avatar Dec 23 '20 22:12 kennedykori

@kennedykori Looks great! Feel free to send a PR so we can include these types with the package

tricoder42 avatar Dec 28 '20 11:12 tricoder42

Oh nice, might spare some time to work on it. Are you okay with converting the project into a typescript project or would you rather I publish the decoration file to DefinitelyTyped? Making this a ts project might require that any future contributors to the project be at-least familiar with typescript. But it will also make it easier to evolve the library and the declarations as they will be on the same repository. @tricoder42 what would be your preference?

kennedykori avatar Jan 01 '21 20:01 kennedykori

Definitely just convert it to Typescript. Typescript is my default choice nowadays 👍

tricoder42 avatar Jan 05 '21 13:01 tricoder42

Awesome, will work on it.

kennedykori avatar Jan 08 '21 00:01 kennedykori