问题
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