TypeScript errors when attempting prop drilling in Ionic React

I’m trying to drill app state down through component props in app.tsx, but get a typescript error:

Type '{ dailyObd: RouteComponentProps<any, StaticContext, {}>; }' is not assignable to type 'IntrinsicAttributes & obds & { children?: ReactNode; }'.
  Property 'dailyObd' does not exist on type 'IntrinsicAttributes & obds & { children?: ReactNode; }'.ts(2322)

Here’s a breakdown of what I’ve got:
app.tsx:

const App: React.FC = () => {
  const [dailyObds, setDailyObds] = useState<dailyObds>([{
    title: 'First',
    completed: false
  }])

  return (
    <IonApp>
      <IonReactRouter>
        <IonSplitPane contentId="main">
          <Menu />
          <IonRouterOutlet id="main">
            <Route path="/page/today" render={(dailyObds)=>(<Today dailyObd={dailyObds} /> )} />
            <Redirect from="/" to="/page/Inbox" exact />
          </IonRouterOutlet>
        </IonSplitPane>
      </IonReactRouter>
    </IonApp>
  )
}

interface dailyObd{
    title: string
    completed: boolean
}
interface dailyObds extends Array<dailyObd>{}

export default App;

Here’s Today.tsx:

const Today: React.FC = ({ dailyObd })=>{
  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonButtons slot="start"><IonMenuButton /></IonButtons>
          <IonTitle>Today</IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent>
        <IonText>Some stuff will go here... eventually.</IonText>>
      </IonContent>
    </IonPage>
  )
}

I set strict to false in tsconfig.json, but I still can’t compile because of the listed error. What am I missing here? Why is it seemingly so difficult to add a prop to a component with TypeScript? Thanks for any help, I am new to Ionic/React/TypeScript.

interface TodayProps extends RouteComponentProps {
  dailyObds: IDailyObd[] | undefined;
}

const Today: React.FC<TodayProps> = ({ dailyObds }) => { }

Since it is a page you will be navigating to, you will also need the RouteComponentProps

1 Like

Hi Aaron,
Thanks a ton for your reply.
I have implemented this interface and now I’m getting another error:

Type '{ dailyObd: RouteComponentProps<any, StaticContext, {}>; }' is missing the following properties from type 'TodayProps': history, location, match  TS2739

It points now to the <Today /> component in the route’s render prop as the source of the error.

Thanks in advance for your consideration.

Here is today.tsx now:

const Today: React.FC<TodayProps> = ({dailyObd})=>{
  return (
    ...
  )
}

interface TodayProps extends RouteComponentProps{
  dailyObd: dailyObd | undefined
}

export default Today

And App.tsx:

const App: React.FC = () => {
  const [dailyObds, setDailyObds] = useState<dailyObds>()
  setDailyObds([{
    title: 'first',
    complete: false
  }])

  return (
    <IonApp>
      <IonReactRouter>
        <IonSplitPane contentId="main">
          <Menu />
          <IonRouterOutlet id="main">
            <Route path="/page/today" render={(dailyObds)=>(<Today dailyObd={dailyObds} /> )} />
          </IonRouterOutlet>
        </IonSplitPane>
      </IonReactRouter>
    </IonApp>
  )
}

interface dailyObd{
    title: string
    completed: boolean
}

interface dailyObds extends Array<dailyObd>{}

export default App;

I have tried to make various other things extend RouteComponentProps to resolve the missing properties error, but then I just end up getting another error elsewhere, so I think I’m doing something wrong still, or perhaps multiple other things wrong.

I think I’ve made progress.
I changed the interface name formatting to meet convention, so dailyObd & dailyObds are now DailyObd & DailyObds.
I added those interfaces also to Today.tsx and in TodayProps changed the prop type of dailyObd to be DailyObds, which is what I expect the incoming property value to be.

Now it is giving me this error:

Type 'RouteComponentProps<any, StaticContext, {}>' is missing the following properties from type 'DailyObds': length, pop, push, concat, and 28 more.ts(2740)
Today.tsx(22, 3): The expected type comes from property 'dailyObd' which is declared here on type 'IntrinsicAttributes & TodayProps & { children?: ReactNode; }'

So it is missing the properties of an array, since DailyObds is extending an array of DailyObd objects.
What in the application is of type ‘RouteComponentProps<any, StaticContext, {}>’ and why is it being typed checked against DailyObds? The only place where RouteComponentProps appears in the application is when TodayProps extends it; I tried also having TodayProps extend DailyObds, but that did not resolve the error.

Updated TS
Today.tsx:


const Today: React.FC<TodayProps> = ({dailyObdProp})=>{
  return (
    <IonPage>
      <IonContent>
        <IonText>{dailyObdProp.map((obd)=>(
          <p>{obd.title}: {obd.completed?'Done':'Not Done'}</p>
        ))}</IonText>>
      </IonContent>
    </IonPage>
  )
}

interface TodayProps extends RouteComponentProps{
  dailyObdProp: DailyObds
}

interface DailyObd{
  title: string
  completed: boolean
}

interface DailyObds extends Array<DailyObd>{}

export default Today

App.tsx:

const App: React.FC = () => {
  const [dailyObds, setDailyObds] = useState<DailyObds>()

  setDailyObds([{
    title: 'First',
    completed: false
  }])

  return (
    <IonApp>
      <IonReactRouter>
        <IonSplitPane contentId="main">
          <Menu />
          <IonRouterOutlet id="main">
            <Route path="/page/today" render={(dailyObds)=>(<Today dailyObdProp={dailyObds} /> )} />
          </IonRouterOutlet>
        </IonSplitPane>
      </IonReactRouter>
    </IonApp>
  )
}

interface DailyObd{
    title: string
    completed: boolean
}

interface DailyObds extends Array<DailyObd>{}

export default App;

is not correct, what are you trying to do here?

Apologies, I don’t see that piece of code in anything that I’ve shared. It is written most recently as:

interface DailyObds extends Array<DailyObd>{}

that is not correct? what is the {} doing? Try just using the code i provided?

I think something isn’t being rendered properly when the code snippets are being quoted.
Just so we’re clear, you’re seeing it written as “interface DailyObds extends Array<DailyObd>{}” right?
The {} at the end of it is the necessary part of the interface declaration, where the actual properties are typed. Since I’m not actually typing out any additional properties, just declaring that it is an array of DailyObd objects, the brackets are empty.
What I’m trying to do is declare that DailyObds is of the type of an Array with DailyObd objects inside of it.
I want the App state to have an array called DailyObds with DailyObd objects inside of it. I want to be able to map and render that array in the Today component and modify it elsewhere. This is why I wish to have the DailyObds state property passed down to Today. I’m trying not to use Redux if at all possible.

Thank you again for your consideration.

Hi Aaron,
Thanks again for your input; I think that I have resolved the issue for the most part.
In the route’s render prop, the anonymous function has a variable passed into it:

<route render={(dailyObd)=><Today dailyObdProp={dailyObd} />

Through rigorous console logging, I found that, in Today.tsx, the variable named “dailyObd” that is being received is not the one from my earlier useState, it is one that has the properties of a RouteComponentProps; this is why TypeScript kept giving me errors: the variable being passed in was not the one that I typed as a DailyObds. I tried having DailyObds also extend RouteComponentProps so that it has all of those properties too, but it seems that no matter what, whatever I set as the variable in the route’s render anonymous function is replaced by something else.
It is working now that I have left that anonymous function variable free.
Is this ok/good practice, or should I change something here?
App.tsx:

const App: React.FC = () => {

  const [dailyObds, setDailyObds] = useState<DailyObd[]>([{
    title: 'first',
    completed: false
  },{
    title: 'second',
    completed: true
  }])

  return (
    <IonApp>
      <IonReactRouter>
        <IonSplitPane contentId="main">
          <Menu />
          <IonRouterOutlet id="main">
            <Route path="/page/today" render={()=>(<Today dailyObdsProp={dailyObds} /> )} />
            <Redirect from="/" to="/page/Inbox" exact />
          </IonRouterOutlet>
        </IonSplitPane>
      </IonReactRouter>
    </IonApp>
  )
}

interface DailyObd{
  title: string
  completed: boolean
}

export default App

Today.tsx:

const Today: React.FC<Today> = (dailyObdsProp)=>{
  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonButtons slot="start"><IonMenuButton /></IonButtons>
          <IonTitle>Today's Obds</IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent>
        <IonText>
          {
            dailyObdsProp.dailyObdsProp.map(
              obd=>(
                <p>{obd.title} - {obd.completed ? 'Completed' : 'Uncomplete'}</p>
              )
            )
          }
        </IonText>
      </IonContent>
    </IonPage>
  )
}

interface Today{
  dailyObdsProp: DailyObd[]
}
interface DailyObd{
  title: string
  completed: boolean
}
export default Today

The above is working exactly as I had expected/wanted.