typescript - Modstridende typer i nogle bestanddele


Jeg prøver at få en metode til at returnere en specifik type afhængigt af en streng, der gives som argument. Dette er, hvad jeg har:

interface Base {
    type: 'a' | 'b';
}

interface MyA extends Base {
    type: 'a';
    nameA: string;
}

interface MyB extends Base {
    type: 'b';
    nameB: string;
}

interface Mappings {
    a: MyA;
    b: MyB;
}

const testMethod = <K extends keyof Mappings>(
    type: K
): Mappings[K][] => {
    const values: Mappings[K][] = [];

    if(type === 'a') {
        values.push({
            type: 'a',
            nameA: 'My name a'
        });
    }
    else if(type === 'b') {
        values.push({
            type: 'b',
            nameA: 'My name b'
        });
    }

    return values;
}

Så hvis jeg kører testMethod('a') ville det have en returtype på MyA[] og når jeg bruger testMethod('b') ville det returnere MyB[]. Men uanset hvad jeg gør, kan jeg ikke få det til at fungere. Fejlene er altid:

Argument af typen 'MyA' kan ikke tildeles parameteren af typen 'Mappings[K]'. Typen 'MyA' kan ikke tildeles typen 'never'. Snittet 'MyA & MyB' blev reduceret til 'never', fordi egenskaben 'type' har modstridende typer i nogle bestanddele.

Jeg troede, at arrayet kunne være problemet, men at returnere en variabel af typen Mappings[K] har det samme problem. Her er linket til playground. Jeg har gjort noget lignende tidligere som dette for at ændre en funktions argument i henhold til den streng, der gives som argument, men her er jeg helt fortabt.

Enhver vejledning eller TypeScript-ressourcer, jeg kan læse, vil blive værdsat!

Svar #1

Mærkeligt nok virkede dette for mig, så snart jeg specificerede, at Mappings udvidede Record<string, MyA | MyB>. Jeg fjernede den fælles forfader Base, da det ikke syntes at hjælpe.

interface MyA {
    type: 'a';
    nameA: string;
}

interface MyB {
    type: 'b';
    nameB: string;
}

interface Mappings extends Record<string, MyA | MyB> {
    a: MyA;
    b: MyB;
}

// same as above

const arrayOfMyA = testMethod('a');  // typed as MyA[]
const arrayOfMyB = testMethod('b');  // typed as MyB[]

Jeg har ikke en intuitiv forklaring, andet end at en eksplicit union er den eneste måde at overbevise TypeScript om, at 'a' | 'b' (keyof Mappings) udtømmende resulterer i MyA | MyB... på trods af at Mappings[keyof Mappings] korrekt resulterer i MyA | MyB både før og efter ændringen! Dette kan være en TypeScript-fejl, eller i det mindste en mulighed for en forbedring.

type MappingResults = Mappings[keyof Mappings];
// typed as MyA | MyB, regardless of whether
// Mappings extends Record<string, MyA | MyB>!

Legepladslink

Relaterede artikler