Determine the route parameter name based on the path string, for example, '/posts/:id'

My Route interface has a params object, and I'm looking to ensure type safety on that params object. For example:

If we have a route config like this:

{
  post: {
    path: 'posts/:id',
  }
}
navigate({ name: 'post', params: { wrongKey: '1' } });

I've defined the Route interface as shown below, but T[keyof T] doesn't seem to correctly infer which key it is:

type Route<T extends Config> = {
  hash?: string;
  name: keyof T & string;
  params?: RouteParams<T[keyof T]['path']>;
  search?: Record<string, string>;
};

I want this scenario to raise an error because wrongKey should be id. Currently, all I get are param keys as types of string.

You can check out the full code in the playground link here.

Answer №1

Firstly, it is important to include as const in order for your paths to be treated as literals rather than just strings:

const routes = {
  post: { path: '/posts/:id' },
  blah: { path: '/posts/:blah' },
} as const;

Secondly, ensure that the navigate function has a second generic parameter to avoid inferring parameters as a union of all possibilities:

type Route<T extends Config, K extends keyof T = keyof T> = {
  hash?: string;
  name: K;
  params?: RouteParams<T[K]['path']>;
  search?: Record<string, string>;
};

const routes = {
  post: { path: '/posts/:id' },
  blah: { path: '/posts/:blah' },
} as const;

navigate(routes, { name: 'post', params: { id: '1' } }); //  ok
navigate(routes, { name: 'post', params: {} }); //           errors: missing id
navigate(routes, { name: 'postj', params: { id: '1' } }); // errors: no postj
navigate(routes, { name: 'post', params: { idj: '1' } }); // errors: no idj

function navigate<T extends Config, K extends keyof T>(config: T, route: Route<T, K>) { }

https://tsplay.dev/NB8nbW

Answer №2

Check out the HOTScript library for a similar example. Just before the API section, there is a code snippet that you can customize to suit your needs.

You might also want to experiment with adding as const after defining the routes object, like shown below:

const routes = {
  post: { path: '/posts/:id' },
} as const;

By doing this, the path property will be treated as a literal type instead of just a generic string type.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What steps can I take to troubleshoot and repair my accordion feature within an Angular project?

As a newcomer to Angular, I recently attempted to create an accordion component but encountered unexpected behavior. Here is the HTML code for my attempt: <div class="faq-item-container"> <h1 class="mt-1 mb-5"><strong>Frequently A ...

What is the best way to export a default object containing imported types in TypeScript?

I am currently working on creating ambient type definitions for a JavaScript utility package (similar to Lodash). I want users to be able to import modules in the following ways: // For TypeScript or Babel import myutils from 'myutils' // myuti ...

Angular Obsidian Theme

Hey there! I've successfully implemented a toggle button that switches my Ionic 3 app to dark mode. However, I'm unsure about where exactly I should define the global class [class.dark-theme]="dark". It's essential for this class to be in th ...

A simple method in JavaScript/TypeScript for converting abbreviations of strings into user-friendly versions for display

Let's say I am receiving data from my backend which can be one of the following: A, B, C, D Although there are actually 20 letters that could be received, and I always know it will be one of these specific letters. For example, I would like to map A ...

Trouble displaying object in template using Angular's ngrx

Within my Typescript interface, I have declared the following structure: export interface FolderList { ADMIN: [Folder[], string, string]; SUPERADMIN: [Folder[], string, string]; USER: [Folder[], string, string]; } The 'Folder' interface is de ...

Unable to access structuredClone on the global object within a Node.js application

structuredClone is causing issues in my NodeJS application. Whenever I try to utilize it, I encounter the error: structuredClone is not defined nodejs. To troubleshoot, I created a simple file and executed the following: console.log({ globals: Object. ...

The object's value may be 'undefined' after utilizing a switch case to ensure it is not undefined

Before I encountered the error Object is possibly 'undefined'.ts(2532) at testObject["x"], I had used case "x" in testObject. Why did this happen? Should I create my own type guard for it? interface TestObject { a?: number; ...

Can Angular 9 be used to compile a latex document?

Is it possible to utilize Angular 9 to compile and generate PDF files using latex? Specifically, I am curious about how to compile a document using Angular and Pdflatex. The idea is for the client to input their data in the form of a JSON data structure ...

How can I implement dynamic styling for the rows in the PrimeNG table?

I have the MyObject.ts file with the following properties: name: String rowStyle: String In addition, I have a MyComponent.ts file containing: myObject1: MyObject = new MyObject(); myObject2: MyObject = new MyObject(); myObjectList: MyObject[] = []; myO ...

How should a child component specify the type of component being passed in props?

Consider the following snippet from App.tsx : <Layout header={ <Header/> } </layout> Now, let's take a look at the Layout component : export default function Layout({header, body}: any) { return ( <div className="layou ...

"Utilizing ReactJS and Typescript: A guide on initiating a Redux dispatch event through an axios

Looking for help with ReactJS typescript and redux dispatch events when calling APIs using axios interceptors? Check out my code snippet below. Codesandbax Repo App.tsx import "./App.css"; import "bootstrap/dist/css/bootstrap.min.css" ...

What is the best way to detect object changes in typescript?

Having an object and the desire to listen for changes in order to execute certain actions, my initial approach in ES6 would have been: let members = {}; let targetProxy = new Proxy(members, { set: function (members, key, value) { console.log(k ...

Is it feasible to incorporate a method into a prototype and ensure that 'this' is associated with the appropriate type in TypeScript?

I have a scenario where I need to add a new method to a prototype, specifically to a class created using TypeScript. Here is an example: declare module "./MyClass" { interface MyClass { myNewMethod(); } } MyClass.prototype.myNewM ...

Customized interfaces utilizing generic components

Here is my simplified question. interface Identity{ name: string; } Next, we have a generic interface. interface State<T extends Identity>{ [T.name] : StateContainer<T> } Unfortunately, this approach fails and the following error is ...

What is TypeScript's approach to managing `data-*` attributes within JSX?

Let's consider the following code snippet: import type { JSX } from 'react'; const MyComponent = (): JSX.Element => ( <div data-attr="bar">Foo</div> ); Surprisingly, this code does not result in any TypeScript er ...

The unique Angular type cannot be assigned to the NgIterable type

As a newcomer to Angular, I was introduced to types and interfaces today. Excited to apply my new knowledge, I decided to enhance my code by utilizing a custom interface instead of a direct type declaration: @Input() imageWidgets: ImageWidget; Here is the ...

Transforming an object into an interface in TypeScript

Recently, I have started learning Typescript and am currently working on a project where I am building a REST API. In this project, I have defined a specific model for my request payload. However, even after typecasting, the type of 'resObj' rem ...

The search for d.ts declaration files in the project by 'typeRoots' fails

// Within tsconfig.json under "compilerOptions" "typeRoots": ["./@types", "./node_modules/@types"], // Define custom types for Express Request in {projectRoot}/@types/express/index.d.ts declare global { namespace Express { interface Request { ...

An unexpected stats.js error occurred while attempting to apply custom styles to the map in AngularGoogleMaps,

My experience with Angular Google Maps has been mostly positive, except for one issue that I have encountered. When attempting to add styles to the map using the styles input attribute, I encounter an error: js?v=quarterly&callback=agmLazyMapsAPILoad ...

Service consuming in Angular 2 using Stomp protocol

Why am I seeing responseBody as undefined, but I am able to see the subscribe response in msg_body? What could be causing this issue with responseBody? let stomp_subscription = this._stompService.subscribe('/topic/queue'); stomp_subscription.ma ...