See a playground of this question here
I have an interface that requires all props. However, creating the object is a two-step process. Therefore I am planning to create 2 Partial
versions of the object, and then merge them together to satisfy the non-partial interface. Example:
interface IComplete {
a: string,
b: string
}
const part1: Partial<IComplete> = {
a: 'hello'
}
const part2: Partial<IComplete> = {
b: 'world'
}
const together: IComplete = {
...part1,
...part2
}
Even though together
is always complete, the compiler complains:
Type '{ a?: string; b?: string; }' is not assignable to type 'IComplete'. Property 'a' is optional in type '{ a?: string; b?: string; }' but required in type 'IComplete'.
Is there a recommended way to achieve this? It is important for my case that the interface IComplete
is not made partial. I.e. the props a and b are never null or undefined.
Use the spread syntax (...) to merge objects in TypeScript, e.g. const obj3 = { ... obj1, ... obj2 } . The type of the final object will successfully be inferred, so trying to add or remove properties from it will cause the type checker to show an error.
The Partial type in TypeScript is a utility type which does the opposite of Required. It sets all properties in a type to optional.
For the purposes of this article, “declaration merging” means that the compiler merges two separate declarations declared with the same name into a single definition. This merged definition has the features of both of the original declarations.
The easiest way would be to remove the type annotations and let type inference do its work:
interface IComplete {
a: string,
b: string
}
const part1 = {
a: 'hello'
}
const part2 = {
b: 'world'
}
const together: IComplete = {
...part1,
...part2
}
This does have certain deleterious effects, e.g. parameters in function expressions in part1
or part2
won't get inferred types.
Instead you can use Pick
- unfortunately you do have to write out the keys that you're picking from each type when using this approach:
interface IComplete {
a: string,
b: string,
c: number
}
const part1: Pick<IComplete, "a"> = {
a: 'hello'
}
const part2: Pick<IComplete, "b" | "c"> = {
b: 'world',
c: 43
}
const together: IComplete = {
...part1,
...part2
}
Frankly, I do not fully understand why typescript transpiler does not permit that syntax.
But the below codes can bypass it and achieve what you want.
interface IComplete {
a: string,
b: string
}
const part1: Partial<IComplete> = {
a: 'hello'
}
const part2: Partial<IComplete> = {
b: 'world'
}
const together: IComplete = {
...part1,
...part2
} as IComplete
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With