You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Allow conditionally setting optional properties in a mapped type #36126
You could imagine an intersection of two mapped types - one with optional properties and one with required. I think that might be what you had in mind?
So from this I imagine a solution like this:
type Optional<T> = {
[P in keyof T]?: T[P]
}
type MapParams<T> = {
[P in keyof T]: T extends string ? T[P] : Optional<T>[P]
}
but this still doesn't work. If I do this:
type Optional<T> = {
[P in keyof T]?: T[P]
}
type MapParams<T> = {
[P in keyof T]: Optional<T>[P];
}
then the ? in Optional gets converted into T[P] | undefined in MapParams
I also ran into this limitation. As pointed out #32562, it is possible to workaround this limitation (I'm posting here because I think this issue has a much clearer title/description and is easier to find).
Here is an ugly but working solution that will hopefully help someone else:
typePickUndefinedKeys<T>={[KinkeyofT]: undefinedextendsT[K] ? K : never;}[keyofT];typePickRequiredKeys<T>={[KinkeyofT]: undefinedextendsT[K] ? never : K;}[keyofT];typeSelectOptional<Textends{}>=Pick<T,Exclude<PickUndefinedKeys<T>,undefined>>;typeSelectRequired<Textends{}>=Pick<T,Exclude<PickRequiredKeys<T>,undefined>>;// EXAMPLEStypeTest1=SelectOptional<{one?: string;two: number}>;// => { one?: string }typeTest2=SelectRequired<{one?: string;two: number}>// => { two: number }
As a more complex example, say you want to map the types in an object while retaining each property's original optional status:
Edit:
It's worth noting that I don't think this workaround can differentiate between { one?: string } and { one: string | undefined }. In my case, that's fine, but that might be problematic for others.
+1 to supporting this in a first-class way. My use case is that I want to map keys of a certain value type to a different value type, while preserving the optional-ness of the properties in the original type:
// I want to turn this:exportinterfaceBaseComment{creator: UserReference;repliers?: UserReference[];}// into this:exportinterfaceDisplayComment{creator: UserID;repliers?: UserID[];}// ideally by doing something likeexporttypeDisplayComment=Display<BaseComment>;
Currently I have to splice together 2 mapped types to combine both required vs optional keys in order to "preserve" their optional-ness:
// Found this method from https://type-level-typescript.com/articles/how-to-get-optional-keys-from-object-typesexporttypeRequiredKeys<T>=keyof{[KinkeyofTasOmit<T,K>extendsT ? never : K]: T[K];};exporttypeOptionalKeys<T>=keyof{[KinkeyofTasOmit<T,K>extendsT ? K : never]: T[K];};exportinterfaceBaseComment{creator: UserReference;repliers?: UserReference[];}exporttypeConvertReferenceToID<T>=TextendsArray<UserReference> ? UserID[] : TextendsUserReference ? UserID : T;exporttypeDisplay<T>={[KinRequiredKeys<T>]: ConvertReferenceToID<T[K]>}&{[KinOptionalKeys<T>]?: ConvertReferenceToID<T[K]>;};exporttypeDisplayComment=Display<BaseComment>;
Activity
Roaders commentedon Jan 10, 2020
From Daniel Rosenwasser (@DanielRosenwasser) on Twitter:
So from this I imagine a solution like this:
but this still doesn't work. If I do this:
then the
?inOptionalgets converted intoT[P] | undefinedinMapParamsjcalz commentedon Jan 13, 2020
Duplicate of #32562
jorroll commentedon Nov 23, 2020
I also ran into this limitation. As pointed out #32562, it is possible to workaround this limitation (I'm posting here because I think this issue has a much clearer title/description and is easier to find).
Here is an ugly but working solution that will hopefully help someone else:
As a more complex example, say you want to map the types in an object while retaining each property's original optional status:
Edit:
It's worth noting that I don't think this workaround can differentiate between
{ one?: string }and{ one: string | undefined }. In my case, that's fine, but that might be problematic for others.DavideValdo commentedon May 17, 2021
I managed to pull this off with some work:
I think it would be confusing to have the logic for adding
?in the right side of a property declarationIt would be awesome to have this syntax:
But I guess this is not such a common problem to justify the effort.
OoDeLally commentedon Apr 1, 2022
I was thinking about this, and I have a syntax proposal that doesn't require any parser change:
Note that TS already uses such "trick" with
neverto command not to add the key at all, so I think my proposal is the closest to an existing behavior.ecyrbe commentedon Jul 31, 2023
Here is a proposal syntax leveraging on
K in keyof T assyntax but allowing modifiers to be part of brakets :if you use '-' instead of '+' it removes the modifier :
layerok commentedon Jun 22, 2024
By combing
PickOptinalPropertiesandPickRequiredPropertiestypes, I was able to construct a type that makes properties that extend undefined optionaljoyt commentedon Apr 2, 2025
+1 to supporting this in a first-class way. My use case is that I want to map keys of a certain value type to a different value type, while preserving the optional-ness of the properties in the original type:
Currently I have to splice together 2 mapped types to combine both required vs optional keys in order to "preserve" their optional-ness: