Reputation: 713
I have implemented a type which takes an object
and returns a type without any nullish
values.
export type OmitNullish<T> = Exclude<T, null | undefined>;
export type OmitNullishKeys<T> = {
[K in keyof T]-?: T[K] extends boolean | string | number | symbol ? OmitNullish<T[K]> : OmitNullishKeys<T[K]>;
};
However, when I attempt to retrieve a nested
key, tsc
using:
export type RandomObj = OmitNullishKeys<{
stackOverflow: {
forums?: {
thread1: 'not available';
} | null;
} | null;
}>;
export type RandomObjectAccessed = RandomObj['stackOverflow']['forums'];
it states the following:
Property 'forums' does not exist on type 'OmitNullishKeys<{ forums?: { thread1: "not available"; } | null | undefined; } | null>'.
It seems as the resulting type is treated as OmitNullishKeys
instead of an object without nullish
values. Is there a reason for this?
Upvotes: 0
Views: 117
Reputation: 713
The issue was resolved initially by:
export type N = null | undefined;
export type OmitNullish<T> = T extends (infer U)[] ? Exclude<U, N>[] : Exclude<U,N>
export type OmitNullishKeys<T> = {
[key in keyof Required<T>]-?: T extends Record<string, unknown> ? OmitNullish<OmitNullishKeys<T[K]>> : OmitNullish<T[K]>
}
Which resolved the issue
OmitNullish
keyof
is used without enforcing non-optionality
, the resulting value is T | undefined
. Required
forces the key to be treated as it were there.but applied the non-nullish
rules to classes such as Date
.
Using the alternate solution provided by @jcalz with the addition of a conditional to avoid overwriting classes, we get
type OmitNullish<T, E = Date> = T extends E ? T : NonNullable<{
[key in keyof T]-?: OmitNullish<T[K]>
}>
which gives us a succinct way of ensuring all elements within an object are not-nullish.
Upvotes: 0
Reputation: 6872
If we introduce a helper type for expanding the type of RandomObj
. Then we can clearly see that your logic in OmitNullishKeys
is faulty. The resulting type RandomObj
does still contain values that might be null.
type ExpandType<T> = T extends object
? T extends infer O ? { [K in keyof O]: ExpandType<O[K]> } : never
: T;
type ExpandedRandomObj = ExpandType<RandomObj>;
/*
type ExpandedRandomObj = {
stackOverflow: {
forums: {
thread1: 'not available';
} | null;
} | null;
}
*/
Upvotes: 2