react - typescript tutorial
Transformar tipo de unión a tipo de intersección (2)
¿Hay una manera de transformar un tipo de unión en un tipo de intersección:
type FunctionUnion = () => void | (p: string) => void
type FunctionIntersection = () => void & (p: string) => void
Me gustaría aplicar una transformación a
FunctionUnion
para obtener
FunctionIntersection
¿Quieres unión a intersección? Los tipos condicionales distributivos y la inferencia de los tipos condicionales pueden hacer eso. (No creo que sea posible hacer una intersección a la unión, lo siento) Aquí está la magia malvada:
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
Eso distribuye el sindicato
U
y lo vuelve a empaquetar en un nuevo sindicato en el que todos los miembros están en una posición contraria.
Eso permite inferir el tipo como una intersección
I
, como se menciona en el manual:
Del mismo modo, los candidatos múltiples para la misma variable de tipo en posiciones contra-variantes hacen que se infiera un tipo de intersección.
A ver si funciona.
Primero, permítame paréntesis entre
FunctionUnion
y
FunctionIntersection
porque TypeScript parece enlazar la unión / intersección más estrechamente que el retorno de la función:
type FunctionUnion = (() => void) | ((p: string) => void);
type FunctionIntersection = (() => void) & ((p: string) => void);
Pruebas:
type SynthesizedFunctionIntersection = UnionToIntersection<FunctionUnion>
// inspects as
// type SynthesizedFunctionIntersection = (() => void) & ((p: string) => void)
¡Se ve bien!
Tenga cuidado de que, en general,
UnionToIntersection<>
exponga algunos detalles de lo que TypeScript piensa que es una unión real.
Por ejemplo,
boolean
aparentemente se representa internamente como
true | false
true | false
, entonces
type Weird = UnionToIntersection<string | number | boolean>
se convierte en
type Weird = string & number & true & false
Espero que ayude. ¡Buena suerte!
Si está tratando de transformar una matriz en una intersección , mapear la matriz de antemano hará que la unión de la matriz resultante tenga un orden incorrecto .
Esto puede no importar si el orden de intersección resultante no importa, pero si lo hace, la respuesta anterior no funcionará.
A continuación se admiten matrices hasta el índice de
9
, que se pueden ampliar manualmente si necesita una repetición más prolongada.
type Idx<T extends any, K extends keyof any, Yes> = T extends Record<K, any>
? T[K] & Yes
: unknown
type ArrayToIntersection<T extends any[]> = Idx<T, ''0'', Idx<T, ''1'', Idx<T, ''2'', Idx<T, ''3'', Idx<T, ''4'', Idx<T, ''5'', Idx<T, ''6'', Idx<T, ''7'', Idx<T, ''8'', Idx<T, ''9'', unknown>>>>>>>>>>
// Usage: => 1 & 2 & 3 & 4
type Result = ArrayToIntersection<[1, 2, 3, 4]>