Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected type enforcement for invalid routes #25

Open
dylanpomeroy opened this issue Mar 13, 2023 · 2 comments
Open

Unexpected type enforcement for invalid routes #25

dylanpomeroy opened this issue Mar 13, 2023 · 2 comments
Labels
bug Something isn't working

Comments

@dylanpomeroy
Copy link

dylanpomeroy commented Mar 13, 2023

Hello, loving this project so far! We think this will help keep our react-router paths under control our large SPA app 🙏

When attempting to use the library, I noticed that type enforcement for the last keys did not behave as expected:

import { arg, createRouting, segment } from 'ts-routes';

export const navRoutes = createRouting({
  businessId: {
    ...segment`/${arg('identityBusinessId')}`,
    children: {
      dashboard: segment`/dashboard`,
    },
  },
});

const routeExample1 = navRoutes.businessId.invalidKey({ identityBusinessId: 'id' }); // type error on `invalidKey` as expected
const routeExample2 = navRoutes.businessId.dashboard.invalidKey({ identityBusinessId: 'id' }); // no type errors
const routeExample3 = navRoutes.businessId.dashboard.invalidKey1.invalidKey2({ identityBusinessId: 'id' }); // type error on `invalidKey2`, but not `invalidKey1`

I would expect (ideally) that use of invalidKey anywhere would throw a type error. Is there anything I'm missing in the routing implementation?

Getting past this issue would allow us to use this library to type enforce our react-router paths which would be a huge value add for our site stability.

Thanks in advance! 🙏

@dylanpomeroy
Copy link
Author

Just wanted to post an update on this. By wrapping segment and using it inside our createRouting call, I was able to improve the type enforcement around the nested keys. Specifically, setting the children in the segment to {} and following the destructure pattern in the docs, type checking started enforcing their usage correctly:

import { segment } from 'ts-routes';

class PathParamDescription<
  TName extends string = string,
  TOptionality extends 'required' | 'optional' = 'optional'
> {
  readonly pattern: string;
  readonly name: TName;
  readonly optionality: TOptionality;

  constructor({
    name,
    optionality,
    pattern,
  }: {
    name: TName;
    optionality: TOptionality;
    pattern?: string;
  }) {
    const patternPart = pattern ? `(${pattern})` : '';
    const requirementPart = optionality === 'optional' ? '?' : '';

    this.name = name;
    this.optionality = optionality;
    this.pattern = `:${name}${patternPart}${requirementPart}`;
  }
}

/**
 * A wrapper for `segment` from `ts-routes`, based on the original implementation
 *
 * By including `children: {}` in the return object, we improve type enforcement for nested routes.
 * See original implementation: https://github.com/leancodepl/ts-routes/blob/f25bcf95213e0acebca0813144bdb7ae61abf5af/src/segment.ts
 */
export const wrappedSegment = <
  TPathParamsDescription extends PathParamDescription<string, 'required' | 'optional'>[]
>(
  literals: TemplateStringsArray,
  ...placeholders: TPathParamsDescription
) => {
  return {
    ...segment(literals, ...placeholders),
    children: {},
  };
};

@alszczep alszczep added the bug Something isn't working label May 22, 2023
@alszczep
Copy link

Hey, happy to see that you've found the solution. Your problem definitely looks like a bug inside the library, we'll try to have it fixed soon so that you won't have to do any workarounds on your side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants