typescript - Varför förlorar jag information om huruvida en egenskap är valfri i denna Mapped Type


Jag har en mappad typ Minus<A,B> för att skapa en typ med alla egenskaper på A förutom de som också finns på B, som definieras som följer:

type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];

/**
 * Type T without any of the properties on U.
 */
export type Minus<T, U> = {[P in Diff<keyof T, keyof U>]: T[P]};

Till exempel, om jag har två gränssnitt, A

interface A {
    thing1: string;
    thing2: number;
}

och B

interface B {
    thing1: string;
}

då Minus<A, B> bör resultera i en typ motsvarande

interface C {
    thing2: number;
}

Detta fungerar bra tills jag har valfria typer på A, eftersom dessa går förlorade någonstans på vägen.

Ersätter A med

interface A {
    thing1: string;
    thing2?: number;
}

kommer att resultera i en typ som ser ut som

interface C {
    thing2: number;
}

istället för det önskade

interface C {
    thing2?: number;    
}

Intressant nog verkar beteendet för en Readonly<T> bevara huruvida egenskaper är valfria eller inte; Readonly kommer att producera en typ som motsvarar

interface ReadonlyA {
    readonly thing1: string;
    readonly thing2?: number;
}

Så jag misstänker att detta har något att göra med min Diff-typ.

Har någon en lösning som kommer att behålla om egenskaper är valfria eller inte på A?

Svar #1

Lösningen var att omdefiniera Minus<A, B> till att vara

type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];

/**
 * Type T without any of the properties on U.
 */
export type Minus<T, U> = Pick<T, Diff<keyof T, keyof U>>;

Vilket korrekt kommer att behålla valfria typer.

Beröm till Daniel Khoroshko för att ha pekat mig i rätt riktning