TypeScript Partials:如何将特定字段从一个对象映射到另一个对象

TypeScript Partials: How to map specific fields from an object to another object

我正在研究一项从某些电子商务中检索产品列表的功能 API。 我正在尝试添加从产品中请求特定字段的功能,删除不必要的字段。

这是代码:

    interface Product {
     images: string[],
     title: string;
     id: number;
     currency: string;
     price: number;
     created: string | Date;
     description: string; 
    }
    
    const getProducts = (selectedProperties: (keyof Product)[]) => {

      // imagine this is a call to an API to get a list of products 
      const products: Product[] = [
                        {
                            id: 1,
                            images: [],
                            title: 'a shirt',
                            currency: "USD",
                            price: 10,
                            created: "2021-04-29T11:21:53.386Z",
                            description: "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."
                         }
                     ];

    if(selectedProperties?.length){
        return products.map(product => {
            const result: Partial<Product> = {};

            selectedProperties.forEach(prop => {
                result[prop] = product[prop]; // <--- This line returns the error: Type 'string | number | string[] | Date' is not assignable to type 'undefined'. Type 'string' is not assignable to type 'undefined'
            })

            return result;
        })
    }

    return products;
}

这是一个 link 代码沙箱,其中包含错误,您可以自己查看:link(查看第 30 行)

我到底做错了什么导致 TypeScript 错误?

这里的问题是编译器将prop的类型推断为keyof Product,这是一个宽类型,对应多个可能的字符串。虽然 you 明白 result[prop] = product[prop] 应该没问题,因为两者都引用了同一个名为 prop 的确切值,但编译器只真正看到 类型 这些东西。它看不出它和 result[prop2] = product[prop1] 之间的区别,其中 prop2prop1 都是 keyof T。您会同意这样的行是错误的,除非您可以将 prop1prop2 限制为完全相同的文字键类型。

这是TypeScript的痛点; microsoft/TypeScript#30769, the change made for TypeScript 3.5 responsible for this checking... it improved soundness, but at the expense of adding some false positives like this. The specific problem with copying properties is an open issue at microsoft/TypeScript#32693. This comment 中的一些讨论暗示 TS 团队已意识到该问题,并认为应该采取一些措施来支持将属性从一个对象复制到另一个对象。但谁知道这会在何时或是否会真正发生。如果你关心你可能想去那里给它一个,但我怀疑这会产生很大的影响。


现在继续进行的方法可能是在 K extends keyof Product 中进行回调 generic 并使 prop 的类型为 K:

selectedProperties.forEach(<K extends keyof Product>(prop: K) => {
  result[prop] = product[prop];  // no error
})

这会使错误消失。从技术上讲,这与以前有同样的问题,因为没有什么能阻止 K 成为完整的联合 keyof Product,但是编译器明确允许从 Product[K]Product[K] 的赋值给泛型 K,尽管存在这种潜在的不健全。

Playground link to code