Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SetRequiredDeep type #939

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

hugomartinet
Copy link

Closes #796

This pull request adds a new SetRequiredDeep which, like SetRequired, allows to make one or several keys in a model required. It adds the possibility to select nested keys by specifying their path.

Example

type AnOptionalType = {
  foo?: {
    bar?: number
    baz?: string
  }
}


type ARequiredDeepType = SetRequiredDeep< AnOptionalType, 'foo.bar'>;
// type ARequiredDeepType = {
//   foo: {
//     bar: number
//     baz?: string
//   }
// }

@Emiyaaaaa
Copy link
Collaborator

Emiyaaaaa commented Aug 14, 2024

Can this feature be added on SetRequired instead of a new type? just move code into SetRequired

@sindresorhus how about you think?

@sindresorhus
Copy link
Owner

The problem with doing both shallow and deep in a single method is that the deep logic affects the performance even if you don't need deep. This was the case for Simplify, where we had to split it out into a SimplifyDeep version.

source/set-required-deep.d.ts Show resolved Hide resolved
test-d/set-required-deep.ts Show resolved Hide resolved
test-d/set-required-deep.ts Show resolved Hide resolved
test-d/set-required-deep.ts Show resolved Hide resolved
}[]
}

type SomeRequiredDeep = SetRequiredDeep<Foo, 'a' | 'array.c'>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type SomeRequiredDeep = SetRequiredDeep<Foo, 'a' | 'array.c'>;
type SomeRequiredDeep = SetRequiredDeep<Foo, 'a' | 'array.${number}.c'>;

I kinda forgot how it's should be. You can add the example in test to ensure it is worked.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda forgot how it's should be. You can add the example in test to ensure it is worked.

This doesn't seem to be resolved @hugomartinet

@Emiyaaaaa
Copy link
Collaborator

Need to resolve all conversation

@hugomartinet
Copy link
Author

Need to resolve all conversation

Done


// Update a root key to required.
declare const variation2: SetRequiredDeep<{a?: number; b?: {c?: string}}, 'a'>;
expectType<{a: number; b?: {c?: string}}>(variation2);
Copy link

@Beraliv Beraliv Aug 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth adding a test case with multiple paths (i.e. BaseType is not a union)?

declare const variation2: SetRequiredDeep<{a?: number; b?: {c?: string}}, 'a' | 'b'>;
expectType<{a: number; b: {c?: string}}>(variation2);


@category Object
*/
export type SetRequiredDeep<BaseType, KeyPaths extends Paths<BaseType>> =
Copy link

@Beraliv Beraliv Aug 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm playing with this solution using the following example:

type Teacher = { address?: { postcode?: string; city?: string } };
type P1 = SetRequiredDeep<Teacher, 'address' | 'address.city'>;
//      ^?

This gives me:

type P1 = {
    address: {
        postcode: string;
        city: string;
    };
} | {
    address: {
        postcode: string;
        city: string;
    };
}

Is the result expected?

To elaborate:

  1. Why is the postcode required?
  2. Why is the result object a union? Are there any plans to merge a union into a single object?

Copy link
Collaborator

@Emiyaaaaa Emiyaaaaa Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, similar to PickDeep and OmitDeep. result should be

type P1 = { 
  address: { 
    postcode?: string; 
    city: string; 
  }; 
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think my current implementation could not work for this, since I use RequiredDeep and RequiredDeep makes all child keys of an object required as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SetRequiredDeep - is it possible?
4 participants