typescript - 将对象列表转换为记录类型
问题描述
我正在尝试编写一个类型安全的函数,它接收一个 shape 对象列表{ key: Key, test: boolean }
并返回一个 shape 对象{ [name: Key]: Type }
。(Key
应该只是extends string
)。Type
应该是number
如果test
给定对象的属性是true
并且string
如果它是false
.
例子:
const r = f([
{ key: 'foo', test: true },
{ key: 'bar', test: false }
]);
// `typeof r` should be `{ 'foo': number, 'bar': string }`
这是我能走多远,我不知道之后该怎么做。
function f<T extends string>(xs: { name: T, key: boolean }[]): ??? {
// ...
}
这样的事情甚至可能吗?
解决方案
这是可以实现的。完整解决方案:
// type represents the input array element
type KeyTest = { key: string, test: boolean };
// type process input array into wanted object
type Result<T extends KeyTest[]
,_Keys extends string = {
[K in keyof T]: T[K] extends KeyTest ? T[K]['key'] : never
}[keyof T & number]> = {
[K in _Keys]: {
[I in keyof T]:
T[I] extends KeyTest ? T[I]['key'] extends K
? true extends T[I]['test'] ? number : string
: never
: never
}[keyof T & number]
}
// type level Result type check
type Test = Result<[
{ key: 'foo', test: true },
{ key: 'bar', test: false }
]>
declare function f<T extends Array<KT>
, KT extends {key: Key, test: Test}
, Key extends string
, Test extends boolean>(...xs: T): Result<T>
// example usage:
const r = f({ key: 'foo', test: true }, { key: 'bar', test: false });
type X = typeof r;
// working with existing arrays
const arr = [
{ key: 'foo', test: true },
{ key: 'bar', test: false }
] as const; // here as const because type will be infered as an array
const r2 = f(...arr);
type X2 = typeof r2;
不幸的是,为了获得适当的类型缩小,我需要将函数输入从单个 Array 参数更改为参数列表。我希望这对你来说不是问题。真正的区别是我们需要...
在传递数组之前使用。这样做是因为默认情况下 TS 将数组类型视为数组而不是元组。
类型说明Result
:
_Keys
- 这些都是key
从元组中收集的所有属性类型[K in _Keys]
- 我们正在遍历从元组收集的所有键[I in keyof T]
- 我们再次遍历原始元组,就像 for inside forT[I]['key'] extends K ? true extends T[I]['test'] ? number : string
- 所以我们在第二个里面,我们检查元组元素是否具有key
我们在地图类型中拥有的确切当前键,如果是,我们检查是否test
为真,如果是,如果number
不是,我们分配给它string
推荐阅读
- symfony - 有没有办法在 Symfony 配置中找到我们的那个〜?
- swift - 领域迁移 - 预期声明错误
- php - access_token过期后如何刷新token
- javascript - 在弹性搜索 node.js 客户端中结合 query_string 和 must
- mysql - mySQL可以在同一个查询中找到不同的东西吗
- oracle - 触发器更新联合视图与触发器表
- sql - SQL 查询从两个不同的表中汇总来自客户的销售额和订单数量
- ios - 在 WKWebView 中打开 Vimeo 视频
- flutter - 如何获取 Flutter 应用的构建和版本号
- dataframe - Pyspark -- java.lang.NullPointerException(使用 jdbc 从 Teradata 读取数据帧时)