我正在研究at对象的简单映射器。它应该接受对象属性的数组,并返回这些属性的值的数组。 它工作正常,但是在Typescript的情况下,我无法保存返回值的类型顺序。
这里是例子
import { createStore, Store as FriendsStore } from "./mobx_react_lite_store";
import { createAccountsStore, AccountsStoreType } from "./accountsStoreLite";
type RootObj = {
friendsStore: FriendsStore,
accountsStore: AccountsStoreType
};
const rootStore: RootObj = {
friendsStore: friendsStore,
accountsStore: accountsStore
};
function pickStores<T, K extends keyof T>(rootStore: T, keys: K[]): T[K][] {
return keys.map((key: K) => {
const store = rootStore[key];
if (!store) {
throw new Error(`Can't find the store with name ${key} in rootStore. Myabe yo've forgottent
to add this store to the rootStore.`);
}
return store;
})
}
当我尝试仅在一家商店中称呼它时,它就像一个饰物 对于前
// Works fine. It shows that accountsStore has AccountsStoreType
const [ accountsStore ] = pickStores(rootStore, ["accountsStore"]);
// Works fine. It shows that accountsStore has friendsStore type
const [ friendsStore ] = pickStores(rootStore, ["friendsStore"]);
但是当我试图用2存储调用它时,返回的类型不保持某些顺序。
因此friendsStore
可以是EITHER friendsStore或AccountsStoreType。 accountsStore
const [ friendsStore, accountsStore ] = pickStores(rootStore, ["friendsStore", "accountsStore"]);
是否可以为每个被破坏的财产保存正确的类型? 感谢您的帮助。
更新 lukasgeiter 提供了正确的答案,但是对于Typescript来说,有趣的技巧很少。我已经研究了它们,寻找了一些文档等,这是了解这些功能的有用资源:
希望此信息对某人有帮助。
答案 0 :(得分:1)
要解决此问题,我们必须弄清楚两件事...
要能够处理keys
数组中元素的各个类型,我们需要TypeScript将其视为元组:
当前TypeScript将keys
参数的类型推断为:
("friendsStore" | "accountsStore")[]
但是,我们想要的是这种类型:
["friendsStore", "accountsStore"]
要实现此目的,有几种解决方案:
最简单但也是最冗长的选择是将数组转换为元组:
<["friendsStore", "accountsStore"]>["friendsStore", "accountsStore"]
或者,我们也可以将数组强制转换为const
。这会将其转换为readonly
元组:
<const>["friendsStore", "accountsStore"] // -> readonly ["friendsStore", "accountsStore"]
如果我们将keys
更改为rest参数,TypeScript将推断其类型为元组。继续阅读以查看实际效果。
使用正确键入的元组,我们可以构造一个返回类型,该返回类型将键映射到T
中的类型:
{ [I in keyof K]: T[keyof T & K[I]] }
[I in keyof K]
遍历keys
数组的元素。 I
是索引,而不是元素本身。K[I]
获取元素的类型T[keyof T & K[I]]
在K[I]
上查找属性T
的类型。我必须添加keyof T &
才能满足编译器的要求。如果丢失,它将抱怨K[I]
不是T
的键,即使我们知道情况总是如此。
我已经创建了两个版本的代码,它们应该适用于一个版本。一个使用rest参数,另一个使用const
强制转换。
不幸的是,我不得不在函数内部引入any
强制转换。可能可以将其转换为更具体的内容,但这是我所能找到的最好的结果。
请注意由于rest参数而导致函数调用方式的变化
function pickStores<T, K extends (keyof T)[]>(rootStore: T, ...keys: K): { [I in keyof K]: T[keyof T & K[I]] } {
return keys.map((key: keyof T) => {
// ...
}) as any;
}
const [ friendsStore, accountsStore ] = pickStores(rootStore, "friendsStore", "accountsStore");
function pickStores<T, K extends readonly (keyof T)[]>(rootStore: T, keys: K): { [I in keyof K]: T[keyof T & K[I]] } {
return keys.map((key: keyof T) => {
// ...
}) as any;
}
const [ friendsStore, accountsStore ] = pickStores(rootStore, ["friendsStore", "accountsStore"] as const);