Borislav Hadzhiev
Wed Mar 09 2022·3 min read
Photo by Andriyko Podilnyk
The "Spread types may only be created from object types" error occurs when we try to use the spread operator with a value that is possibly not an object. To solve the error, use a conditional to make sure the value is an object before using the spread operator.
Here are 2 examples of how the error occurs.
type Person = { name: string } | undefined; const val1: Person = undefined; // ⛔️ Error: Spread types may only be // created from object types.ts(2698) console.log({ ...val1 }); const val2 = false; // ⛔️ Error: Spread types may only be // created from object types.ts(2698) console.log({ ...(val2 && { name: 'James' }) });
In the first example, the val1
variable can either store an object or an
undefined
value.
Trying to use the
spread syntax
with an undefined
value causes the error.
false
, so we try to use the spread syntax with a boolean
value and get the error.The spread syntax (...) can only be used with object types.
To solve the error, we have to make sure the value we are using the spread syntax with is an object.
If you are absolutely positive the value is an object and TypeScript is getting confused, use a type assertion.
const obj1 = Math.random() > 0.5 ? { name: 'James' } : true; const result = { ...(obj1 as Record<string, unknown>) };
Type assertions are used when we have information about the type of a value that TypeScript can't know about.
We effectively tell TypeScript that obj1
will be an object and not to worry
about it.
Another approach to solve the error is to use a type guard.
type Person = { name: string } | undefined; const val1: Person = Math.random() > 0.5 ? undefined : { name: 'James' }; const result = { ...(typeof val1 === 'object' ? val1 : {}) }; console.log(result.name?.toUpperCase());
The val1
variable can either have a value of undefined
or be an object.
We used a ternary operator with the spread syntax to provide an empty object as
a fallback incase the val1
variable does not store an object.
undefined
value.If you don't like this approach, try using the Object.assign()
method, which
is more forgiving.
const result = Object.assign({}, false, true, undefined, null, 0, { name: 'James', }) as { name: string }; console.log(result.name); // 👉️ "James"
The parameters we passed to the Object.assign method are:
However, we are able to pass pretty much any value to the Object.assign
method
without TypeScript yelling at us.
Notice that we used a type assertion to type the result
variable. Had we not
done this, it would have been typed as any
.