typescript - Angi egenskapstype
Er det mulig å sette typen til en egenskap i TypeScript uten å caste den? Vurder denne koden:
interface Overlay {
type: "modal" | "drawer"
other?: number
}
const rec = {
obj1: { type: "modal" },
obj2: { type: "drawer" },
...
}
Objektet rec har typen { obj1: { type: string }, obj2: { type: string } }. Jeg vil at det skal ha typen { obj1: Overlay, obj2: Overlay, ... }.
Mine forsøk:
- Ok - men veldig omstendelig og legger til variabler
const obj1: Overlay = { type: "modal" }
const obj2: Overlay = { type: "drawer" }
const ...
const rec = { obj1, obj2, ... }
- Dårlig - tillater at feil skjules (f.eks.
{} as Overlayvil bli vurdert som ok av TS). Å brukesatisfiesi stedet setter ikke typen, men sjekker den på en per-egenskap basis.
const rec = {
obj1: { type: "modal" } as Overlay,
obj2: { type: "drawer" } as Overlay,
...
}
- Dårlig - mister nøkkeltypeinformasjonen (
"obj1" | "obj2" | ...blirstring)
const rec: Record<string, Overlay> = {
obj1: { type: "modal" },
obj2: { type: "drawer" },
...
}
- Dårlig - mister informasjon om 'other'-egenskapen og setter feilaktig typen til 'type' til enten
"modal"eller"drawer"i stedet for unionstypen
const rec = {
obj1: { type: "modal" },
obj2: { type: "drawer" },
...
} as const
Finnes det en bedre måte å oppnå riktig type enn #1?
Svar #1
Opptak
Du kan bruke Record-typen for dette, slik:
type AcceptedKey = 'obj1' | 'obj2' | 'obj3'
interface Overlay {
type: 'modal' | 'drawer'
other?: number
}
const rec: Record<AcceptedKey, Overlay> = {
obj1: { type: 'modal' },
obj2: { type: 'drawer' },
obj3: { type: 'drawer' },
}
Objekter som sendes til hver egenskap i "Record" må nå samsvare med Overlay-typen. I tillegg må hvert element fra AcceptedKey eksistere som en nøkkel i Record.
Spesifikasjonen til Record er som følger:
/** * Construct a type with a set of properties K of type T */ type Record<K extends keyof any, T> = { [P in K]: T; };
Delvis rekord
Hvis du også vil at AcceptedKey skal brukes som valgfrie nøkler, kan du bruke Partial sammen med Record på denne måten:
const partialRec: Partial<Record<AcceptedKey, Overlay>> = {
obj1: { type: 'modal' },
obj2: { type: 'drawer' },
}
Dette kan være et godt alternativ hvis du har et begrenset og forhåndsbestemt antall nøkler.
Nøkkelformat i stedet for spesifikke nøkler
Hvis du trenger typen til nøkkelen i et format i stedet for konkrete verdier, kan du legge inn en number-type i en string-type slik:
type AcceptedKeyFormat = `obj${number}`
interface Overlay {
type: 'modal' | 'drawer'
other?: number
}
const rec2: Record<AcceptedKeyFormat, Overlay> = {
obj0: { type: 'modal' },
obj1: { type: 'drawer' },
obj999: { type: 'drawer' },
}
Dette betyr også at du ikke trenger å legge til hver nøkkel til typen også. Dette kan være et godt alternativ hvis hver post kan ha forskjellige nøkler.
