简体   繁体   中英

Convert an interface to a tuple in typescript

I would like to convert an interface into a tuple of keys and values. I was wondering if this would be possible using generics, but don't know enough about the language features to do this.

This is the kind of thing I would like to do:

interface Person {
    name: string,
    age: number
}

type Args = ToTuple<Person> // result would be ['name', string, 'age', number]

function DoSomethingWithArgs(...args: Args) {
    return (
        args[0] === 'name' &&
        typeof args[1] === 'string' &&
        args[2] === 'name' &&
        typeof args[3] === 'number'
    )
}

Is this possible?

I'm unsure why you want this, but here goes...

Using ideas from this answer to convert a mapped type to an intersection of functions that we can then match against different type parameters, we can define ToTuple in a way that will work for a fixed maximum number of members of the original interface.

type IntersectionOfValues<T> =
  {[K in keyof T]: (p: T[K]) => void} extends
    {[n: string]: (p: infer I) => void} ? I : never;

type IntersectionOfFunctionsToType<F, T> =
    F extends {
        (na: infer NA, a: infer A): void;
        (nb: infer NB, b: infer B): void;
        (nc: infer NC, c: infer C): void;
    } ? [NA, A, NB, B, NC, C] :
    F extends {
        (na: infer NA, a: infer A): void;
        (nb: infer NB, b: infer B): void;
    } ? [NA, A, NB, B] :
    F extends {
        (na: infer NA, a: infer A): void
    } ? [NA, A] :
    never;

type ToTuple<T> = IntersectionOfFunctionsToType<
    IntersectionOfValues<{ [K in keyof T]: (k: K, v: T[K]) => void }>, T>;

interface Person {
    name: string,
    age: number
}

type Args = ToTuple<Person> // ['name', string, 'age', number]

An alternative approach would be to use UnionToIntersection on keyof the interface, but I believe that going through a union may carry a greater risk of losing the order of the members of the interface. (I believe I've seen unions lose order in the past, though I couldn't reproduce it in tests in the playground just now.) In the solution above, it's well-established that intersections are ordered, so we are only relying on the mapped types to preserve order and the inference process in IntersectionOfValues to generate the contravariant candidates in order and intersect them in order. This is still implementation-dependent behavior, but I think it's unlikely to change.

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