如何强制对象的键仅在它们实际包含在联合类型的数组中时才有效?
type Category = 'software' | 'hardware' | 'books'
type Item = {
categories: Category[];
registry: Partial<{[key in Category]: string}>
}
//Should be invalid because 'books' is not in categories array:
const myInValidItem: Item = {
categories: ['software', 'hardware'],
registry: { books: 'blabla' }
}
答案 0 :(得分:0)
最简单的解决方案可能是定义一个辅助函数,以检查相关的registry
和categories
类型:
function createParts<T extends Category[]>(
categories: T, registry: { [K in T[number]]?: string }
) {
return { categories, registry };
}
const myInValidItem: Item = createParts(
["software", "hardware"],
{ books: "blabla" }
) // error, books not contained
您还可以创建限制性更强的Item
类型并将其用于函数参数:
const myInValidItem = {
categories: ['software', 'hardware'],
registry: { books: 'blabla' }
} as const // const assertion here to preserve the tuple type
type ConstrainedItem<T extends readonly Category[]> = {
categories: T;
registry: Partial<{ [key in T[number]]: string }>
}
declare function doSomething<T extends readonly Category[]>(item: ConstrainedItem<T>): void
doSomething(myInValidItem) // error
doSomething(myValidItem)
答案 1 :(得分:0)
与ford04提出的解决方案相同,但解释略有不同:
type Category = 'software' | 'hardware' | 'books';
const createItem = <T extends Category>(item: {
categories: T[];
registry: { [key in T]?: string }
}) => item;
//Should be invalid because 'books' is not in categories array:
const myInValidItem = createItem({
categories: ['software', 'hardware'],
registry: { 'books': 'blabla' }
});