我想定义一个对象的类型,但是让typescript推断出键并且没有那么多的开销来制作和维护所有键的UnionType.
键入一个对象将允许所有字符串作为键:
const elementsTyped: {
[key: string]: { nodes: number, symmetric?: boolean }
} = {
square: { nodes: 4, symmetric: true },
triangle: { nodes: 3 }
}
function isSymmetric(elementType: keyof typeof elementsTyped): boolean {
return elementsTyped[elementType].symmetric;
}
isSymmetric('asdf'); // works but shouldn't
Run Code Online (Sandbox Code Playgroud)
推断整个对象将显示错误并允许所有类型的值:
const elementsInferred = {
square: { nodes: 4, symmetric: true },
triangle: { nodes: 3 },
line: { nodes: 2, notSymmetric: false /* don't want that to be possible */ }
}
function isSymmetric(elementType: keyof typeof elementsInferred): boolean {
return elementsInferred[elementType].symmetric;
// Property 'symmetric' does not exist on type '{ nodes: number; }'.
}
Run Code Online (Sandbox Code Playgroud)
我得到的最接近的是这个,但它不想像这样保持一组键:
type ElementTypes = 'square' | 'triangle'; // don't want to maintain that :(
const elementsTyped: {
[key in ElementTypes]: { nodes: number, symmetric?: boolean }
} = {
square: { nodes: 4, symmetric: true },
triangle: { nodes: 3 },
lines: { nodes: 2, notSymmetric: false } // 'lines' does not exist in type ...
// if I add lines to the ElementTypes as expected => 'notSymmetric' does not exist in type { nodes: number, symmetric?: boolean }
}
function isSymmetric(elementType: keyof typeof elementsTyped): boolean {
return elementsTyped[elementType].symmetric;
}
isSymmetric('asdf'); // Error: Argument of type '"asdf"' is not assignable to parameter of type '"square" | "triangle"'.
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来定义对象而不维护密钥集?
mar*_*eck 13
TypeScript4.9.0添加了satisfies关键字,可用于在推断键时约束对象的值。
type ElementValue = {
nodes: number;
symmetric?: boolean;
};
const elements = {
square: { nodes: 4, symmetric: true },
triangle: { nodes: 3 },
} satisfies Record<string, ElementValue>;
type Elements = typeof elements;
type ElementType = keyof Elements;
function isSymmetric(elementType: ElementType): boolean {
const element = elements[elementType];
return 'symmetric' in element && element.symmetric;
}
isSymmetric('asdf'); // doesn't work
Run Code Online (Sandbox Code Playgroud)
中间函数可用于在推断键时约束对象的值。
type ElementValue = {
nodes: number;
symmetric?: boolean;
};
function typedElements<T extends Record<string, ElementValue>>(o: T) {
return o;
}
const elements = typedElements({
square: { nodes: 4, symmetric: true },
triangle: { nodes: 3 },
});
type Elements = typeof elements;
type ElementType = keyof Elements;
function isSymmetric(elementType: ElementType): boolean {
const element = elements[elementType];
return 'symmetric' in element && element.symmetric;
}
isSymmetric('asdf'); // doesn't work
Run Code Online (Sandbox Code Playgroud)
所以你想要一些推断密钥但限制值类型的东西,并使用多余的属性检查来禁止额外的属性.我认为获得该行为的最简单方法是引入辅助函数:
// Let's give a name to this type
interface ElementType {
nodes: number,
symmetric?: boolean
}
// helper function which infers keys and restricts values to ElementType
const asElementTypes = <T>(et: { [K in keyof T]: ElementType }) => et;
Run Code Online (Sandbox Code Playgroud)
这个辅助函数从映射类型推断出类型.现在您可以像这样使用它:Tet
const elementsTyped = asElementTypes({
square: { nodes: 4, symmetric: true },
triangle: { nodes: 3 },
line: { nodes: 2, notSymmetric: false /* error where you want it */}
});
Run Code Online (Sandbox Code Playgroud)
该类型所产生的elementsTyped意志(一旦你修复错误)已经推断出密钥square,triangle以及line与价值ElementType.
希望对你有用.祝好运!