typescript - Y a-t-il un moyen d'obtenir le type d'intersection des paramètres rest génériques ?
J'écris une fonction de fusion qui fusionne plusieurs objets et retourne.
type A = { a: number };
type B = { b: number };
type C = { c: number };
const a: A = { a: 1 };
const b: B = { b: 2 };
const c: C = { c: 3 };
function merge<T extends any[]>(...args: T): { [k in keyof T]: T[k] } {
return args.reduce((previous, current) => {
return Object.assign(previous, current);
});
}
const m = merge(a, b, c);
m.a;
m.b;
m.c;
Ce que j'attends pour le type de m est A & B & C, mais j'ai obtenu [A, B, C] dans le compilateur, et cela me donne une erreur.
Property 'a' does not exist on type '[A, B, C]'.ts(2339)
Y a-t-il une façon correcte de déclarer le type de retour de ma fonction merge ?
Réponse #1
Ce dont vous avez besoin est une intersection des éléments du tableau :
Aire de jeu TS
type ArrayIntersection<T extends readonly unknown[]> = T extends [infer Head, ...infer Rest] ?
Head & ArrayIntersection<Rest>
: unknown;
function merge <T extends readonly any[]>(...args: T): ArrayIntersection<T> {
return args.reduce((previous, current) => {
return Object.assign(previous, current);
});
}
type A = { a: number };
type B = { b: number };
type C = { c: number };
declare const a: A;
declare const b: B;
declare const c: C;
const m = merge(a, b, c); // A & B & C
m.a; // number
m.b; // number
m.c; // number
Notez que les types intersection qui sont incompatibles (ou qui ont des membres dont les types sont incompatibles) entraîneront never pour ce type :
declare const result: ArrayIntersection<[
{ a: string },
{ b: number },
{ person: { first: string } },
{ person: { last: string } },
{ b: string },
]>;
result.person; // { first: string; last: string; }
result.a; // string
result.b; // never
Réponse #2
T[number] produira une union des types dans le tableau args, puis vous pouvez utiliser un type Union to Intersection pour fusionner les membres de cette union en une intersection :
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
function merge<T extends any[]>(...args: T): UnionToIntersection<T[number]> {
return args.reduce((previous, current) => {
return Object.assign(previous, current);
});
}
Terrain de jeu
