【问题标题】:Object with one key's value dependent on another key's value [duplicate]一个键的值依赖于另一个键的值的对象[重复]
【发布时间】:2022-12-03 18:07:44
【问题描述】:

实现这种效果的最佳方式是什么(注意:这不是有效的语法 - 将其视为伪代码):

type Config = {
  [key: string]: <T> {
    params: T,
    doSth: (params: T) => void,
  },
}

IE。通用 T 类型对于每个键的值(它本身是一个对象)都是不同的,但同时它在不同字段下的该值(对象)中被重用。此外,T 派生自 params 字段。有了它我可以做到:

const config: Config = {
  a: {
    params: { x: 123 },
    doSth: params => {}, // Type of "params" is "{ x: 123 }"
  },
  b: {
    params: { y: 'asd' },
    doSth: params => {}, // Type of "params" is "{ y: 'asd' }"
  },
}

令我惊讶的是,谷歌搜索并没有产生匹配的结果,尽管它看起来相对有用图案- 有很多类似的问题,但并不完全相同。我尝试应用的一些解决方案都失败了。

【问题讨论】:

  • 您正在寻找 existentially qualified generics,也称为“存在类型”,但 TypeScript 不直接支持它们(大多数语言也不支持泛型)。有一些方法可以模拟它们(如this)或解决它们(如@TJCrowder 的回答)。有关详细信息,请参阅链接问题的答案。

标签: typescript


【解决方案1】:

在 TypeScript 中,有些事情您无法单独使用类型来完成,有时您需要一个函数来提供帮助,即使该函数在运行时实际上没有做任何事情。我思考这是那些时代之一。这是一个接近您所描述内容的函数示例:

type ConfigEntry<T extends object> = {
    params: T;
    doSth: (params: T) => void;
};

function makeConfigEntry<T extends object>(obj: ConfigEntry<T>): ConfigEntry<T> {
    return obj;
}

请注意 ConfigEntry 如何让我们将使用该类型的两个地方联系起来。您将在定义属性值时使用该函数:

const config = {
    a: makeConfigEntry({
        params: { x: 123 },
        doSth: params => {}, // Type of `params` is `{ x: number; }`
        //     ^?
    }),
    b: makeConfigEntry({
        params: { y: "asd" },
        doSth: params => {}, // Type of `params` is `{ y: string; }`
        //     ^?
    }),
};

请注意,上面没有 Config 类型注释。 TypeScript 将从对象初始值设定项中推断出它。

但是请注意params 上的类型并不是您想要的。 TypeScript 不会从您的对象中推断出类型 { x: 123; }{ y: "asd"; }。它会推断出{ x: number; }{ y: string; },或者如果您定义对象as const,它会推断出{ readonly x: 123; }{ readonly y: "asd"; }

const config = {
    a: makeConfigEntry({
        params: { x: 123 } as const,
        doSth: params => {}, // Type of `params` is `{ readonly x: 123; }`
        //     ^?
    }),
    b: makeConfigEntry({
        params: { y: "asd" } as const,
        doSth: params => {}, // Type of `params` is `{ readonly y: "asd"; }`
        //     ^?
    }),
};

这可能不是您想要的,但我认为它很接近,可能是当今 TypeScript 所能达到的与您想要的最接近的几种方法之一。

以上Playground example

【讨论】:

  • 那行得通-谢谢。这也是我之前尝试过的解决方案之一,但坦率地说,正如您所指出的那样 - 感觉非常像黑客。没有那个伪造的功能,这不能在 TS 中完成吗?
  • @jaloc 没有函数,TypeScript 没有动机去推断类型。这有点像花朵上的花瓣吸引传粉者。因此,如果我们只有那个 Config 类型,TypeScript 就不会尝试推断 T。
  • 这实际上可以通过一个函数和对该函数的一次调用来完成。你可能会得到一些想法here。祝你好运!
  • @jalooc - 正如 catgirlkelly 所说,显然我们需要它来传递泛型。我问了其中一位真正了解 TypeScript 的人(我想是 Titian Cernicova Dragomir)他是否知道是否有某种类型的计划——只针对我们需要这些无所事事的功能的情况,他说他不知道不知道有没有——可能是因为功能有效,即使它们感觉很老套。 :-)(需要说明的是:他不在 TypeScript 项目团队中,他只是对它了如指掌,而且消息灵通。)
  • 在这种情况下,您将如何键入 config 变量?就像{ [x: string]: ConfigEntry },但您在 ConfigEntry 上缺少一个泛型?你如何解决这个问题?
猜你喜欢
  • 2016-10-22
  • 2021-05-30
  • 1970-01-01
  • 1970-01-01
  • 2017-08-03
  • 2017-05-24
  • 2020-09-26
  • 2022-11-22
  • 1970-01-01
相关资源
最近更新 更多