remove null or undefined from properties of a type
Asked Answered
D

7

147

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.

Demurral answered 29/10, 2018 at 16:34 Comment(2)
For Type1 you need to remove optional modifierAdequacy
awesome @artem, that was what I was looking for.Demurral
D
71

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

Demurral answered 29/10, 2018 at 17:12 Comment(4)
This is exactly the answer I expected, filtering an existing interface. Thank you!Hereditable
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.Corm
Hi Nikolas. Yeah, that was hard to find. Two year ago, @Adequacy told me such an operator exists.Demurral
There is something missing, I get Type 'NoUndefinedField<Uint8Array>' is missing the following properties from type 'Uint8Array': [Symbol.iterator], [Symbol.toStringTag] -- this one worked: https://mcmap.net/q/160723/-in-typescript-can-i-remove-the-undefined-and-null-types-from-an-object-using-a-list-of-keysUpheave
K
258

Use the NonNullable built-in type:

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

See TypeScript: Documentation - Utility Types

Kufic answered 1/2, 2019 at 16:34 Comment(4)
So sad that it does not exclude null from the type if you don't have --strictNullChecks enabled...Evelynneven
Downvoted because this removes null and undefined from the type itself, not from its properties, does it? Hence it does not answer the question.Buttress
Indeed! typescriptlang.org/play?#code/…Profusive
@Klesun: good to know! I was pulling my hair not understanding why neither Required nor NonNullable were having any effect! For the record: check your tsconfig.json to make sure strict or strictNullChecks are on.Fissirostral
D
71

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

Demurral answered 29/10, 2018 at 17:12 Comment(4)
This is exactly the answer I expected, filtering an existing interface. Thank you!Hereditable
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.Corm
Hi Nikolas. Yeah, that was hard to find. Two year ago, @Adequacy told me such an operator exists.Demurral
There is something missing, I get Type 'NoUndefinedField<Uint8Array>' is missing the following properties from type 'Uint8Array': [Symbol.iterator], [Symbol.toStringTag] -- this one worked: https://mcmap.net/q/160723/-in-typescript-can-i-remove-the-undefined-and-null-types-from-an-object-using-a-list-of-keysUpheave
P
16

@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 }
Pathogenic answered 20/7, 2019 at 5:2 Comment(1)
The re-written solution won't be recursive though, will it?Ensoul
A
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

Alrick answered 6/3, 2022 at 19:39 Comment(2)
It wont, it will make properties required but doesn't tell typescript properties can't be undefined or nullAttendant
Worded differently, Required is the opposite of Partial, and { foo?: string } means the property may or may not exist, and { foo: string | null } means property will always exist, but it's value may be string | nullGiotto
W
14

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>;
};
Worsted answered 7/3, 2020 at 4:39 Comment(1)
Thanks, this works well. I was having problems using the other answers as well when having user defined types for properties.Gilder
B
6

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

Bennet answered 14/1, 2022 at 18:7 Comment(1)
I was looking for a solution to make all properties of a type non-nullable. This works, thanksHandspring
A
3

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

Aracelis answered 18/4, 2023 at 7:19 Comment(2)
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.Progress
it's a beautiful tweak on typescripts built-in RequiredGiotto

© 2022 - 2024 — McMap. All rights reserved.