Reputation: 228
So I've just started to combine react, redux (react-redux) and typescript. But I can't seem to figure out something here, namely, why the child components inside of the App component require all of the props that I pass into the App component.
App component:
const App = ({contacts, user, activeUserId}: ApplicationState) => (
<div className="App">
<Sidebar contacts={contacts} />
<Main user={user} activeUserId={activeUserId}/>
</div>
);
const getContacts = ({contacts, user, activeUserId}: ApplicationState) => ({contacts, user, activeUserId});
export default connect(getContacts)(App);
Sidebar component:
const Sidebar = ({contacts}: ApplicationState) => {
let contactsValues: Array<Contacts> = contacts && Object.values(contacts);
return (
<aside className="Sidebar">
{contactsValues && contactsValues.map((contact: Contacts) => <User user={contact} key={contact.user_id}/>)}
</aside>
)
}
I don't think there's any reason to list the Main component here as well since its only an empty component but gives the same errors, so I will just go ahead an list the Interfaces:
export default interface Contacts {
email: string,
name: string,
profile_pic: string,
status: string,
user_id: string
}
export default interface ApplicationState {
contacts: Contacts,
user: object,
activeUserId: string | null
}
Actual error code: "TS2739: Type '{ contacts: Contacts; }' is missing the following properties from type 'ApplicationState': user, activeUserId"
So, both components ask to have all the props injected into them, even though they are not required inside the component itself. If I supply the components the everything works and I get no errors.
I'm pretty sure there's something wrong with my syntax or 'wiring' of the types.
Can we also get a explanation or a decent link to docs/materials that help us understand why this is happening?
If there is anything else that I should be including please let me know and I will provide!
Edit:
I've actually realized that its important to show the Main component too because this one also causes problems and some of the fixes you guys have suggested only fix the Sidebar component but not the Main.
Main component:
import React from "react";
import "./Main.scss";
import ApplicationState from "../../models/ApplicationState";
const Main = ({user, activeUserId}: ApplicationState) => {
return (
<main className="Main">
Main Stuff
</main>
)
}
Edit:
From what I've experimented with all of these answers I think the best solution would be to make everything in the interfaces optional, but if I do this then the contactsValues variable inside the Sidebar component throws: TS2322: Type 'any[] | undefined' is not assignable to type 'Contacts[]'. Type 'undefined' is not assignable to type 'Contacts[]'..
Upvotes: 2
Views: 638
Reputation: 13933
The problem is with your Sidebar component where you just passed the contacts and defined its type to be ApplicationState... Change Sidebar parameter as:
const Sidebar = (contacts: Contacts) => {
let contactsValues: Array<Contacts> = contacts && Object.values(contacts);
return
( <aside className="Sidebar">
{contactsValues && contactsValues.map((contact: Contacts) =>
<User user={contact} key={contact.user_id}/>
)}
</aside> ) }
Another way to resolve the error is to make interface attribute optional as:
Update
I think there is one more problem with the interfaces:
export default interface Contact { //It's a single object, So Contact is OK
email: string,
name: string,
profile_pic: string,
status: string,
user_id: string
}
export default interface ApplicationState {
contacts: Contact[], // I guess you need an array of Contacts
user?: object,
activeUserId?: string
}
And I think you are getting error because of wrong initialization. Change to
let contactsValues: Array<Contacts> = contacts ? Object.values(contacts): [] as Contact[];
Upvotes: 1
Reputation: 6603
Replace the Applicationstate interface with this :
export default interface ApplicationState {
contacts?: Contacts,
user?: object,
activeUserId?: string | null
}
Upvotes: 0
Reputation: 486
The problem is in this function
const Sidebar = ({contacts}: ApplicationState) => {
let contactsValues: Array<Contacts> = contacts && Object.values(contacts);
return (
<aside className="Sidebar">
{contactsValues && contactsValues.map((contact: Contacts) => <User user={contact} key={contact.user_id}/>)}
</aside>
)
}
the type { contacts: Contacts }
is not the same type ApplicationState
If you want to pass just contacts to your function you must create a new type or
make ApplicationState
like this
export default interface ApplicationState {
contacts: Contacts,
user?: object,
activeUserId?: string | null
}
Upvotes: 1