skip to Main Content

I have this item interface:

interface Item<Href extends string> {
  href: Route<Href>
}

I want to have a component that takes a list of these Item in a single property:

interface Props {
  items: Item[]
}

const Component = (props: Props): ReactNode => { ... };

<Component items={[
  { href: '/' },
  { href: '/auth' },
]} />

How can I make this work? Currently it complains because I’m not passing the generic to the Item interface when I define Props.

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to @Konrad's comment, the solution was simpler than I expected.

    It was enough to add a generic to the component type

    Here's a full example:

    import * as React from 'react';
    import type { ReactNode } from 'react';
    
    type StaticRoutes = '/' | '/auth'
    type Route<T extends string> = T extends StaticRoutes ? T : never;
    
    interface Item<Href extends string> {
      href: Route<Href>
    }
    
    interface Props<T extends string> {
      items: Item<T>[]
    }
    
    const Component = <T extends string,>(props: Props<T>): ReactNode => { 
      return null;
     };
    
    const App = () => <Component items={[
      { href: '/' },
      { href: '/auth' },
    ]} />
    

    https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcA5FDvmQNwBQokscMAnmFnAN6ZUwByEACacAvnCIlylPDFp06bDnADKMZDGC4MEAK4ws6ALzkA9GTgAfM8n0ALMovacd+rAB4AKnCwAPAwB2QuioMFDAAQDmAHxwJt5+gcGq6praegboAPxw3gBccAFYAG5YUPQMAQZQBHicAJIGIO4AEpQEPv5YQSFhETHcdHBwdu0Frgat7dF0ogoR1bW4nAAKxGCoXp1JveFRsVxDcMBNqAWNWM2e0QDaALqzCrgQAaFwAMIkkEVVcXBbiW6yVCe0iABpogAKMDrM5wNYQDZeaIASnGfEEIjiBzgR0oMF0UAChV0ABtSfQ4KIKs9XvAAIJgMB-SEo7H-T7gF7deAnS6oIxcG5HHijLAEApkcxUsEikZjGz2CyiWV3cSmaJAA


  2. I believe that you should specify the type as well, you are defining in your item to get a Href that extends from string, so you can do the same in the Props interface or set string directly.

    I made this quick example:

    import './App.css'
    
    import { ReactNode } from 'react'
    import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
    
    
    interface Item<Href extends string> {
      href: Href,
      component?: ReactNode
    }
    
    interface Props {
      items: Array<Item<string>>
    }
    
    const Component = ({ items }: Props): ReactNode => {
      return (
        <Router>
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            <Routes>
              {items.map((item, index) => (
                <Route key={index} path={item.href} element={item.component} />
              ))}
            </Routes>
          </div>
        </Router>
      );
    };
    
    const ITEMS: Array<Item<string>> = [
      { href: '/', component: <h1>Dashboard</h1> },
      { href: '/auth', component: <h1>Auth</h1> },
    ];
    
    function App() {
      return (
        <>
          <Component items={ITEMS} />
        </>
      );
    }
    
    export default App;
    

    It is a good practice to use Array instead of Type[] or [Type], it is easier to read.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search