如何解决TS4.1:有没有一种方法可以定义此属性路径类型,而该类型不太深?
在即将推出的TypeScript 4.1的template literal types上进行了实验,我试图定义一个可以检查属性路径的通用类型。
直到TS 4.1,尚无法键入if b.startswith('y'):
print('you fell and died')
之类的表达式,因此您必须满足'foo.bar.baz'
的要求。现在,对于模板文字类型,我希望能够键入这些属性路径,并将其用于诸如MongoDB查询和投影对象之类的事情。例如:
string
这是我想出的类型:
db.someCollection.find({ 'foo.bar.baz': { $exists: true } });
可悲的是,TS编译器将此类型视为“过深或无限大”。 有什么方法可以以不引发错误的方式重新定义它?
解决方法
在TS 4.0中,您可以使用Variadic Tuple Types获得与Array
类型完全相同的元素类型。将其与Recursive Type Aliases结合使用,即可实现所需的功能。前往TS游乐场
进一步的解释:
-
ExtractPropsPath<T>
:此别名仅保留T
的任何成员,即string[]
。例如:['arr'] | ['arr',...any[]]
,此别名将仅保留['arr']
-
Join
:将[...Elements][]
与定界符D
连接起来。在这种情况下,定界符是点.
-
PathOf
:解决方案的重点在这里。PathOf
返回的联盟类型将:- 如果
[key]
是原始元素,则返回T[key]
- 如果
[key] | [key,...nested-if]
是一个对象,则返回T[key]
(注意...
,我们将返回数组类型) - “嵌套-如果”是我们检查是否
-
T[key]
是具有1个成员(例如:[number]
)的元组,如果成员类型为基本类型,则返回['0']
,否则我们返回递归{{1 }}(将此点标记为{1}) -
PathOf<member>
是具有多个成员或数组类型(例如:T[key]
或[number,string]
)的元组- 检查元组是否为联合(例如:
number[]
->[number,string]
),然后仅返回递归number | string
- 如果不是联合,则为数组类型,我们可以使用与{1}相同的逻辑
- 检查元组是否为联合(例如:
-
- 如果
-
PathOf
:基本上是将SerializedPathOf
的联合体PathOf
转换为string[]
与分隔符string
的联合联合体(例如:{{1 }}->.
)
基于Amit的答案,它也适用于数组,尽管它不考虑Chau的元组。
type Path<T> = T extends Array<any>
? `${number}` | `${number}.${Path<T[number]>}`
: T extends object
? {
[P in keyof T]: (P & string) | `${P & string}.${Path<T[P]>}`
}[keyof T]
: never
,
要回答我自己的问题,我终于想出了以下类型:
type PropsPath<T extends object> = {
[P in keyof T]: T[P] extends object
? `${string & P}` | `${string & P}.${PropsPath<T[P]>}`
: `${string & P}`
}[T extends any[] ? (number & keyof T) : keyof T];
Updated example in TS Playground
它可以工作,但可悲的是没有涵盖T
具有嵌套属性的情况,该属性是长度未知的数组(any[]
)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。