33

If I have a type with all required properties, how can I define another type with the same properties where some of it's properties are still required but the rest are optional?

For example I want a new type derived from SomeType where prop1 and prop2 are required but the rest are optional:

interface SomeType {
    prop1;
    prop2;
    prop3;
    ...
    propn;
}

interface NewType {
    prop1;
    prop2;
    prop3?;
    ...
    propn?;
}

5 Answers 5

71

You can use combination of Partial and Pick to make all properties partial and then pick only some that are required:

interface SomeType {
    prop1: string;
    prop2: string;
    prop3: string;
    propn: string;
}

type OptionalExceptFor<T, TRequired extends keyof T> = Partial<T> & Pick<T, TRequired>

type NewType = OptionalExceptFor<SomeType, 'prop1' | 'prop2'>

let o : NewType = {
    prop1: "",
    prop2: ""
}
Sign up to request clarification or add additional context in comments.

3 Comments

For completeness: type RequiredExceptFor<T, TOptional extends keyof T> = Pick<T, Diff<keyof T, TOptional>> & Partial<T>; with type Diff<T, U> = T extends U ? never : T;
There's a catch here. If the source properties are optional, say prop1 and prop2, that won't trigger any error. Wrapping Pick in Required shold do the job. type OptionalExceptFor<T, TRequired extends keyof T> = Partial<T> & Required<Pick<T, TRequired>>;
Thanks @AlexanderD. But for this one, I want only to mark optional what properties I want, so the rest remains the same.
7
type onlyOneRequired = Partial<Tag> & {id: string}

In the above type, all properties of Tag are optional instead of id which is required. So you can use this method and specify the required properties.

4 Comments

This solution does not work : typescriptlang.org/play?#code/…
My bad, it does not work with nested types
@cassepipe Sorry I was on a holiday I hope the answer helped you :)
@M Fuat It did thanks. Actually I believe none of the other answers can work with nested types anyways. Your answer should be the accepted one as it is the most readable in my opinion
5

For tetter performance, in addition to Titian's answer, you must do :

type OptionalExceptFor<T, TRequired extends keyof T = keyof T> = Partial<
  Pick<T, Exclude<keyof T, TRequired>>
> &
  Required<Pick<T, TRequired>>;

2 Comments

this works for me when I tried to use the type in a spread operator into a fully required version, there Titian's above did not.
In what situations would this affect performance? Would it be compile times for typescript? Or handling big objects in editor? As I guess it has no impact on js execution?
4

From this article:

We can derive the following type:

export type PartialPick<T, F extends keyof T> = Omit<T, F> & Partial<Pick<T, F>>;

F - the fields that should be made optional

T - the type

In your example:

type NewType = PartialPick<SomeType, 'prop3' | ... | 'propn'>

If you'd like to make some properties required instead of the partial use:

type RequiredPick<T, F extends keyof T> = Omit<T, F> & Required<Pick<T, F>>;

If NewType should be an interface and has additional fields besides the fields in SomeType, you can use extends from the type:

interface SomeType {
    prop1;
    prop2;
    prop3;
    prop4;
}
interface NewType extends PartialPick<SomeType, 'prop3' | 'prop4'> {
    prop5;
}

Comments

0

Here is another way

export type ContactInfoFormInput = Pick<AccountDetails, 'email' | 'phone'> &
  Pick<Profile, 'firstName' | 'lastName'> & {
    dateCreated?: Profile['dateCreated'];
  };

So in this example, email, phone, firstName, lastName are all required but dateCreated which also comes from the Profile base type is optional

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.