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}
);