代码之家  ›  专栏  ›  技术社区  ›  Jesse Carter

创建多个泛型类型的交集类型

  •  3
  • Jesse Carter  · 技术社区  · 6 年前

    我已经读了很多关于变量类型和typescript中一些新的tuple内容的文章,但是考虑到目前的语言能力,我很难确定我要完成的工作是否完全不可能。

    当前API的确切问题可以在这里看到:

    export type Themed<T> = { theme: T };
    
    export type ThemedStyleAugmentationFn<P, T> = (
      allProps: Partial<P> & Themed<T>
    ) => string;
    
    export function augmentComponent<
      P,
      TA extends T,
      C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
      T extends object,
      O extends object = {},
      A extends keyof any = never
    >(
      styledComponent: StyledComponent<C, T, O, A>,
      styleAugmentation: ThemedStyleAugmentationFn<P, TA>
    ): StyledComponent<C, T, O & Partial<P>, A> {
      const augmented = styled(styledComponent)`
        ${styleAugmentation}
      `;
    
      return augmented as StyledComponent<C, T, O & Partial<P>, A>;
    }
    
    export function multiAugment<
      P1 extends {},
      TA1 extends T,
      P2 extends {},
      TA2 extends T,
      C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
      T extends object,
      O extends object = {},
      A extends keyof any = never
    >(
      styledComponent: StyledComponent<C, T, O, A>,
      styleAugmentations: [ThemedStyleAugmentationFn<P1, TA1>, ThemedStyleAugmentationFn<P2, TA2>]
    ): StyledComponent<C, T, O & Partial<P1 & P2>, A> {
      const augmented = styled(styledComponent)`
        ${styleAugmentations}
      `;
    
      return augmented as StyledComponent<C, T, O & Partial<P1 & P2>, A>;
    }
    

    augmentComponent 签名的重要部分如下: O & Partial<P> .

    multiAugment 它显式取两个元组 ThemeStyleAugmentationFun 它在这里: O & Partial<P1 & P2>

    我希望能够编写一个multiorgant的版本,它可以获取一个任意的扩充列表fn,并将它们结合在一起,这样它就可以支持任何arity。可能返回版本的 O & Partial<P1 & P2 & P3 ... & P100> 例如。

    我希望尽可能避免需要大量的函数重载来支持这一点,因为我可以继续编写长度增加的元组版本。

    1 回复  |  直到 6 年前
        1
  •  4
  •   jcalz    6 年前

    我不能确定,因为我没有安装您正在使用的库,但也许您可以这样做:

    type PfromSA<SA extends Array<ThemedStyleAugmentationFn<any, any>>>
      = { [K in keyof SA]: SA[K] extends ThemedStyleAugmentationFn<infer P, any> ? (x: P) => void : never } extends
      { [k: number]: (x: infer P) => void } ? P : never;
    
    type SAExtendsTProperly<SA extends Array<ThemedStyleAugmentationFn<any, any>>, T>
      = { [K in keyof SA]: SA[K] extends ThemedStyleAugmentationFn<any, infer U> ? [U] extends [T] ? SA[K] : ThemedStyleAugmentationFn<any, T> : never }
    
    export function multiAugment<
      SA extends Array<ThemedStyleAugmentationFn<any, any>>,
      C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
      T extends object,
      O extends object = {},
      A extends keyof any = never
    >(
      styledComponent: StyledComponent<C, T, O, A>,
      ...styleAugmentations: SA & SAExtendsTProperly<SA, T>
    ): StyledComponent<C, T, O & Partial<PfromSA<SA>>, A> {
      const augmented = styled(styledComponent)`
        ${styleAugmentations}
      `;
    
      return augmented as StyledComponent<C, T, O & Partial<PfromSA<SA>>, A>;
    }
    

    你可以用一个 generic rest parameter 为了你 styleAugmentations 参数(在上面的示例中,我将其设置为rest参数而不是tuple;typescript不会从数组文本推断tuple类型,但它将从rest参数推断tuple类型。如果需要数组文字,则需要断言或以其他方式哄骗编译器将其解释为元组)。

    此类型参数 SA 是一个数组 ThemedStyleAugmentationFn<any, any> . 然后是类型函数 PfromSA<SA> 使用 type inference in conditional types 计算你想要的交叉点 P 类型从 沙特阿拉伯 . 以及类型函数 SAExtendsTProperly<SA> 做一些类似的事情以确保每个元素 ThemedStyleAugmentationFn<P, TA> TA 适当延长 T (因为 主题样式元素fn<p,ta> 可能在 助教 你不能确定 SA extends ThemedStyleAugmentationFn<any, T> 你必须穿过这三元组,抓住 助教 对于每个元素)。

    这个 应该 你想怎么做就怎么做,但同样,如果没有更完备的代码,我也不能确定。

    希望对你有帮助。祝你好运。