我找到了解决方案:
首先创建一个 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;
最后一步...
你的美丽类型为unionyse或eventyse(对于 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 是最好的...