【问题标题】:Type map returning the intersection of the type mapped member of a union类型映射返回联合的类型映射成员的交集
【发布时间】:2018-10-29 02:37:23
【问题描述】:

我的类型安全查询生成器中有以下数据类型。

// types
type SUDI = S | U | D | I
type SUD = S | U | D
type S = 'Select'
type U = 'Update'
type D = 'Delete'
type I = 'Insert'

// states
interface STATE_SUDI { state: 'SUDI' }
interface STATE_SUD { state: 'SUD' }
interface STATE_S { state: 'S' }
interface STATE_U { state: 'U' }
interface STATE_D { state: 'D' }
interface STATE_I { state: 'I' }

您可以在类型和状态之间进行转换。

type TypeToState<T> = 
  SUDI extends T ? STATE_SUDI :
  SUD extends T ? STATE_SUD :
  S extends T ? STATE_S :
  U extends T ? STATE_U :
  D extends T ? STATE_D :
  I extends T ? STATE_I : never;

type StateToType<T> = 
  T extends STATE_SUDI ? SUDI :
  T extends STATE_SUD ? SUD :
  T extends STATE_S ? S :
  T extends STATE_U ? U :
  T extends STATE_D ? D :
  T extends STATE_I ? I : never;

状态数组的类型是所有状态类型的并集数组。例如:

declare let array: (STATE_SUDI | STATE_SUD)[]

当数组元素的类型用StateToType映射时,变成:

StateToType<STATE_SUDI | STATE_SUD>
// = StateToType<STATE_SUDI> | StateToType<STATE_SUD>
// = SUDI | SUD
// = (S | U | D | I) | (S | U | D)
// = (S | U | D | I)
// = SUDI

我希望的行为是将StateToType 应用于工会的每个成员,然后得到交集。

BetterStateToType<test>
// = StateToType<STATE_SUDI> & StateToType<STATE_SUD>
// = SUDI & SUD
// = (S | U | D | I) & (S | U | D)
// = (S | U | D)
// = SUD

我需要帮助来定义BetterStateToType

我知道可以将并集转换为交集,但我不知道是否也可以在交集之前应用映射。

Transform union type to intersection type

Intersection of mapped types

【问题讨论】:

    标签: typescript generics


    【解决方案1】:

    是的,这是可能的:

    type BetterStateToType<T> =
      (T extends any ? ((x: [StateToType<T>]) => void) : never) extends
      ((x: [infer I]) => void) ? I : never
    
    type StateToTypeSuSussudio = BetterStateToType<STATE_SUDI | STATE_SUD>;
    // = SUDI & SUD
    // = (S | U | D | I) & (S | U | D)
    // = (S | U | D)
    // = SUD
    // = "Select" | "Update" | "Delete"
    

    它类似于常规的联合到交叉代码:

    type UnionToIntersection<U> = 
      (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
    

    但它使用[StatetoType&lt;T&gt;] 代替U,它变成(在分发联合之后)类似于[SUDI] | [SUD]。单元素元组“框”可防止编译器评估 SUDI | SUD,后者立即折叠为 SUDI,而 [SUDI] | [SUD] 则保持不变,直到发生联合到交集之后。

    我猜你对 never 类似的结果没问题:

    type NotSure = BetterStateToType<STATE_S | STATE_U>
    // = "Select" & "Update", not gonna happen
    

    顺便说一句,如果我不必使用条件类型,我倾向于避免使用它们,所以我更倾向于这样定义StateToType&lt;&gt;

    type StateTypeMap = {
      SUDI: SUDI
      SUD: SUD
      S: S
      U: U
      D: D
      I: I
    }
    type StateToType<T extends { state: keyof StateTypeMap }> =
      StateTypeMap[T['state']];
    

    我想这差不多。


    希望有所帮助;祝你好运!

    【讨论】:

      猜你喜欢
      • 2018-05-07
      • 2019-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-12
      • 1970-01-01
      相关资源
      最近更新 更多