Home > Software engineering >  What is the difference between Partial and Optional operator in typescript?
What is the difference between Partial and Optional operator in typescript?

Time:11-01

interface I1 {
    x: number;
    y: string;
}

interface I2 {
    x?: number;
    y?: string;
}

const tmp1: Partial<I1> = {}, tmp2: I2 = {};

Just like the example, is there an obvious difference between these two things?

CodePudding user response:

The difference is what is being expressed.

The types of tmp1 and tmp2 are the same because Partial does the same as

type MyPartial<T> = { [K in keyof T] ?: T[K] }

Playground Link

Where ? is a mapping modifier that makes a property optional.

However, other than structural compatibility, the types express *different things`:

  • I1 implies that the regular shape of the object expected is non-optional. Modifying it via Partial means that is an exception to the regular expectations.
  • I2 is the opposite - the regular shape of the object expected is fully optional.

Illustrating with a real looking type might make it be clearer:

interface User {
    age: number;
    name: string;
}

Cements the decision that all User objects must have age and name filled in. Otherwise they are not a valid User. However, conceivably there can be a Partial<User> in the system while the full set of information is still being collected. That would be a temporary state cannot be directly used with (for example)

function saveUser(user: User) { /* ... */ }

as that function requires a real user object with all the fields.

Conversely, a fully optional type might be more appropriate when any subset of the data is valid:

interface SurveyResult {
    score?: number;
    comment?: string;
}

Means that any survey outcome is expected. Only the score can be filled in, or the comment, or even nothing. Presumably, even an empty result still counts for the total surveys or similar.

CodePudding user response:

The existing answer addresses the direct question you had, but you might be wondering why there are multiple ways to express optional type fields like this.

There are in fact several reasons why Partial<I1> may be used instead of I2 (this is not an exhaustive list). The first and most obvious is that if you add a new field to I1 then Partial<I1> will automatically contain it. This is especially important in larger projects, or for cases where the type of I1 may be coming from an external dependency. Additionally Partial<I1> is more readable for other developers who may modify the code later (or yourself, when you go looking for bugs a few months down the line). Partial<I1> can be much more concise, especially if I1 has a lot of fields. There is also the issue of typos and other potential problems that can appear when you are duplicating code in several places. As a general rule of thumb, you should use Partial<Type1> rather than manually creating a Type2 in scenarios like the original question.

  • Related