【问题标题】:Is it possible to change an key value interface into a tuple是否可以将键值接口更改为元组
【发布时间】:2021-02-11 01:33:28
【问题描述】:

我需要在这两种类型中提供相同的数据

type DataMap = { 
  id001: 'name1', 
  id002: 'name2', 
  id003: 'name3', 
  ....
} 

type DataTuple = [
  {id: 'id001', name: 'name1'},
  {id: 'id002', name: 'name2'},
  {id: 'id003', name: 'name3'}, 
  ...
]

我只想声明这种类型一次并且有一个单一的事实来源, 但我无法弄清楚将类型从对象转换为元组的实用程序类型函数。

理想情况下,我想做这样的事情:

type DataMap = { 
  id001: 'name1', 
  id002: 'name2', 
  id003: 'name3', 
  ....
}; 
type DataTuple = MapToTuple<DataMap>;

// or 

type DataTuple = [
  {id: 'id001', name: 'name1'},
  {id: 'id002', name: 'name2'},
  {id: 'id003', name: 'name3'}, 
  ...
];
type DataMap = TupleToMap<DataTuple>;

MapToTuple&lt;T&gt;TupleToMap&lt;T&gt; 是否可以使用这些功能?

【问题讨论】:

    标签: typescript typescript4.0 typescript3.8


    【解决方案1】:

    对于 TypeScript 4.1+,您可以像这样实现 TupleToMap,假设您知道 id 属性应该是键,name 属性应该是值:

    type TupleToMap<T extends { id: PropertyKey, name: any }[]> = {
        [V in T[number]as V['id']]: V['name']
    };
    
    type DataMap = TupleToMap<DataTuple>;
    /* type DataMap = {
    id001: "name1";
    id002: "name2";
    id003: "name3";
    } */
    

    上面使用了key remapping,它是在 TS 4.1 中引入的。对于早期版本,您可以改为这样编写:

    type TupleToMap<T extends { id: PropertyKey, name: any }[]> = {
        [K in T[number]['id']]: Extract<T[number], { id: K }>['name']
    };
    

    对于MapToTuple,不清楚您打算从哪里获得元组的排序。对于人类来说,id001 的条目应该在 id002 的条目之前是显而易见的,但是对于编译器,我不确定是否值得尝试理解这一点。如果我想出一些不疯狂的东西,我会回来。

    Playground link to code

    【讨论】:

    • 你在 20 分钟内让我的尝试蒙羞,我花了一天的时间。谢谢!对于订单.. js 对象中的订单现在得到保证,因此对象中的数组将是确定性的。接口/类型不是这种情况吗?
    • 不,TypeScript 中对象类型的键没有一致的可观察顺序。请参阅this question,了解一种显示它有多糟糕的方法。
    • 就像,您可以使用this,但不能保证编译器会按照您看到的顺序看到键。如果您可以处理无序数组(例如此处链接的代码中的DataArray),那将是编译器能力范围内的事情。否则,?‍♂️
    【解决方案2】:

    我有一个TupleToMap&lt;T&gt; 的解决方案,虽然它很长

    
    type DataTuple = [
      { id: 'id001'; name: 'name1' },
      { id: 'id002'; name: 'name2' },
      { id: 'id003'; name: 'name3' }
    ];
    
    type TupleKeys<T> = Exclude<keyof T, keyof any[]>;
     
    type TupleToObject<T extends Record<string, any>> = {
      [k in TupleKeys<T>]: { [P in T[k]['id']]: T[k]['name'] };
    }[TupleKeys<T>];
    
    type MergeUnions<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any
      ? { [K in keyof R]: R[K] }
      : never;
    
    type TupleToMap<T> = MergeUnions<TupleToObject<T>>;
    type DataMap = TupleToMap<DataTuple>
    

    ts playground link

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-15
      • 2017-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多