如何使Typescript推断对象的键但定义其值的类型?

时间:2019-02-08 18:31:38

标签: typescript

我想定义一个对象的类型,但是让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

推断整个对象将显示一个错误并允许所有类型的值:

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; }'.
}

我最接近的是这个,但它不想维护这样的键集:

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"'.

有没有一种更好的方法来定义对象而不维护键集?

1 个答案:

答案 0 :(得分:5)

因此,您需要一些可以推断键但限制值类型并使用excess property checking来禁止额外属性的内容。我认为获得该行为的最简单方法是引入一个辅助函数:

// 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;

此帮助函数从映射类型Tinfers类型et。现在,您可以像这样使用它:

const elementsTyped = asElementTypes({
  square: { nodes: 4, symmetric: true },
  triangle: { nodes: 3 },
  line: { nodes: 2, notSymmetric: false /* error where you want it */} 
});

生成的elementsTyped的类型将(一旦您纠正错误)具有推断的键squaretriangleline,其值为ElementType

希望对您有用。祝你好运!