typescript - 使用并发承诺填充记录
问题描述
示例代码:
type I = 'a' | 'b' | 'c';
const is: Record<I, null> = { 'a': null, 'b': null, 'c': null}
// replace with any async processing function of your choice
function asyncRandomize(): Promise<number> {
return new Promise(resolve => setTimeout(() => resolve(Math.random()), 1000))
}
const irandomized: Promise<[I, number][]> = Promise.all(
Object.keys(is).map((i: I) =>
asyncRandomize()
.then((v): [I, number] => [i, v])
)
)
有没有办法让irandomized
有类型Promise<Record<I, number>>
而不是Promise<[I, number][]>
不经过any
?
解决方案
我认为您将需要一个Object.fromEntries()
像那:Record<string, number>
Record<I, number>
const irandomized = Promise.all(
(Object.keys(is) as I[]).map((i: I) =>
asyncRandomize()
.then((v): [I, number] => [i, v])
)
).then(z => Object.fromEntries(z)) as Promise<Record<I, number>>;
你没有any
在那里使用。
如果您不想在代码中使用类型断言,则可以创建自己的函数,就像Object.fromEntries()
其类型更具体一点(尽管类型断言等需要在该函数的实现中发生)。这是一个可能对您有用的功能:
type Entry = readonly [PropertyKey, any];
type ExtractSupertype<T, U> = T extends any ? [U] extends [T] ? T : never : never;
function fromEntries<E extends readonly Entry[]>(entries: E): {
[K in E[number][0]]: ExtractSupertype<E[number], readonly [K, any]>[1] // TS 4.0-
// [K in E[number] as K[0]]: K[1] // TS 4.1+, easier syntax
} {
const ret: any = {};
for (let entry of entries) {
ret[entry[0]] = entry[1];
}
return ret;
}
请注意,当 TypeScript 4.1 发布并引入映射类型as
子句ExtractSupertype
时,将不再需要该公式。
你可以把它藏在图书馆的某个地方。这个想法是fromEntries()
应该能够将强类型数组或条目元组转换为强类型对象:
const foo = fromEntries([
["x", Math.random()], ["y", new Date()], ["z", Math.random() < 0.5]
] as const);
/* const foo: {
x: number;
y: Date;
z: boolean;
} */
您可以看到Record<string, number | Date | boolean>
,您实际上获得了与特定类型关联的特定属性,而不是仅仅获取 。
有了这个,你可以在没有更多不安全类型断言的情况下做这样的事情:
const iKeys = ["a", "b", "c"] as const;
const irandomized = Promise.all(
iKeys.map((k) =>
asyncRandomize()
.then(v => [k, v] as const)
)
).then(fromEntries);
请注意,我is
只更改为它的键数组。无论如何,您并没有对其值做任何事情,并且编译器将Object.keys(is)
其视为string[]
而不是I[]
(并且有充分的理由,请参阅this question),因此我选择删除中间人并改用强类型的键元组。
无论如何,您可以验证这irandomized
是您期望的类型:
/* const irandomized: Promise<{
a: number;
b: number;
c: number;
}> */
并且它在运行时按预期工作:
irandomized.then(e => console.log(JSON.stringify(e)));
// {"a":0.9961594084980729,"b":0.015675814053288217,"c":0.1783156372032898}
推荐阅读
- c++ - 如何将串行输入存储在char数组arduino中?
- php - 关于在变量中使用 ++$ 而不是回显它的问题
- capl - 如何使用 XCP 协议和 CAPL 在 ECU 中一次更改多个 XCP 信号?
- html - 我的 YouTube 嵌入无法在我的网站上运行
- wordpress - 无法调整 Divi 页脚 wordpress 上的图标字体大小
- api - 如何使用 REST API 在共享点中创建网页?
- jquery - 每当我尝试将浏览器窗口宽度调整为大于 600 像素时,导航栏右侧的菜单就会隐藏
- winforms - Winforms VLC Player 流媒体图像失真
- forms - Embed Form 和 EntityType 在 Embed Form 中选择关联实体
- c++ - 为什么 pow() 函数没有给出正确的结果来打印两个间隔之间的 armstrong 数,但 num*num*num 在 C++ 中给出?