typescript - TS4.1:有没有办法定义这种不太深的属性路径类型?
问题描述
尝试使用即将推出的 TypeScript 4.1 的模板文字类型,我尝试定义一个可以检查属性路径的泛型类型。
在 TS 4.1 之前,无法键入诸如 之类的表达式'foo.bar.baz'
,因此您必须满足于string
. 现在,使用模板文字类型,我希望能够键入这些属性路径,并将它们用于诸如 MongoDB 查询和投影对象之类的事情。例如:
db.someCollection.find({ 'foo.bar.baz': { $exists: true } });
这是我想出的类型:
type PropsPath<T> =
T extends object
? T extends any[]
? number
: {
[P in keyof T]: P | `${P}.${PropsPath<T[P]>}`
}[keyof T]
: '';
遗憾的是,TS 编译器认为这种类型“过深或可能无限”。有没有办法以不引发错误的方式重新定义它?
解决方案
使用 TS 4.0,您可以使用Variadic Tuple Types来获得类型的确切元素Array
类型。将它与Recursive Type Aliases结合起来,您可以实现您想要的。看看 TS 游乐场
进一步说明:
ExtractPropsPath<T>
T
: 这个别名只保留它的任何成员string[]
。例如:['arr'] | ['arr', ...any[]]
,这个别名只会保留['arr']
Join
[...Elements][]
:用分隔符加入 anD
。在这种情况下,分隔符是一个点.
PathOf
: 解决方案的关键就在这里。PathOf
返回一个联合类型,它将:[key]
如果T[key]
是原语则返回- 返回
[key] | [key, ...nested-if]
ifT[key]
是一个对象(注意...
,我们将返回数组类型) - “nested-if”是我们检查是否
T[key]
是一个有 1 个成员的元组(例如:),如果成员类型是原始的,[number]
则返回['0']
,或者我们返回递归PathOf<member>
(将此点标记为 {1})T[key]
是具有多个成员的元组或数组类型(例如:[number, string]
或number[]
)然后- 检查元组是否是联合(例如:
[number, string]
->number | string
)然后只返回递归PathOf
- 如果不是联合,那么它是一个数组类型,我们可以使用与 {1} 相同的逻辑
- 检查元组是否是联合(例如:
SerializedPathOf
: 基本上将PathOf
它的并集转换为带有分隔符string[]
的联合并集(例如:-> )string
.
['obj'] | ['obj', 'num']
'obj' | 'obj.num'
推荐阅读
- java - BCrypt rawPassword 不能为空 Spring
- terraform - ElasticSearch:使用 terraform 配置安全组
- javascript - 未定义的范围值
- javascript - 如何定位 svg 元素?
- php - 如何在html中使用include
- react-native - 无法使用自定义谷歌字体反应原生博览会
- ruby-on-rails - Ruby on Rails - 有时该列存在,有时不存在。我转储数据库时是否与此 Postgres 错误有关
- reactjs - 正确部署和更新 React 应用到 Github Pages
- jquery - Jquery 检查下拉选择的值是否包含特定字符
- javascript - 使用 jQuery 在 SVG 中嵌入 SVG