Fartab
Fartab

Reputation: 5503

remove null or undefined from properties of a type

I need to declare a type such that removes the undefined from its property types.

Suppose we have:

type Type1{
  prop?: number;
}

type Type2{
  prop: number | undefined;
}

type Type3{
  prop: number;
}

I need to define a generic type called NoUndefinedField<T> such that NoUndefinedField<Type1> gives the same type as Type3 and the same type as NoUndefinedField<Type2>.

I tried this

type NoUndefinedField<T> = { [P in keyof T]: Exclude<T[P], null | undefined> };

But it only works for Type2.

Upvotes: 168

Views: 124695

Answers (7)

Jerboas86
Jerboas86

Reputation: 664

The following utility type will:

  • Remove optional property modifier (?) from each field
  • Remove null and undefined from each field
  • Accept only object type
type RequiredProperty<T extends object> = { [P in keyof T]-?: Required<NonNullable<T[P]>>; };

Typescript playground

Upvotes: 5

DShook
DShook

Reputation: 15672

Use the NonNullable built-in type:

type NonNullable<T> = Exclude<T, null | undefined>;  // Remove null and undefined from T

See TypeScript: Documentation - Utility Types

Upvotes: 280

Parsa Nasirimehr
Parsa Nasirimehr

Reputation: 408

Nowadays you can use Required to do exactly what you need:

Required<Type1>

That will result in all the fields becoming non-optional. More details can be found here

Upvotes: 15

rmolinamir
rmolinamir

Reputation: 1480

Some of the answers were not working for me, I ended up with a similar solution based on the top answers:

type RequiredNonNullableObject<T extends object> = { [P in keyof Required<T>]: NonNullable<T[P]>; };

This results in the following:

type ObjectType = {

  startDateExpr?: string | null;
  endDateExpr?: string | null;

  startDate?: Date | null;
  endDate?: Date | null;

}

type Result = RequiredNonNullableObject<ObjectType>; 

With the Result type being equal to:

type Result = {
  startDateExpr: string;
  endDateExpr: string;
  startDate: Date;
  endDate: Date;
}

TypeScript Playground Example

Upvotes: 7

Stepan
Stepan

Reputation: 1236

Something in both @Fartab's and @tim.stasse's answers is messing up a property of type Date for me:

// both:
type NoUndefinedField<T> = {
  [P in keyof T]-?: NoUndefinedField<NonNullable<T[P]>>;
};
type NoUndefinedField<T> = {
  [P in keyof T]-?: NoUndefinedField<Exclude<T[P], null | undefined>>;
};
// throw:
Property '[Symbol.toPrimitive]' is missing in type 'NoUndefinedField<Date>' but required in type 'Date'.ts(2345)
// and
type NoUndefinedField<T> = { [P in keyof T]: Required<NonNullable<T[P]>> };
// throws:
Property '[Symbol.toPrimitive]' is missing in type 'Required<Date>' but required in type 'Date'.ts(2345)

I'm having success with this solution without recursion:

type NoUndefinedField<T> = {
  [P in keyof T]-?: Exclude<T[P], null | undefined>;
};

Upvotes: 14

Fartab
Fartab

Reputation: 5503

Thanks to @artem, the solution is:

type NoUndefinedField<T> = { [P in keyof T]-?: NoUndefinedField<NonNullable<T[P]>> };

Notice the -? syntax in [P in keyof T]-? which removes optionality

Upvotes: 82

tim.stasse
tim.stasse

Reputation: 309

@DShook's answer is incorrect (or rather incomplete) because the OP is asking to remove null and undefined from the types properties, not from the type itself (a distinct difference).

While @Fartab's answer is correct, I'll add to it, as there is now the built-in Required type, and the solution can be re-written as:

type RequiredProperty<T> = { [P in keyof T]: Required<NonNullable<T[P]>>; };

This will map the types properties (not the type itself), and ensure that each one is neither; null or undefined.

An example of the difference between removing null and undefined from the type, versus removing them from a types properties (using the above RequiredProperty type):

type Props = {
  prop?: number | null;
};

type RequiredType = NonNullable<Props>; // { prop?: number | null }
type RequiredProps = RequiredProperty<Props>; // { prop: Required<number> } = { prop: number }

Upvotes: 16

Related Questions