Oh boy, how did I not know about Partial until now? This is something all Typescripters need to know.
I'll use the example based on the official docs...
https://www.typescriptlang.org/docs/handbook/utility-types.html
Let's sasy you have a simple interface and instance...
interface Todo {
title: string;
description: string;
}
const todo1 = {
title: 'organize desk',
description: 'clear clutter',
};
How would we write a method that takes our instance of Todo and updates it with values from another Todo?
How about this?
function updateTodo(originalTodo: Todo, fieldsToUpdateTodo: any) {
return { ...originalTodo, ...fieldsToUpdateTodo };
}
const todo2 = updateTodo(todo1, {
description: 'throw out trash',
});
Not great. We had to type fieldsToUpdateTodo as any because if it was an Todo, we would need to set every property on the Todo interface. What if we only wanted to update description? Hence using any. I guess we could mark all properties in Todo as optional, but then we'd lose a lot of the typechecking that we love.
If we knew we only ever wanted to update description things are easier...
function updateTodoDescription(originalTodo: ITodo, description: string) {
return { ...originalTodo, description: description };
}
But this pattern isn't scaleable if we had many properties and wanted to arbitrarily update properties.
Let's cut to the chase. How can Partial help? Turns out it's simple, barely an inconvenience...
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return { ...todo, ...fieldsToUpdate };
}
Wrapping an object in Partial marks all the properties on that object as optional.
We can then call our updateTodo like this...
const todo2 = updateTodo(todo1, {
description: 'throw out trash',
});
We are not forced to set every property from the Todo interface. Our UpdateTodo method can then happily use the spread operator to merge the two Todo's.
Top comments (19)
I normally use
Partial<T>
interface when making class constructors.I do the same except with
Object.assign
with partials like so:Works really nicely for creating and updating data.
Rather than having a web of
Object.assign
everywhere you actually see and work with the shape of your data.Your
extend
method just looks likeObject.assign
:)Completely forgot that one exists. Symptom of working too much with an old IE11-supported javascript framework. :P
Nice, I didn't know about
Partial
, nice find, will be useful!Yup it could be used, but take into account that
Object.assign
doesn't merge nested objects.Interesting pattern. I may have to play with it. Thanks!
Yeah
Partial<T>
is great. Another good one isReadonly<T>
. It's a neat way to make things read-only, from a TS perspective even if under the hood (read JS), things are not truly read-only.Here's a TypeScript Playground example for those interested.
For reference, here's the full list of built-in Utilitiy Types. Lots of great stuff in there.
Looking forward to your next post!
It's also interesting to use the Omit<> type, which in most cases is actually a better fit because you can actually say which attibutes are not gonna be present.
Shoutout to Fiona Tran for bringing Partial to my attention.
This a much faster way to type Pick<T,any> :) thanks!
Partial’s are tight!
why not simply use optional parameters ?
Just because something should be optional in a parameter for example doesn't mean it should be optional everywhere, as would happen if you set it optional in the interface
This is great - also the first I'm learning about it!
This partial pattern is completely awesome.. thanks @nick
Watch out...
wow, I didn't know about partial either, thanks for sharing