Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Recursively remove all undefined and null types from data structures of arbitrary-depth
type DeepRequiredNonNullable<T> = T extends null | undefined
? never
: (T extends (infer ElementType)[]
? DeepRequiredNonNullable<ElementType>[]
: (T extends Record<string | number, any>
? { [key in keyof T]-?: DeepRequiredNonNullable<T[key]> }
: T));
// Number test
type BadPrimitive = number | null | undefined | string;
type GoodPrimitive = number | string;
const num1: DeepRequiredNonNullable<BadPrimitive> = 1;
const num2: DeepRequiredNonNullable<BadPrimitive> = 'a';
const numberTester: GoodPrimitive[] = [num1, num2];
// Arr test
type BadArray = BadPrimitive[];
type GoodArray = GoodPrimitive[];
const arr1: DeepRequiredNonNullable<BadArray> = [1, 'a'];
const arr2: DeepRequiredNonNullable<BadArray> = [];
const arrTester: GoodArray[] = [arr1, arr2];
// Obj test
type BadObject = { a?: BadPrimitive; b?: BadArray; c?: GoodPrimitive };
type GoodObject = { a: GoodPrimitive; b: GoodArray; c: GoodPrimitive };
const obj1: DeepRequiredNonNullable<BadObject> = { a: 1, b: [1], c: 1 };
const obj2: DeepRequiredNonNullable<BadObject> = { a: 'a', b: ['a'], c: 'a' };
const objTester: GoodObject[] = [obj1, obj2];
// Boss level
type BadEverything = {
a?: {
b?: number | null;
};
c: string | null;
d: Array<null | undefined | number>;
e: {
f?: {
g: Array<null | undefined | number>;
h?: Array<
| null
| undefined
| {
i?: Array<number | null | string>;
}
>;
};
};
};
type GoodEverything = {
a: {
b: number;
};
c: string;
d: Array<number>;
e: {
f: {
g: Array<number>;
h: Array<{
i: Array<number | string>;
}>;
};
};
};
const everything1: DeepRequiredNonNullable<BadEverything> = {
a: {
b: 1,
},
c: 'a',
d: [1],
e: {
f: {
g: [1],
h: [{ i: [1, 'a'] }],
},
},
};
const everythingTester: GoodEverything[] = [everything1];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.