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

Deep analogue of MarkRequired with the skeleton of DeepModify #315

Open
xenoterracide opened this issue Jun 22, 2022 · 8 comments
Open

Deep analogue of MarkRequired with the skeleton of DeepModify #315

xenoterracide opened this issue Jun 22, 2022 · 8 comments
Labels
enhancement New feature or request v10.1

Comments

@xenoterracide
Copy link

I would like to be able to provide a structure to DeepRequired like DeepOmit, and I suspect this would be useful to all the Deep nested. The same structure as DeepOmit would work.

type TeacherSimple = DeepRequired<
  Teacher,
  {
    gender: never;
    students: {
      score: never;
    };
  }
>;
@Beraliv
Copy link
Collaborator

Beraliv commented Jun 22, 2022

Hey @xenoterracide!

Thank you for the suggestion! Yeah, it's a good feature that can be implemented

@Beraliv Beraliv added the enhancement New feature or request label Jun 22, 2022
@Beraliv
Copy link
Collaborator

Beraliv commented Aug 19, 2022

I started working on it here – #329

It will take time, so it will be possibly available in the release after the next one

@Beraliv
Copy link
Collaborator

Beraliv commented Mar 16, 2023

I think I will create a separate DeepMarkRequired to not change the simplicity of DeepRequired

@Beraliv Beraliv changed the title Deep nested with key specification Deep analogue of MarkRequired with the skeleton of DeepModify Mar 16, 2023
@Beraliv Beraliv added the help wanted Extra attention is needed label Mar 16, 2023
@Beraliv Beraliv removed the help wanted Extra attention is needed label Apr 3, 2023
@Beraliv Beraliv added the v10.1 label May 1, 2024
@jrnail23
Copy link

jrnail23 commented Aug 21, 2024

I'd love this too -- I have this need right now :)

@Beraliv
Copy link
Collaborator

Beraliv commented Aug 22, 2024

@jrnail23 hey! currently, it's a part of the next v10.1 release so it's unlikely to get merged today and be available. But I can have a look at the implementation now. I will come back to you when I have it.

@Beraliv
Copy link
Collaborator

Beraliv commented Aug 22, 2024

After reflecting on the proposal, I've realised that the Filter object-like structure (similar to DeepOmit and DeepPick) would have an obvious disadvantage: it is unclear what properties have to be required: leaves only or all keys included in the filter?

A simple example would be:

// There is a teacher with all required properties
type Teacher = {
  name: string;
  gender: "M" | "F"; // etc
  address: {
    postcode: string;
    city: string;
    street: string;
    apt: string;
  };
};

// Developers have to validate the object from the backend, therefore all properties are marked as optional
type MaybeTeacher = DeepPartial<Teacher>;

// But some of the properties have to be required for business logic, e.g. a city where a teacher lives
type TeacherWithAddress = DeepMarkRequired<
  MaybeTeacher,
  {
    address: {
      city: never;
    };
  }
>;

What is expected to get in TeacherWithAddress?

// 1. Only city is a required property while address will be optional
// {
//   name?: string;
//   gender?: "M" | "F"; // etc
//   address?: { // address is NOT required 🔴
//     postcode?: string;
//     city: string; // city is required 🟢
//     street?: string;
//     apt?: string;
//   };
// }

// 2. Both address and city will be required
// {
//   name?: string;
//   gender?: "M" | "F"; // etc
//   address: { // address is required 🟢
//     postcode?: string;
//     city: string; // city is required 🟢
//     street?: string;
//     apt?: string;
//   };
// }

Because the syntax is ambiguous, it will definitely confuse engineers during development.

One possible workaround is to use true on objects that have to be required, e.g.

type TeacherWithAddress = DeepMarkRequired<
  MaybeTeacher,
  {
    address: true | {
      city: never;
    };
  }
>;

However, I agree that it's not the best syntax

I suggest an alternative syntax with union elements:

type TeacherSimple = DeepMarkRequired<
  MaybeTeacher,
  'address' | 'address.city'
>;

DeepMarkRequired, similarly to MarkRequired will have an autocomplete, meaning address and address.city will be automatically inferred.

@jrnail23 @xenoterracide @DustinJSilk What do you think?

@Beraliv
Copy link
Collaborator

Beraliv commented Aug 22, 2024

Meanwhile, I've improved Paths performance in #409.

This will provide better DX if DeepMarkRequired's alternative syntax meets your requirements

@Beraliv Beraliv mentioned this issue Aug 22, 2024
2 tasks
@Beraliv
Copy link
Collaborator

Beraliv commented Aug 22, 2024

@jrnail23 @xenoterracide @DustinJSilk my proposal is implemented in #408

If you'd like to test the solution, please have a look at the TypeScript Playground - https://tsplay.dev/w1qRGw. It's not production-ready yet but I'm happy to experiment with it. Any feedback is welcome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request v10.1
Projects
None yet
Development

No branches or pull requests

3 participants