Improved control over mapped type modifiers#21919
Conversation
|
We should talk about this in the next design meeting though. |
|
Is there any way filter out just the required properties or just the optional properties? I've been trying to make a type mapping that does this with no luck so far. |
|
@yortus Something like this: type OptionalPropNames<T> = { [P in keyof T]: undefined extends T[P] ? P : never }[keyof T];
type RequiredPropNames<T> = { [P in keyof T]: undefined extends T[P] ? never : P }[keyof T];
type OptionalProps<T> = { [P in OptionalPropNames<T>]: T[P] };
type RequiredProps<T> = { [P in RequiredPropNames<T>]: T[P] };
type Foo = {
a: string;
b: number;
c?: string;
d?: number;
}
type T1 = RequiredProps<Foo>; // { a: string, b: number }
type T2 = OptionalProps<Foo>; // { c?: string | undefined, d?: number | undefined }Strictly speaking this doesn't filter on optional vs. required, but rather whether |
|
i salute the idea, but somehow this syntax doesn't seem scalable |
|
@ahejlsberg thanks, that's just what I need. @Aleksey-Bykov the syntax makes me uncomfortable too. TypeScript is steadily building up really useful full compile-time programming capabilities, but some of the syntax seems very specific to a few cases (e.g. this PR). Having a few highly orthogonal compile-time programming constructs that also covered these special cases would be ideal. But I'm sure that's much easier said than done. |
|
on a constructive note, at some point when there are over 10 different modifiers at play we gonna need some meta syntax to control them, something like this, forgive my french: or something like |
|
to extend this idea to mapped or nested types by making a set modifiers a function of the previous/higher set of modifiers |
|
These look good to me, and I'm actually pretty OK with the syntax. If something better were suggested, sure, but I'd be comfortable/happy with using this one. As for @Aleksey-Bykov suggestions, compile-time, type-domain functions in general would be a really useful thing to have. Conditional types get us a big step closer to that, but we still aren't there. This might be a nice place to start. |
|
I think we're making big strides forward. With the pattern matching and recursion, I got a bunch of types to work that just hadn't been possible before (e.g. setting/removing readonly/? recursively in nested structures, flattening promises/arrays). |
Mapped types currently support adding a
readonlyor?modifier to a mapped property, but they do not provide support the ability to remove modifiers. This matters in homomorphic mapped types (see #12563 and #12826) which by default preserve the modifiers of the underlying type.With this PR we provide the ability for a mapped type to either add or remove a particular modifier. Specifically, a
readonlyor?property modifier in a mapped type can now be prefixed with either+or-to indicate that the modifier should be added or removed.Using this ability, the PR defines a new
Required<T>type inlib.d.ts. This type strips?modifiers from all properties ofT, thus making all properties required:Some examples of
+and-on mapped type modifiers:A modifier with no
+or-prefix is the same as a modifier with a+prefix. So, theReadonlyPartial<T>type above corresponds toIn
--strictNullChecksmode, when a homomorphic mapped type removes a?modifier from a property in the underlying type it also removesundefinedfrom the type of that property:Fixes #15012.