Typescript-grensesnitttype med valgfrie nøkler av forskjellige typer og strictNullChecks
Jeg prøver å lage følgende grensesnitt i TypeScript:
type MoveSpeed = "min" | "road" | "full";
interface Interval {
min?: number,
max?: number
}
interface CreepPlan {
[partName: string] : Interval;
move?: MoveSpeed;
}
Imidlertid er denne syntaksen ugyldig. Kompilatoren sier Property 'move' of type '"min" | "road" | "full" | undefined' is not assignable to string index type 'Interval'..
Jeg bruker kompilatoralternativet strictNullChecks:true, som er grunnen til at undefined er inkludert implisitt for move?-nøkkelen.
Men denne syntaksen er gyldig:
type MoveSpeed = "min" | "road" | "full";
interface Interval {
min?: number,
max?: number
}
interface CreepPlan {
[partName: string] : Interval;
move: MoveSpeed; // 'move' is required
}
Jeg vil uttrykke ideen "CreepPlan består av string:Interval-par, bortsett fra den valgfrie 'move'-nøkkelen som er et string:MoveSpeed-par." Er det mulig å uttrykke dette i TypeScript?
Svar #1
Du uttalte at alle egenskaper på CreepPlan har Interval-typeverdier da du skrev:
interface CreepPlan {
[partName: string] : Interval;
}
dvs., enhver og hver streng-indeks-tilgjengelig egenskap av CreepPlan vil være et Interval. Dette gjelder også for move, siden foo['move'] er det samme som foo.move.
Men når man ser på Interval, er det ingen påkrevd struktur for det:
interface Interval {
min?: number,
max?: number
}
Det er ingen påkrevde felt i den kontrakten, men den krever et objekt. Den vil gjerne akseptere et tomt objekt, men den krever et objekt som kan ha min og max egenskaper.
Din MoveSpeed-type, på den annen side, tillater undefined:
Egenskapen 'move' av typen '"min" | "road" | "full" | undefined' kan ikke tildeles til strengindekstype 'Interval'.
Dermed må Interval være et objekt uten påkrevde egenskaper (noe string lett kan oppfylle), men som ikke tillater undefined, noe MoveSpeed faktisk tillater.
Typene dine er disjunkte, men det er ikke åpenbart før du løser dem ut en eller to ganger.
Svar #2
Som beskrevet i TypeScript-dokumentasjonen, hvis du bruker indekserbare egenskaper, bør alle returtypene til alle de andre egenskapene kunne tilordnes til returtypen til indeksreturtypen. Det er fordi foo['bar'] og foo.bar er det samme.
Så hvorfor fungerer dette?
interface CreepPlan {
[partName: string]: Interval;
move: MoveSpeed;
}
Fordi enhver MoveSpeed er en gyldig Interval-verdi (det er et intervall med udefinert både min/max).
Hvorfor fungerer ikke dette?
interface CreepPlan {
[partName: string]: Interval;
move?: MoveSpeed;
}
move? har typen MoveSpeed pluss typen undefined. Hvis den har verdien undefined, kan den ikke tildeles til Interval, så kompilatoren viser korrekt en feil.
Hvordan kan du fikse dette? Gjør ganske enkelt indeksereren til å ha undefined som en gyldig verdi:
interface CreepPlan {
[partName: string]: Interval | undefined;
move?: MoveSpeed;
}
