打字稿如何定义对象,其中键的值取决于另一个键

Posted

技术标签:

【中文标题】打字稿如何定义对象,其中键的值取决于另一个键【英文标题】:Typescript how to define object in which key's value depends on another key 【发布时间】:2021-01-30 15:46:14 【问题描述】:

我是 typescript 的新手,一直在定义 JSON 对象的类型。在以下示例中,我想为myJSONObject 定义类型。我定义的所需类型是JSONType_1JSONType_2

type RequireOnlyOne<T, Keys extends keyof T = keyof T> =
    Pick<T, Exclude<keyof T, Keys>>
    & 
      [K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, undefined>>
    [Keys];

interface NetworkIdOptions 
  group?: string;
  individual?: string;


type NetworkId = RequireOnlyOne<NetworkIdOptions, 'group' | 'individual'>;

export interface JSONType_1 
  networkId: NetworkId;
  tasks: Array<
  | taskInterface_1
  | taskInterface_2
  | taskInterface_3
  >;

export interface JSONType_2 
  networkId: 
    group: 'myFavGroup';
  ;
  tasks: Array<
  | taskInterface_4
  | taskInterface_5
  >;

根据这个networkId 可以有group 密钥或individual 密钥。 当networkIdgroup 键并且谁的值是=myFavGroup 时,我希望这个对象是JSONType_2 的类型。 请注意,当组名称为 myFavGroup 时,tasks 会发生变化。 上面定义的JSONType_1 & JSONType_2的用例:

myFunc(myJSONObject: JSONType_1 | JSONType_2) 
  if (myJSONObject.networkId.group && myJSONObject.networkId.group === 'myFavGroup') 
    differentFunction(myJSONObject) // this function takes input only in `JSONType_2`.
  

在这个if 条件中,我希望myJSONObject 具有JSONType_2 而不是JSONType_1 | JSONType_2 类型。 因为我只想将JSONType_2 发送到不同的功能。 我得到的错误:

Argument of type 'JSONType_1 | JSONType_2' is not assignable to parameter of type 'JSONType_2'.
...
Types of property 'group' are incompatible.
Type 'string' is not assignable to type '"myFavGroup"'.

myJSONObject 来自另一个结构固定的服务。 2个例子:


  networkId: 
    group: 'Desktop_group';
  ;
  tasks: [
     cmd: 'playMusic', songName: 'xyz' ,
     cmd: 'playVideo', videoName: 'abc' ,
  ];


  networkId: 
    group: 'myFavGroup';
  ;
  tasks: [
     cmd: 'sendMusicList', path: '/home/user/musicFolder' ,
     cmd: 'sendFilesStats', path: '/home/user/someFolder' ,
  ];

请注意,所有任务 JSON 对象也是预定义和固定的。唯一的区别是myFavGroup 的任务不同于任何其他组。

如果有比我正在做的更好的编码方式,我也会感谢您的帮助。提前致谢。

【问题讨论】:

你如何声明 myJSONObject 或结构是什么?可以举个例子吗? 通过添加我收到的 myJSONObject 示例来编辑问题。 @MBB 【参考方案1】:

您的代码看起来有点脏,我会考虑进行一些重构,但是!

// if group = 'myFavGroup' only for JSONType_2 you can exclude it for JSONType_1
interface NetworkIdOptions 
  group?: Exclude<'myFavGroup', string>; // <---
  individual?: string;

要使类型兼容,您需要将group 属性设为JSONType_2 的可选属性

export interface JSONType_2 
  networkId: 
    group?: 'myFavGroup'; // <---
  ;

这样,在检查 networkId.group 等于 'myFavGroup' 之后,您的 Typescript 编译器会自动理解您的参数是 JSONType_2 类型,并且您可以成功地将其传递给 differentFunction

另一种解决方案就是使用类型断言:

differentFunction(myJSONObject as JSONType_2)

【讨论】:

谢谢 Dmitry,对不起这个脏代码,我还在学习打字稿。你想建议我怎样才能让它更干净吗?第一个解决方案也不起作用,它在Types of property 'tasks' are incompatible. 上引发错误,因为我们可以看到myFavGroup 的任务不同。但第二个解决方案奏效了。

以上是关于打字稿如何定义对象,其中键的值取决于另一个键的主要内容,如果未能解决你的问题,请参考以下文章

具有定义值的打字稿动态对象键

如何将对象数组转换为在打字稿中具有动态键的单个对象

带有任意键的对象的打字稿接口? [复制]

打字稿中具有通用键的对象

具有未知键的对象的打字稿类型,但只有数值?

打字稿中具有联合类型键的松散类型对象