Hone logo
Hone
Problems

TypeScript Non-Nullable Union Helper

In TypeScript, it's common to work with types that can be either a specific type or null/undefined. This can sometimes lead to unnecessary checks and can make type definitions more verbose. This challenge asks you to create a utility type that simplifies working with types that are guaranteed to be non-nullable.

Problem Description

Your task is to implement a TypeScript utility type called NonNullableUnion<T>. This utility type should take a union type T as input and return a new union type where all occurrences of null and undefined have been removed.

Key Requirements:

  1. Remove null: If null is part of the input union T, it should not be present in the output type.
  2. Remove undefined: If undefined is part of the input union T, it should not be present in the output type.
  3. Preserve other types: All other types within the union T should be preserved in the resulting type.
  4. Handle primitive types: The utility should correctly handle primitive types, objects, and other valid TypeScript types within the union.
  5. Handle existing NonNullable: Be mindful that TypeScript already has a NonNullable<T> utility type. Your NonNullableUnion<T> should effectively apply the concept of non-nullability to each member of a union type, not just the union as a whole in a single step.

Expected Behavior:

  • NonNullableUnion<string | number | null> should resolve to string | number.
  • NonNullableUnion<string | undefined> should resolve to string.
  • NonNullableUnion<string | null | undefined> should resolve to string.
  • NonNullableUnion<{ a: number } | null> should resolve to { a: number }.
  • NonNullableUnion<string | null | { b: string } | undefined> should resolve to string | { b: string }.
  • NonNullableUnion<string> should resolve to string.

Examples

Example 1:

type InputType1 = string | number | null;
type OutputType1 = NonNullableUnion<InputType1>;
// Expected OutputType1: string | number

Explanation: The null is removed from the union.

Example 2:

type InputType2 = { name: string } | undefined | boolean | null;
type OutputType2 = NonNullableUnion<InputType2>;
// Expected OutputType2: { name: string } | boolean

Explanation: Both undefined and null are removed, preserving the object type and the boolean type.

Example 3:

type InputType3 = number | undefined;
type OutputType3 = NonNullableUnion<InputType3>;
// Expected OutputType3: number

Explanation: Only undefined is present, and it is removed.

Constraints

  • The solution must be a single TypeScript utility type definition.
  • The utility type should be named NonNullableUnion<T>.
  • No external libraries or packages are allowed.
  • The solution should be efficient and not rely on excessively complex or recursive type manipulations if a simpler approach exists.

Notes

Consider how you can iterate over the members of a union type and apply a transformation to each member individually. TypeScript's conditional types and distributive conditional types will be key here. Think about how to check if a type is null or undefined and how to exclude it from a union.

Loading editor...
typescript