将接口转换为打字稿中的元组

时间:2018-10-30 05:50:04

标签: typescript

我想将接口转换为键和值的元组。我想知道使用泛型是否有可能,但是对语言功能了解得不够多。

这是我想做的事情:

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'
    )
}

这可能吗?

1 个答案:

答案 0 :(得分:3)

我不确定为什么要这么做,但是这里...

使用this answer中的想法,将映射的类型转换为函数的交集,然后我们可以针对不同的类型参数进行匹配,我们可以以适用于固定最大数量的方式定义ToTuple原始界面的成员。

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]

另一种方法是在keyof接口上使用UnionToIntersection,但是我认为通过联合可能会冒更大的风险来失去接口成员的顺序。 (我相信我曾经见过工会失去秩序,尽管我现在无法在操场上的测试中重现它。)在上面的解决方案中,确定交叉点是有序的,所以我们仅依靠映射的类型以保留顺序,并在IntersectionOfValues中进行推理过程以按顺序生成反变候选并按顺序相交。这仍然是依赖于实现的行为,但是我认为这不太可能改变。