0

我有这种类型:

type FetcherEvents = {
    signInWithEmailAndPassword: [email: string, password: string];
    signUpWithEmailAndPassword: [email: string, password: string, ...data: any[]];
    signWithEmail: [email: string, code: any];
}

我想将每个属性转换为一个对象并创建一个有区别的联合。

所以它变成了这样:

type Resolved =
  | {
      type: "signInWithEmailAndPassword";
      value: [email: string, password: string];
    }
  | {
      type: "signUpWithEmailAndPassword";
      value: [email: string, password: string, ...data: any[]];
    }
  | {
      type: "signWithEmail";
      value: [email: string, code: any];
    };

你能帮助我吗。

4

1 回答 1

0

我找到了解决方案:

首先创建一个 TuplifyUnion

将“某种类型”的联合转换为数组(或元组)

type _UnionToIntersection<U> = (
  U extends unknown ? (k: U) => void : never
) extends (k: infer I) => void
  ? I
  : never;

type _LastOf<T> = _UnionToIntersection<
  T extends unknown ? () => T : never
> extends () => infer R
  ? R
  : never;

type _Push<T extends unknown[], V> = [...T, V];

type _TuplifyUnionBoolean<T> = [T] extends [never]
  ? true
  : false;

// TS4.1+
export type TuplifyUnion<T> =
  true extends _TuplifyUnionBoolean<T>
    ? []
    : _Push<
        TuplifyUnion<Exclude<T, _LastOf<T>>>,
        _LastOf<T>
      >;

// #endregion

不要问我 TuplifyUnion 是怎么做的,我是从另一个stackoverflow复制过来的。

第二步为数组和对象创建...Rest函数。

像这样 :

type RestArrayOf<T extends any[]> = T extends [any, ...infer U] ? U : never;

type RestObjectOf<T> = RestArrayOf<
  TuplifyUnion<keyof T>
>[number] extends keyof T
  ? { [key in RestArrayOf<TuplifyUnion<keyof T>>[number]]: T[key] }
  : never;

最后一步...

你的美丽类型为unionyseeventyse(对于 xstate)你的界面:

type Eventyse<T> = TuplifyUnion<keyof T>[0] extends keyof T
  ? TuplifyUnion<keyof T>[1] extends keyof T
    ?
        | {
            type: TuplifyUnion<keyof T>[0];
            value: T[TuplifyUnion<keyof T>[0]];
          }
        | Eventyse<RestObjectOf<T>>
    : {
        type: TuplifyUnion<keyof T>[0];
        value: T[TuplifyUnion<keyof T>[0]];
      }
  : never;

所以...

已解决的类型:

type Resolved= Eventyse<FetcherEvents>;

输出:


  | {
      type: "signInWithEmailAndPassword";
      value: [email: string, password: string];
    }
  | {
      type: "signUpWithEmailAndPassword";
      value: [email: string, password: string, ...data: any[]];
    }
  | {
      type: "signWithEmail";
      value: [email: string, code: any];
    };

谢谢。TypeScript 是最好的...

于 2021-05-26T12:30:14.950 回答