How to build up a target object from generic partials in TypeScript?

旧城冷巷雨未停 提交于 2019-12-24 00:37:39

问题


I am using typescript@2.3.4.

I have a target object:

interface MyTarget {
    a: string;
    b: string;
    c: string;
    d: string;
}

I want to create multiple converts of partial objects using generics.

One such convert might look like this:

const convert = <T extends object>(t: T): MyTarget => {
    return {
        c: "c",
        d: "d",
        ...t,
    };
};

Yet this yields into:

error TS2698: Spread types may only be created from object types.

even though I guard the generic T to be an object.

I then remember that there is a Partial type, hence I tried this:

const convert = (partial: Partial<MyTarget>): MyTarget => {
    return {
        c: "c",
        d: "d",
        ...partial,
    };
};

Yet the Partial makes all properties optional. I don't want that and it would now throw:

src/Partial.ts(14,5): error TS2322: Type '{ a?: string; b?: string; c: string; d: string; }' is not assignable to type 'MyTarget'.
  Property 'a' is optional in type '{ a?: string; b?: string; c: string; d: string; }' but required in type 'MyTarget'.

I want to create an instance of MyTarget with every field set as an requirement. I do want to keep typesafety, which is why I don't want to this even though it works:

const convert = (partial: Partial<MyTarget>): MyTarget => {
    return {
        c: "c",
        d: "d",
        ...partial,
    } as MyTarget; // loses type checks, really don't want to
};

回答1:


I think you are using an older version of TS (in newer version spread expressions are typed correctly).

Regardless of this, the true issue is that the object literal might not be a full MyTarget. Your code would allow this call

convert({a : "" })// return value is not really MyTarget since it will not contain b

What you really want is the parameter to be MyTarget except c and d:

interface MyTarget {
    a: string;
    b: string;
    c: string;
    d: string;
}
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
const convert = (t: Omit<MyTarget, 'c' | 'd'>) : MyTarget => {
    return {
        c: "c",
        d: "d",
        ...t,
    };
};



回答2:


I went with Qwertiy's solution:

interface XYZ {
  x: number;
  y: number;
  z: number;
}

declare var { z, ...xy }: XYZ;

type XY = typeof xy; // { x: number; y: number;}

which works perfectly for tsc@2.3.



来源:https://stackoverflow.com/questions/54533141/how-to-build-up-a-target-object-from-generic-partials-in-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!