开发者问题收集

如何在 TypeScript 中使用嵌套对象?类型“object”上不存在属性

2021-11-19
3715

我有一个运行良好的 React/GraphQL 小型应用程序,我正在尝试向其中添加 TypeScript,因为我对 TypeScript 不熟悉,正在尝试学习它。我有一个 GraphQL API 端点,它返回产品及其信息。使用 React,我将产品存储在一个状态中,然后使用 JSX 呈现每个产品。

我创建了一个类型 Product ,其中包含我期望 API 返回的信息,但它也返回了嵌套对象,我尝试的一切都触发了 TypeScript 错误。这是 API 返回内容的简化示例:

{
    "data": {
        "products": [
            {
                "productName": "Soda",
                "code": "sod",
                "prices": {
                    "nationalPrices": {
                        "localPrices": [
                            {
                                "pricePerUnit": "1.99"
                            }
                        ],
                        "regionalPrices": [
                            {
                                "pricePerUnit": "2.49"
                            }
                        ]
                    },
                    "vendorPrices": {
                        "localPrices": [
                            {
                                "pricePerUnit": "1.49"
                            }
                        ]
                    }
                }
            },
            // more products... 
        ]
    }
}

这是我目前拥有的解决方案。 codeproductNameprices 运行良好,但 nationalPrices 触发了 TypeScript 错误 property nationalPrices does not exist on type 'object' 。我该怎么做才能修复此错误?

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>
        </>
    )
}
2个回答

Product 不包含 nationalPrices 属性。Product.prices 包含。我们可以设置一个包含 Product.prices 中预期内容的 Prices 类型,并使用它来定义 Product 对象的 prices 属性。

type Prices = {
    nationalPrices: nationalPricesObject;
    vendorPrices: someOtherPricesObject;
}

type Product = {
    code: string;
    productName: string;
    prices: Prices;
}
James
2021-11-19

在 TypeScript 中使用 object 比较棘手,一般不推荐使用。这里有两个问题:

  1. object 是一种模棱两可的类型,因此您不能使用 prices.nationalPrices ,因为 nationalPrices 不存在于 object 类型上。>
  2. 修复此问题后,您还会遇到一个错误,即 localPrices[0] 属于 object 类型,但没有 pricePerUnit

要修复这些问题,请使您的类型更具体:

type nationalPricesObject = {
    localPrices: { pricePerUnit: number; }[]; // assuming this is number?
}

type Product = {
    code: string;
    productName: string;
    prices: nationalPricesObject;
}

最后,按照惯例,TypeScript 中的类型应为 PascalCase ,并且应优先使用接口。因此,我会将您的代码更改为:

interface Price {
  pricePerUnit: number;
}

interface NationalPrices {
    localPrices: Price[];
}

interface Product {
    code: string;
    productName: string;
    prices: NationalPrices;
}
Kevin Koehler
2021-11-19