如何让 Typescript 推断对象的键但定义其值的类型? [英] How to make Typescript infer the keys of an object but define type of its value?

查看:24
本文介绍了如何让 Typescript 推断对象的键但定义其值的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想定义一个对象的类型,但让 typescript 推断键,并且没有太多开销来创建和维护所有键的 UnionType.

I want to define the type of an object but let typescript infer the keys and don't have as much overhead to make and maintain a UnionType of all keys.

输入一个对象将允许所有字符串作为键:

Typing an object will allow all strings as keys:

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

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

Inferring the whole object will show an error and allows all kind of values:

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

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

The closest I got was this, but it don't want to maintain the set of keys like that:

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

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

Is there a better way to define the object without maintaining the set of keys?

推荐答案

所以你想要推断键但限制值类型并使用 多余的属性检查 禁止额外的属性.我认为获得这种行为的最简单方法是引入一个辅助函数:

So you want something that infers keys but restricts the value types and uses excess property checking to disallow extra properties. I think the easiest way to get that behavior is to introduce a helper function:

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

这个辅助函数推断类型 T 来自 et 的映射类型.现在你可以像这样使用它:

This helper function infers the type T from the mapped type of et. Now you can use it like this:

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

结果 elementsTyped 的类型(一旦您修复错误)将推断出键 squaretriangleline,值为 ElementType.

The type of the resulting elementsTyped will (once you fix the error) have inferred keys square, triangle, and line, with values ElementType.

希望对你有用.祝你好运!

Hope that works for you. Good luck!

这篇关于如何让 Typescript 推断对象的键但定义其值的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆