打字稿:为包含索引签名和密钥对的响应对象添加类型

Typescript: add typing for response object containing both index signature and key-pairs

我不确定为我从后端服务收到的响应对象添加打字稿类型的最佳方法:

{
    de49e137f2423457985ec6794536cd3c: {
        productId: 'de49e137f2423457985ec6794536cd3c',
        title: 'item 1',
    },
    d6623c1a2b843840b14c32685c212395: {
        productId: 'd6623c1a2b843840b14c32685c212395',
        title: 'item 2',
    },
    ids: [
        'de49e137f2423457985ec6794536cd3c',
        'd6623c1a2b843840b14c32685c212395',
    ],
}

它包含项目 ID 数组 string[] 以及索引签名 [id: string]: Item.

Typescript 似乎不喜欢在单个界面中同时拥有索引签名和数组。例如:

interface ItemList {
    [id: string]: Item;
    ids: string[];
}

我知道在使用索引签名时,其他属性需要 return 相同的类型。我是 Typescript 的新手,我有点不确定如何在不将 ids 移出项目对象的情况下处理这些数据?

interface ItemList {
    [id: string]: Item;
    ids: string[];
}
interface Item {
    productId: string;
    title: string;
}

const item: ItemList = {
    de49e137f2423457985ec6794536cd3c: {
        productId: 'de49e137f2423457985ec6794536cd3c',
        title: 'item 1',
    },
    d6623c1a2b843840b14c32685c212395: {
        productId: 'd6623c1a2b843840b14c32685c212395',
        title: 'item 2',
    },
    ids: [
        'de49e137f2423457985ec6794536cd3c',
        'd6623c1a2b843840b14c32685c212395',
    ],
};
console.log(item.ids.map((id: string) => item[id]));

错误

属性 'map' 在类型 'Item | string[]' 上不存在。

属性 'map' 在类型 'Item' 上不存在。

这里的简单修复是使用交集类型:

type ItemList = {
    [id: string]: Item;
} & {
    ids: string[];
}
interface Item {
    productId: string;
    title: string;
}

const item: ItemList = Object.assign({ // Can't build the object directly 
    de49e137f2423457985ec6794536cd3c: {
        productId: 'de49e137f2423457985ec6794536cd3c',
        title: 'item 1',
    },
    d6623c1a2b843840b14c32685c212395: {
        productId: 'd6623c1a2b843840b14c32685c212395',
        title: 'item 2',
    }
}, {
    ids: [
        'de49e137f2423457985ec6794536cd3c',
        'd6623c1a2b843840b14c32685c212395',
    ],
});
console.log(item.ids.map((id: string) => item[id]));

交集类型允许不一致,命名为属性 - 索引组合。 (请注意,这不是严格类型安全的,因为 item['ids'] 不像预期的那样 return Item,但在这种情况下它似乎是一个不错的 trade-off)