简体   繁体   中英

Typescript union of generic parameters in array

I have an interface with three generic parameters that looks something like this

interface X<A,O,I> {
...
}

I want to create a function that accepts an array of these interfaces as a rest argument such that the types of O and I are the same, but the type of A can vary. Additionally, I want the return type to be a union of all the types of A.

let item1: X<Type1,string,string> = value1;
let item2: X<Type2,string,string> = value2;

// I want the return type for this to be 'Type1 | Type2'
myFunction(item1, item2) 

I've been thinking about this for a while and can't come up with anything good. Wondering if anyone else has a better thought on how to accomplish this.

EDIT: Based on wantok's answer, I ended up with this

type ExtractFirst<T> = T extends X<infer A, unknown, unknown>[] ? A : never;

export function myFunction<T extends Array<X<any, unknown, I>>, I>(input: I, ...types: T): ExtractFirst<T> {
  ...
}

I don't know whether I understood you properly, or I'm dumb but it's really simple from my point of view:D

const myFunction (item1: Item1Interface, item2: Item2Interface): Type1 | Type2 => {}

Or if you want to "dynamically" read the type from your function parameter I hope you can do something like this:

const myFunction (item1: Item1Interface, item2: Item2Interface): typeof item1 => {}
interface X<A, O, I> {
    getA(): A;
}
// The other generic types of X don't have to be unknown, but they
// need to be something.

function myFunction<T>(...items: Array<X<T, unknown, unknown>>): T {
    return items[0].getA();
}
const item1: X<string, string, string> = { ... };
const item2: X<number, string, string> = { ... };

const v = myFunction(item1, item2); // This doesn't compile.
// Argument of type 'X<number, string, string>' is not assignable to
// parameter of type 'X<string, unknown, unknown>'.
//  Type 'number' is not assignable to type 'string'.

const v = myFunction<string | number>(item1, item2); // This does compile.

If the types of A on the different items are not the same, you need to tell the function which types you're passing. In practice, this shouldn't be a big deal, since you will either be constructing your items manually and thus, you should know the union you'll need to pass, or you got the list of items from somewhere else in which case you must already have a type that they all conform to.

You can also use a conditional type to extract the union type if you have an array of items.

type ExtractFirst<T> = T extends X<infer A, unknown, unknown>[] ? A : never;
const args = [item1, item2];

// equivalent to myFunction<string | number>(..args);
const v = myFunction<ExtractFirst<typeof args>>(...args);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM