Search code examples
typescriptpreactpreact-router

Preact router Property 'path' does not exist on type 'IntrinsicAttributes'


I am currently going through a problem whilst making a website of mine with preact router. whenever I try to put something in the router it has an error of Property 'path' does not exist on type 'IntrinsicAttributes'. But it doesn't stop the site from running but whenever I change the url to '/shop' it doesn't show anything. shop function

import { Item } from '../../Types/types'
import './item.css'
import Navbar from '../Navbar'
export default function Items(items:Array<Item>) {
    return (
    <>
    <Navbar />
    <div className='container'>
    {
    items.map( item => { 
    return ( 
    <div className='item'>
        <div>
            <h3>
                {item.name}
            </h3>
        </div>      
        <div className='itemimage'>
            <img src={item.picture} alt={item.name} />
        </div>
        <div>
            <strong>{item.price}</strong>
        </div>
    </div>
    )})
    }
    </div>
    </>
    )
}

and my router function

import Router from 'preact-router'
import {App} from '../app'
import Items from './shop/items'
export const Route = () => {
    return (
    <Router>
    <App path='/' />
    <Items path='/shop' />  
    </Router>
    )
}

I tried following the tutorial on preact router. It did not work. I then tried to look up this problem there was nothing about this exact problem with preact-router.


Solution

  • I just encountered the same problem, and while rschristian's answer is good start, pointing to Route component, it's not entirely correct as the used form

    <Route path="/" component="{<SomeComponent />} />
    

    causes following error:

    Type 'Element' is not assignable to type 'AnyComponent<{ path: string; component: Element; }> & (Element | undefined)'.
    

    That's because Route expects AnyComponent which is either FunctionalComponent<Props> or ComponentConstructor<Props, any>.

    So you want to use one of the following:

    import { Route, Router } from 'preact-router'
    import { App } from '../app'
    import Items from './shop/items'
    
    export const Routing = () => {
      return (
          <Router>
              {/* No props needed for App, so we can pass just the constructor. */}
              <Route path="/" component={App} />
              {/*
                  If you need to pass props too, the Route will accept them.
                  However it makes them all optional,
                  so you'll get no type warning when you don't specify them all.
              */}
              <Route path="/shop" component={Items} items={...} />
          </Router>
      )
    }
    

    Alternatively, if you don't want to use Route, you can add path into component's props. Now you can do this manually:

    interface ItemsProps {
        items: Item[]
        // Add the optional `path?` attribute to satisfy typescript.
        path?: string
    }
    

    or use RoutableProps:

    import { RoutableProps } from "preact-router";
    
    interface ItemsProps extends RoutableProps {
        items: Item[]
        // RoutableProps will add `path?` and `default?` attributes,
        // make sure you don't have conflict here, typescript won't tell you
        // and I'm not sure what the behavior would be.
    }
    
    function Items(props: ItemsProps) {
        // Implementation ...
    }
    

    Then you can skip the Route wrapper and use your component directly.

    <Router>
        {/* No props needed for App, so wrapping in Route is still okay. */}
        <Route path="/" component={App} />
        {/* Since Items now supports `path` prop, typescript will be satisfied. */}
        <Items path="/shop" items={...} />
    </Router>
    

    I'm currently using this solution with preact-router version 4.1.2.