When using the Minus mapped type it seems to be removing modifiers from the properties. I think it is being caused by the Exclude type but I am not sure why.
I expected Minus to just remove the keys of U from T without changing the property modifiers of T.
type Minus<T, U> = { [P in Exclude<keyof T, keyof U>]: T[P] }
type Noop<T> = { [P in keyof T]: T[P] }
interface Student {
readonly gpa: number
hobby?: string
name: string
}
interface Person {
name: string
}
type Difference = Minus<Student, Person>
// type Difference = {
// gpa: number; <-- Where did readonly go?
// hobby: string | undefined; <-- Why is it no longer optional? It seems to have picked up '| undefined' though...
// }
const test1: Difference = { gpa: 4 } // <-- Error: property 'hobby' is missing
type NoopType = Noop<Student>
// type StringsOnly = {
// readonly gpa: number;
// hobby?: string | undefined;
// name: string;
// }
const test2: NoopType = { gpa: 4, name: "bob" } // OK
Typescript will preserve modifiers for homomorphic mapped types as described here, but the basic idea is that modifiers are preserved if the type has the form { [P in keyof T]: T[P] }
or something similar to that. In your case the compiler doesn't recognize the mapped type as being homomorphic because of Exclude<keyof T, keyof U>
and I am pretty sure this limitation is documented somewhere but I can't fin it at the moment. The simple way of getting around this is to use an extra indirection through Pick
for example:+
type Minus<T, U> = Pick<T, Exclude<keyof T, keyof U>>