我目前正在做一个servienow项目,这个项目显然不太关注DX。这就是为什么我想添加一些类型定义,使它更不容易出错。
基本上,我有数据库的表,可以使用类检索。语法看起来或多或少像new Query("table").where("field", fieldValue)
。fieldValue
的类型取决于字段的类型。我正在提取表信息并将它们存储在 typescript 文件中。到目前为止,这是有效的。但是也有可能访问与表相关的字段,如下所示:new Query("table").where("ref.otherField", fieldValue)
类型可以无限嵌套,因为例如用户表可能有一个对管理器的引用,它再次指向用户表。这是我只想支持两个相关领域的方式,如果开发人员需要更多,我只想接受任何。
我的目标基本上是创建一个包含所有可能的字符串和相应值的类型,然后将此类型用于where函数。为此,我必须将引用字段的名称添加到引用表的字段中:
type AppendPrefix<prefix extends string, Object extends Record<string, any>> = {
[key in `${prefix}.${keyof Object}`]: key extends `${prefix}.${infer Field}`
? Object[Field] extends Reference<any>
? sys_id | null
: Object[Field]
: never;
};
到目前为止,这对于给定的前缀和表也是有效的。但是如果我有两个字段和两个不同的表,我就不能让它工作。然后只取这些表的重叠部分,例如,如果两个表都有一个名为name
的字段,我会得到如下内容:
{
...
"prefix1.name": string;
"prefix2.name": string;
}
我尝试像这样获取所有前缀类型:
type AddReferenceTable<Table extends keyof Tables.List, Field extends keyof Tables.List[Table]> = AppendPrefix<
Field,
GetReferenceTable<Table, Field>
>;
type GetReferenceTable<
Table extends keyof Tables.List,
Field extends keyof Tables.List[Table]
> = Tables.List[Table][Field] extends Reference<infer T>
? Tables.List[T]
: never;
下面是一个完整的代码示例:Playground
有人能告诉我我做错了什么吗?或者我试图解决问题的方法很糟糕,有更好的方法吗?
谢谢你!
1条答案
按热度按时间mbskvtky1#
因为你的实体引用的是自己的
(User.manager: User)
,这将导致无限递归,唯一合适的解决方案是限制递归的深度。您将需要根据您的用例来评估此值,但对于此解决方案,限制为2
让我们从算法开始:
ObjWithNoReference
是一个初始类型,没有引用其他表的属性ObjWithNoReference
ObjWithNoReference
的键),以确保我们只遍历引用的字段。{keyName: sys_id | null}
。ObjWithNoReference
和引用的表数据实施:
公用事业:
Prettify
-使IDE显示的类型更具可读性和线性(删除&
,. etc)ValueOf
-返回传递类型的所有值的并集UnionToIntersection
-将传递的并集转换为交集。解释here:DepthLimit
-表示最大参考深度的数字:深度检查机制说明:我们要递归调用的类型将接受
unknown[]
的额外泛型参数,默认为[]
。在每次递归调用时,我们都要将一个元素推到数组中,以增加它的长度。如果数组的长度等于DepthLimit
,则停止递归调用。所需类型:
首先,让我们使用mapped type选择不是对另一个表的引用的属性:
看看我们是否需要再深入一点。如果达到限制,则返回没有引用的字段:
为了检索引用其他表的字段,我们将使用Map类型,而初始类型具有省略键
ObjWithNoReference
:如果
T[K]
是一个引用,我们检索该able的名称,并将其放入infer
变量TableName
中,并调用该名称的表DesiredType
,深度级别增加。将结果放入ReferencedTable
:ReferencedTable
的预期形状为Record<string, unknown>
,其中键是表的键。但是,我们需要用当前表的键和.
作为这些键的前缀。由于我们必须在当前表的键下添加sys_id
,我们将手动添加它与交集:到目前为止,代码将给出类似于以下内容(仅包括引用字段):
我们需要得到
asset
,manager
的值,而不是整个对象,因为我们想要平面结构。我们将使用ValueOf
。如果我们将前面代码块中的示例结果传递给
ValueOf
,我们将得到:这不是预期的,因为
ValueOf
返回值的并集,我们需要使用UnionToIntersection
将其变成单个对象:这是需要的结构,但很难读懂。让我们用
Prettify
改进一下:看起来很棒!现在让我们把这一切放在一起:
测试:
现在我们需要在
Query.where
中调用这个类型:链接到Playground