-
Notifications
You must be signed in to change notification settings - Fork 118
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
Is a version of DeepOmit that recursively removes keys possible? #104
Comments
You'd need a separate type for that. If we decide there are enough usecases for it, we could write one, it would even be simpler than the specific The question here: what should be the type constraint for the filter here? |
For anyone else looking for this I have a solution that works in TS 4.9. It was adapted from https://gist.github.com/ahuggins-nhs/826906a58e4c1e59306bc0792e7826d1 (which itself was adapted from https://stackoverflow.com/a/55539616/3438793). The key(s) to exclude has no relation to the type, just like the built-in /** Union of primitives to skip with deep omit utilities. */
type Primitive = string | Function | number | boolean | symbol | undefined | null;
/** Deeply omit members of an interface or type. */
type DeepOmitKey<T, K extends keyof any> = T extends Primitive
? T
: T extends any[]
? { [P in keyof T]: DeepOmitKey<T[P], K> }
: {
[P in Exclude<keyof T, K>]: T[P] extends infer TP // Distribute over unions
? DeepOmitKey<TP, K>
: never;
}; |
@simon-abbott thank you for the suggestion! Would you like to see it like that in this library? The use case is clear for me based on StackOverflow example, I'm happy to add it, test cases and examples if anyone or you are interested |
It would be useful, yes! There aren't many use cases for it, but where it's needed it's really useful. I'm using the above code in our codebase, so being able to import it from ts-essentials instead would be great. In fact, the reason I found this issue was because I was hoping ts-essentials already had this built in, and when I was trying to find it I came across this issue asking for it. |
Great! I will start working on it when finish other PRs Let me know if you have other good examples that I can add to the documentation. If not, I will leave |
I could make up some synthetic examples, but the only realistic use-case I can currently think of is |
After trying this out on more code, I realized that my first draft discards optionality, which isn't ideal. Here is a second version that preserves optionality: type Primitive =
| string
| Function
| number
| boolean
| symbol
| undefined
| null;
type OptionalKeys<T> = {
[K in keyof T]-?: T extends { [P in K]: any } ? never : K;
}[keyof T];
type RequiredKeys<T> = Exclude<keyof T, OptionalKeys<T>>;
// This is technically optional, but without it the resulting type is full of
// intersections, which is hard to read. For example, if this is left out, the
// type `DeepOmitKey<{a?: string; b: number; c: boolean}, 'b'>` gets resolved as
// `{a?: string} & {c: boolean}` instead of `{a?: string; c: boolean}`.
type ResolveIntersection<T> = T extends infer O
? { [K in keyof O]: O[K] }
: never;
/** Deeply omit members of an interface or type. */
type DeepOmitKey<T, K extends keyof any> = T extends Primitive
? T
: T extends any[]
? { [P in keyof T]: DeepOmitKey<T[P], K> }
: ResolveIntersection<
{
[P in Exclude<OptionalKeys<T>, K>]+?: Required<T>[P] extends infer TP // Distribute over unions
? DeepOmitKey<TP, K>
: never;
} & {
[P in Exclude<RequiredKeys<T>, K>]-?: Required<T>[P] extends infer TP // Distribute over unions
? DeepOmitKey<TP, K>
: never;
}
>; |
@simon-abbott LGTM! I will need to run some checks before adding this enhancement. Let me know if you'd like to contribute yourself, I will be able to help with it. Otherwise I will add it to my list and will come back to you once the PR is ready |
Go for it! I'm in no rush for this to be added (we just have that definition in our own codebase for now), I just want to save the 5 others who will find this useful the trouble of having to invent it themselves. 😄 |
Is it possible to write a DeepOmit that recursively applies the filter ...?
I get type errors for iWishThisWouldTypeCheck because of missing __typename fields ...
In my case -- a version that simply took string arguments would work fine if that is easier to accomplish somehow ... -- eg
DeepOmit<Input, "__typename">
The text was updated successfully, but these errors were encountered: