As I know there is no way to change property modifier of mapped types based on conditional types. Here is my use case:
export class MakeItRequired<T extends ModelValue<any>> {
target: "MakeItRequired" = "MakeItRequired"
constructor(public option: T) {
}
}
export type ModelValue<T> =
T extends StringConstructor ? string :
T extends NumberConstructor ? number :
T extends BooleanConstructor ? boolean :
unknown
export type ModelFromSchema<T> = {
[P in keyof T]?:
T[P] extends MakeItRequired<infer U> ? ModelValue<U> :
ModelValue<T[P]>
}
export const schema = {
id: new MakeItRequired(Number),
firstName: String,
lastName: String
}
export const type: ModelFromSchema<typeof schema> = {}
My goal is to have id non optional, while having others optional.
Additional screenshoot from vscode:

Can we have this feature?
~Okay, I think I found the way it can be implemented right now:~
export type ModelFromSchema<T> = {
[P in keyof T]+?:
T[P] extends MakeItRequired<infer U> ? unknown :
ModelValue<T[P]>
} & {
[P in keyof T]-?:
T[P] extends MakeItRequired<infer U> ? ModelValue<U> :
unknown
}
~Looks like unknown saves us here.~
~Issue can be closed, but I would like team to pay attention on the scalability of the current approach.~
EDIT 1: No, I was too happy about it. It doesn't work.
EDIT 2: Okay, found a resolution:
type MakeItRequiredKeyNames<T> = { [K in keyof T]: T[K] extends MakeItRequired<infer U> ? K : never }[keyof T];
type MakeItRequiredKeys<T> = Pick<T, MakeItRequiredKeyNames<T>>;
type NonMakeItRequiredKeyNames<T> = { [K in keyof T]: T[K] extends MakeItRequired<infer U> ? never : K }[keyof T];
type NonMakeItRequiredKeys<T> = Pick<T, NonMakeItRequiredKeyNames<T>>;
export type ModelFromSchema<T> = {
[P in keyof NonMakeItRequiredKeys<T>]?:
T[P] extends MakeItRequired<infer U> ? never :
ModelValue<T[P]>
} & {
[P in keyof MakeItRequiredKeys<T>]:
T[P] extends MakeItRequired<infer U> ? ModelValue<U> :
never
}
Just note that your types might look a little "ugly" in the tooltip. It'll still work just fine, though.
If you want to make it look a little better (maybe for debugging or something),
Identity<T> = T;
Merge<T> = (
T extends any ?
Identity<{ [k in keyof T] : T[k] }> :
never
);
Then,
type Blah = Merge<ModelFromSchema<T>>;
When you hover over Blah, you should see the two objects merged into one
I'm on mobile and can't test it but I think the above works. I'll check again when I get home
Possibly relevant comment from another somewhat related issue (#31581, about detecting such modifiers)
I'd be interested in more streamlined manipulation of modifiers in mapped types. Detecting `readonly` and optional properties is indeed a bunch of hoop jumping, and then if you want to selectively *alter* the modifiers, you need to split the mapping into pieces and intersect them:It would be a lot nicer to essentially read and selectively write modifiers inside the mapping directly. (Note the word "selectively"; the [current support](https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#improved-control-over-mapped-type-modifiers) for altering modifiers is all-or-nothing ).type SelectivePartial<T, K extends keyof T> = Partial<Pick<T, K>> & Required<Pick<T, Exclude<keyof T, K>>> extends infer U ? { [P in keyof U]: U[P] } : never; type Foo = SelectivePartial<{ a: string, b: number, c?: boolean }, 'b'> // type Foo = { b?: number | undefined; a: string; c: boolean; }
Most helpful comment
Possibly relevant comment from another somewhat related issue (#31581, about detecting such modifiers)