128

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.

Koen.
  • 25,449
  • 7
  • 83
  • 78
Fartab
  • 4,725
  • 2
  • 26
  • 39
  • 3
    For Type1 you need [to remove optional modifier](https://stackoverflow.com/questions/49655419/mapped-types-removing-optional-modifier) – artem Oct 29 '18 at 16:55
  • awesome @artem, that was what I was looking for. – Fartab Oct 29 '18 at 17:06

7 Answers7

225

Use the NonNullable built-in type:

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

See TypeScript: Documentation - Utility Types

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
DShook
  • 14,833
  • 9
  • 45
  • 55
  • So sad that it does not exclude `null` from the type if you don't have `--strictNullChecks` enabled... – Klesun Mar 02 '21 at 13:49
  • 5
    Downvoted because this removes `null` and `undefined` from the type itself, not from its properties, does it? Hence it does not answer the question. – zbr Dec 13 '22 at 11:53
  • Indeed! https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgJLIN4Chm+XALmRAFcBbAI2mQB9iSAbBgbhzwqIGcwpQBzWshIgAJhBigII1nmQIA-EQoB7ZQwhwQrAL5YsYAJ4AHFADllAVVHjJIgGLAIDEQB4AKgD5kAXkzIA2gAKyKDIANYQBsowyG4AugC0isjmVmISIFIOTq7mIKaMDHAU6u5BcR5e2qxYCMog3PhEAKIAHggMJGIuqAA09EyCwum2Xr7YsoQDDL1suBzIAESLs7IIRDwkELO6tfWNC3kFTMWlqGOYc03Tq+xEy7e468ib21i7dQ1gckSp1hlZRzOHoXCZ4KakJiPZALB5XZ6vHZYIA – Antoine Dec 16 '22 at 10:47
61

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

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
Fartab
  • 4,725
  • 2
  • 26
  • 39
  • This is exactly the answer I expected, filtering an existing interface. Thank you! – Lancer.Yan Aug 21 '20 at 09:36
  • Thank you very much. I was wondering what does the `-?`. Where did you find this specification? I always read the documentation of TS first, but I think that there isn't easy to find stuff. – Nikolas Freitas Mr Nik Nov 19 '20 at 17:50
  • Hi Nikolas. Yeah, that was hard to find. Two year ago, @artem told me such an operator exists. – Fartab Nov 20 '20 at 23:40
  • There is something missing, I get `Type 'NoUndefinedField' is missing the following properties from type 'Uint8Array': [Symbol.iterator], [Symbol.toStringTag]` -- this one worked: https://stackoverflow.com/a/61766383/544779 – Mörre Apr 07 '21 at 14:40
16

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

13

@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 }
tim.stasse
  • 171
  • 1
  • 7
12

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>;
};
Stepan
  • 1,136
  • 12
  • 14
5

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

rmolinamir
  • 1,121
  • 14
  • 15
  • I was looking for a solution to make all properties of a type non-nullable. This works, thanks – Tris Jun 15 '22 at 06:57
1

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

Jerboas86
  • 596
  • 4
  • 12
  • I like this one. It takes the best parts of all the other answers. It even covers the distinction between an optional property (`?`) and `| undefined` in a type (removes both) which is helpful if you have the `exactOptionalPropertyTypes` TS config option turned on. – RcoderNY Aug 21 '23 at 02:33