I have a React/GraphQL small application working fine, and I'm trying to add TypeScript to it, as I'm new to TypeScript and trying to learn it. I have a GraphQL API endpoint that is returning products and information on those products. Using React, I'm storing products in a state and then rendering each product using JSX.
I created a type Product
with the information that I expect the API to return, but it's also returning nested objects, and everything I tried triggers a TypeScript error. This is a simplified example of what the API is returning:
{
"data": {
"products": [
{
"productName": "Soda",
"code": "sod",
"prices": {
"nationalPrices": {
"localPrices": [
{
"pricePerUnit": "1.99"
}
],
"regionalPrices": [
{
"pricePerUnit": "2.49"
}
]
},
"vendorPrices": {
"localPrices": [
{
"pricePerUnit": "1.49"
}
]
}
}
},
// more products...
]
}
}
And this is the solution I currently have. code
, productName
and prices
are working fine, but nationalPrices
is triggering a TypeScript error property nationalPrices does not exist on type 'object'
. What can I do to fix this error?
type nationalPricesObject = {
localPrices: object[];
}
type Product = {
code: string;
productName: string;
prices: object;
nationalPrices: nationalPricesObject;
}
function ProductList() {
const [products, setProducts] = useState < Product[] > ([]);
const { loading, data, error } = useQuery(LOAD_PRODUCTS);
useEffect(() => {
if (data) {
setProducts(data.products);
}
}, [data]);
return (
<>
<div>
{products.map(p =>
(
<div>
<ProductCard
productName={p.displayName}
code={p.code}
// simplified code below for sake of clearity
pricePerUnit={p.prices.nationalPrices.localPrices[0]['pricePerUnit']}
/>
</div>
))}
</div>
</>
)
}
CodePudding user response:
Product doesn't contain a nationalPrices
property. Product.prices does. We can set a type Prices which contains the stuff expected in Product.prices, and use that to define the prices property of the Product object.
type Prices = {
nationalPrices: nationalPricesObject;
vendorPrices: someOtherPricesObject;
}
type Product = {
code: string;
productName: string;
prices: Prices;
}
CodePudding user response:
Usage of object
is tricky in typescript, and generally not recommended. You have two problems here:
object
is an ambiguous type, so you cannot useprices.nationalPrices
becausenationalPrices
does not exist on typeobject
- Once you fix this, you will also encounter an error that
localPrices[0]
which is of typeobject
does not havepricePerUnit
To fix these, make you types more specific:
type nationalPricesObject = {
localPrices: { pricePerUnit: number; }[]; // assuming this is number?
}
type Product = {
code: string;
productName: string;
prices: nationalPricesObject;
}
Lastly, by convention, types in typescript should be PascalCase
, and interfaces should be preferred. So, I would change your code to look like:
interface Price {
pricePerUnit: number;
}
interface NationalPrices {
localPrices: Price[];
}
interface Product {
code: string;
productName: string;
prices: NationalPrices;
}