Typescript将对象的const数组转换为类型化索引查找对象


const cars = [
{ id: 'id1', name: 'ford' },
{ id: 'id2', name: 'audi' },
{ id: 'id3', name: 'bmw' },
] as const;
type CarId = typeof cars[number]['id'];
const carIndexes = cars.reduce((acc, car, i) => ({ ...acc, [car.id]: i }), {});
console.log(carIndexes);

这个代码运行良好,并打印出

{ id1: 0, id2: 1, id3: 2 }

carIndexes给了我一个映射,允许我通过它们的id来查找每辆车的索引,但我希望carIndexes是强类型的。当我将其类型签名更改为{ [K in CarId]: number }:时

const carIndexes: { [K in CarId]: number } = cars.reduce((acc, car, i) => ({ ...acc, [car.id]: i }), {});

我得到错误:

error TS2739: Type '{}' is missing the following properties from type '{ id1: number; id2: number; id3: number; }': id1, id2, id3

我希望使用普通对象,而不是Map,因为类型为{ [K in CarId]: number }的对象保证查找任何CarId的索引都不会失败。

AFAIK,如果不手动转换为{[K in CarId]: number},typescript就无法检测到cars.reduce((acc, car, i) => ({ ...acc, [car.id]: i }), {})(或其他方式)将返回一个以整个CardId为索引的对象。

我认为您必须显式键入reduce accumulator值:

const cars = [
{ id: 'id1', name: 'ford' },
{ id: 'id2', name: 'audi' },
{ id: 'id3', name: 'bmw' },
] as const;
type CarId = typeof cars[number]['id'];
const carIndexes = cars
.reduce(
(acc, car, i) => (
{ ...acc, [car.id]: i }
),
{} as { [K in CarId]: number }
);
console.log(carIndexes);

在这种情况下,类型安全的最佳尝试可能是使用相应的部分类型:

let carIndexes: Partial<{ [key in CarId]: number }> = {};
for (let i = 0; i < cars.length; ++i) {
carIndexes[cars[i].id] = i;

// note that following line would not compile due to TS2339: Property 'OTHER_PROPERTY' does not 
// exist on type 'Partial<{ id1: number; id2: number; id3: number; }>'
// carIndexes.OTHER_PROPERTY = 0;
}

事实上,使用其他一些答案提出的包含显式强制转换的reduce()函数可以确保几乎没有静态类型安全。例如,如果我犯了如下拼写错误,代码仍然可以编译:

const carIndexes: { [K in CarId]: number } = cars.reduce(
(acc, car, i) => ({ 
...acc,
//following line should not compile as there is no property "id" on typeof carIndexes
id: i 
}),
{} as {[K in CarId]: number}
);

相关内容

  • 没有找到相关文章

最新更新