typescript - TypeScript 按属性分组,具有准确的键值关联
问题描述
我想要一个按功能分组,其中组类型被精确建模。例如,在下面很明显tag.value.format()
应该键入 check 因为我们正在release
小组中工作。
const tags: ParsedTag[] = [
{ type: 'release', value: Semver.parse('1.2.3')! },
{ type: 'unknown', value: 'foobar' },
]
const tagGroups = groupByProp(tags, 'type')
// Goal: .format type checks
console.log(tagGroups.release.map(tag => tag.value.format()))
我尝试构建这样的功能可以在这个 TS Playground 实例中找到。
解决方案
我找到了解决方案。完整的代码是:
type IndexableKeyTypes = string | number | symbol
type Indexable<T = unknown> = Record<string | number, T>
type JustIndexableTypes<T> = T extends IndexableKeyTypes ? T : never
type KeysMatching<Rec, Keys> = NonNullable<
{
[RecKey in keyof Rec]: Rec[RecKey] extends Keys ? RecKey : never
}[keyof Rec]
>
type GroupBy<T extends Indexable, K extends IndexableKeys<T>> = {
[KV in JustIndexableTypes<T[K]>]: Array<T extends Record<K, KV> ? T : never>
}
type IndexableKeys<Rec> = KeysMatching<Rec, IndexableKeyTypes>
export function groupByProp<Obj extends Indexable, KeyName extends IndexableKeys<Obj>>(
xs: Obj[],
keyName: KeyName
): GroupBy<Obj, KeyName> {
type KeyValue = JustIndexableTypes<Obj[KeyName]>
const seed = {} as GroupBy<Obj, KeyName>
return xs.reduce((groupings, x) => {
const groupName = x[keyName] as KeyValue
if (groupings[groupName] === undefined) {
groupings[groupName] = []
}
groupings[groupName].push(
x as Obj extends Record<KeyName, KeyValue> ? Obj : never
)
return groupings
}, seed)
}
//
// TEST
//
import * as Semver from 'semver'
type ParsedTag =
| { type: 'unknown'; value: string }
| { type: 'release'; value: Semver.SemVer }
const tags: ParsedTag[] = [
{ type: 'release', value: Semver.parse('1.2.3')! },
{ type: 'unknown', value: 'foobar' },
]
const tagGroups = groupByProp(tags, 'type')
// Goal: .format type checks
console.log(tagGroups.release.map(tag => tag.value.format()))
可以在此处找到 TS Playground 实例的链接。
起初我遇到困难的部分(导致原始问题)是:
type GroupBy<T extends Indexable, K extends IndexableKeys<T>> = {
[KV in JustIndexableTypes<T[K]>]: Array<T extends Record<K, KV> ? T : never>
}
我意识到通过迭代键值类型,我可以在T
.
该解决方案依赖于它们是工会中的歧视性财产,这在我看来是合理和直观的。
推荐阅读
- dask - 即时重新配置 Dask 作业队列
- python - 跨不同时间序列的异常检测技术?
- php - 如何在 firebase-php 中获取失败的令牌?
- java - JavaFX - 如何使用 Java 代码更改选定 TableColumn 的颜色?
- java - 如何在 Java 中设置 SQL Server 数据库连接超时和查询超时
- azure - 使用 azure 应用程序网关 V2 来自网站的多个登录提示
- javascript - 调用函数时得到未定义的结果
- ios - Firebase动态链接未打开应用程序iOS 14
- javascript - 通过 d3.js 创建的世界地图中的工具提示
- r - group_split 的输出需要保存为单独的数据框