简化问题:假设我们有一个图,并且每个 node 都有其唯一的名称.如果我们有一个类型,将图的边描述为从名称到 node 名称列表的映射,我们将如何做到这一点?

从逻辑上讲,这应该是这样的:

type EdgesT = { [name: string]: Exclude<keyof EdgesT, name>[]; };

但是,即使没有排除部分,我也无法使该描述起作用,因为它总是将Keyof EdgesT视为字符串.

或者,如果函数参数也有同样的问题,我们可以这样做:

type BuildEdges<T> = { [Name in keyof T]: Exclude<keyof T, Name>[]; };

const fn = <T>(edges: BuildEdges<T>) => null;

对于这种明确的情况,这是可行的.但如果我们要从类型参数中获得更多信息(对于其他东西),我们就不能.对于类型参数,<T>可以,<T extends Record<string, any>>可以,<T extends Record<string, unknown>>可以,但其他任何东西都不能.例如,<T extends Record<string, number>>不能工作--有人知道为什么吗?

有没有想过解决这种情况、取得更多成就或描述这种限制的 idea ?

推荐答案

在Typescript 中没有特定的类型是这样工作的.从根本上讲,它是generic.您不能将其表示为BuildEdges<T>中的每一个可能的T的大union.从概念上讲,它将是一种特殊的泛型类型,称为102 generic...你想说"一个值是BuildEges,如果有existsT是有效的".但是TypeScrip并不直接支持存在主义类型(尽管有一个开放的功能请求,如microsoft/TypeScript#14466).在另一个实现了这一点的领域中,也许您可以编写

// THIS IS NOT VALID TYPESCRIPT, DO NOT TRY:
type BuildEdges = <exists T>{ [K in keyof T]: Exclude<keyof T, K> []; }

但现在,你需要做一些其他的事情.


有很多方法可以在TypeScript中编码存在类型,但它们最终会比我认为你需要的更复杂. 相反,您可以将其保留为常规泛型类型,

type BuildEdges<T> = { [K in keyof T]: Exclude<keyof T, K>[]; };

然后编写一个助手函数来推断T给定值.不管怎样,这是你的方法,但你似乎没有找到好的constraint分.以下是我会怎么做:

const fn = <T extends BuildEdges<T>>(edges: T) => null;

这是一个递归约束.它实质上验证了T是正确的BuildEdges<T>,从而产生了以下所需的行为:

fn({ a: ["c"], b: ["a"], c: ["a", "b"] }); // okay
fn({ a: ["c"], b: ["a"], c: ["a", "c"] }); // error!

Playground link to code

Typescript相关问答推荐

类型脚本如何将嵌套的通用类型展开为父通用类型

您可以创建一个类型来表示打字员吗

React-Native运行方法通过监听另一个状态来更新一个状态

为什么TypeScript失go 了类型推断,默认为any?''

如何为父类构造函数中的修饰属性赋值?

如何使默认导出与CommonJS兼容

通过按键数组拾取对象的关键点

如何调整对象 struct 复杂的脚本函数的泛型类型?

如何在Reaction Query Builder中添加其他字段?

如何 bootstrap TS编译器为类型化属性`T`推断正确的类型?

如何在ANGLE中注册自定义验证器

Angular 自定义验证控件未获得表单值

有没有办法取消分发元组的联合?

如何将对象数组中的键映射到另一种对象类型的键?

如何正确调用创建的类型?

创建一个TypeScrip对象并基于来自输入对象的约束定义其类型

具有匹配功能的TS通用事件处理程序

错误TS7030:并非所有代码路径都返回值.";由tsfig.json中的";Strong";:False引起

递归JSON类型脚本不接受 node 值中的变量

const 使用条件类型时,通用类型参数不会推断为 const