Reputation: 5503
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
Reputation: 664
The following utility type will:
null
and undefined
from each fieldobject
typetype RequiredProperty<T extends object> = { [P in keyof T]-?: Required<NonNullable<T[P]>>; };
Upvotes: 5
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
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
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;
}
Upvotes: 7
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
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
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