I am building a expense tracker app using react + typescript
expense_type.ts
export type IState = {
id : number,
text : string,
amount : number
}
export type IinitialStateType = {
transactions : IState[]
}
export type IActions = {
type : string,
payload : any
}
export type contextProps = {
transactions : IState[];
addTransaction: (trans: IState) => void;
deleteTransaction: (id: number) => void;
}
Then I have used API Context and reducer and initialize my initial states in Global State file
GlobalState.tsx
import React , {createContext,useReducer} from 'react'
import {IinitialStateType,contextProps} from '../Types/expense_type'
import AppReducer from './AppReducer'
const initailState : IinitialStateType = {
transactions : [
{ id: 1, text: 'Flower', amount: -20 },
{ id: 2, text: 'Salary', amount: 300 },
{ id: 3, text: 'Book', amount: -10 },
{ id: 4, text: 'Camera', amount: 150 }
]
}
export const GlobalContext = createContext<Partial<contextProps>>({})
export const GlobalProvider : React.FC = ({children}) : JSX.Element => {
const [state,dispatch] = useReducer(AppReducer,initailState)
return(
<GlobalContext.Provider value={{
transactions : state.transactions
}}>
{children}
</GlobalContext.Provider>
)
}
Then I have used context in TransactionList.tsx component and map all the initial state values and pass those values to child component Transaction.tsx where those values are receiving
TransactionList.tsx
import React ,{useContext}from 'react'
import {GlobalContext} from './../Context/GlobalState'
import {contextProps,IinitialStateType,IState} from '../Types/expense_type'
import {Transaction} from './Transaction'
export const TransactionList : React.FC = () : JSX.Element => {
const {transactions} : any = useContext(GlobalContext)
return (
<>
<h3>History</h3>
<ul className="list">
{
transactions.map( (transaction : IState , index : number) =>
(<Transaction key={index} transaction={transaction} />
))
}
</ul>
</>
)
}
Transaction.tsx
import React from 'react'
import {IinitialStateType} from '../Types/expense_type'
export const Transaction : React.FC<IinitialStateType>= (props : any) : JSX.Element => {
let sign : string = props.transaction.amount > 0 ? '+' : '-'
return (
<>
<li className={props.transaction.ammount < 0 ? "minus" : "plus"}>
{props.transaction.text}{" "}
<span>
{sign}${Math.abs(props.transaction.ammount)}
</span>
<button
className="btn-delete"
>
x
</button>
</li>
</>
)
}
But while compiling it gives error in TransactionList.tsx file
TypeScript error in C:/Users/Abdul Rehman Aziz/Desktop/New folder/expense-tracker-ts/src/Components/TransactionList.tsx(14,88): Type '{ key: number; transaction: IState; }' is not assignable to type 'IntrinsicAttributes & IState & { children?: ReactNode; }'. Property 'transaction' does not exist on type 'IntrinsicAttributes & IState & { children?: ReactNode; }'. TS2322
12 | <h3>History</h3>
13 | <ul className="list">
> 14 | { transactions.map( transaction => (<Transaction key={transaction.id} transaction={transaction} />)) }
| ^
15 | </ul>
16 | </>
17 | </>
You have to specify the type of Props for React.FC, not state. Like this:
export const Transaction: React.FC<{ transaction: IState }> = (
props: any
I have also made a working sample: https://codesandbox.io/s/focused-sanderson-e6zlm?file=/src/App.tsx
Your Transaction component is expecting props of type IinitialStateType and as per your definition of that type it does not has a property called transaction and as well it does not receive one item but an array. If you change the Type of your props in the Transaction component to something like
export const Transaction : React.FC<IState>= (props : any) : JSX.Element => {
...
}
it should help.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.