typescript - 我可以在 TypeScript 中创建一个对每个键值对都是类型安全的键值字典吗?

标签 typescript dictionary types

这个问题有点牵涉,可能最好通过探索一个基本的状态系统来解决,所以和我一起在这里走一分钟。假设我有这个状态类:

class AccountState {
  public id: string;
  public displayName: string;
  public score: number;
}
来自 jcalz's work here ,我知道我可以构建一个以类型安全的方式引用任何 AccountState 属性的函数——我可以获取属性名称和值,并使用泛型对该值施加属性自己的类型限制,这非常令人印象深刻:
class Store {
  state = new AccountState();

  mutate<K extends keyof AccountState>(property: K, value: AccountState[K]): void {
    this.state[property] = value;
  }
}

const store = new Store();
store.mutate('displayName', 'Joseph Joestar'); // ok
store.mutate('displayName', 5); // not ok: surfaces the below typescript error
// ts(2345) Argument of type 'number' is not assignable to parameter of type 'string'.
使用 ValueOf<T>在 jcalz 的回答中,我还可以建模一个类型安全的键值字典。对我来说,向您展示它是如何工作的以及它的缺点可能是最简单的:
type ValueOf<T> = T[keyof T];

class Store {
  state = new AccountState();

  mutateMany(updates: { [key in keyof AccountState]?: ValueOf<AccountState> }): void {
    Object.keys(updates).forEach(property => {
      const value = updates[property];
      (this.state[property] as any) = value;
    });
  }
}

const store = new Store();
store.mutateMany({ displayName: 'Joseph Joestar', score: 5 }); // ok
store.mutateMany({ displayName: 1000, score: 'oh no' }); // unfortunately, also ok
store.mutateMany({ score: true }); // not ok, surfaces the below error
// ts(2322) Type 'boolean' is not assignable to type 'ValueOf<AccountState>'.
// (if AccountState had a boolean property, this would be allowed)
那一秒mutateMany()是一个问题。如您所见,我可以要求 key 是 AccountState 的某些属性。我还可以要求该值对应于 AccountState 上的某些属性,因此它必须是 string | number .但是,不要求该值与属性的实际类型相对应。
如何使字典完全类型安全,例如{ displayName: 'a', score: 1 }是允许的,但 { displayName: 2, score: 'b' }不是?
我考虑过声明一个 AccountStateProperties 接口(interface),它简单地重复所有这些属性及其值,然后定义 mutateMany(updates: AccountStateProperties) ,但是对于更多涉及的状态对象,这会增加很多代码重复。直到今天我才知道我可以做一些这些事情,我想知道打字系统是否有一些我可以在这里利用的东西来使这个字典在没有这种方法的情况下完全类型安全。

最佳答案

mutateMany方法,[key in keyof AccountState]?: ValueOf<AccountState> ,您是说对于任何 key , 值的类型可以是 AccountState 的任意类型拥有。如果您尝试使用不在 AccountState 中的内容进行更新,您会看到这一点。 (如 true )。
相反,我相信你想要:

mutateMany(updates: { [key in keyof AccountState]?: AccountState[key] })
这表示 key 处的值还应该匹配 AccountState 的类型在 key而不仅仅是 AccountState 的任何类型的值.
[编辑:如果您查看链接的答案,则以“为了确保键/值对在函数中正确“匹配”,您应该使用泛型以及查找类型...”开头的部分描述这个]

关于typescript - 我可以在 TypeScript 中创建一个对每个键值对都是类型安全的键值字典吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66068373/

相关文章:

c++ - 在 C++ 中,您可以使用 bool 和 int 运算符执行哪些操作?

asp.net-mvc-3 - 具有动态数据的 MVC 3 - 将数据类型应用于动态数据

javascript - 为什么 `export default` 导出的是 `default` 的对象而不是对象本身?

typescript - React Native/Typescript - 错误模块 '"react-native "' has no exported member ' Pressable'.ts(2305)

reactjs - 无法将 href 与 IconButtonProps 一起使用

angular - 在移动设备上显示 Accordion 并在其他设备上显示标签

swift - 合并两个字典的通用函数

python - 动态创建字典并自动分配函数评估中的属性

objective-c - 获取给定 UTType 的扩展

java - 遗传算法 - 我需要什么数据结构?