I'm fairly new to advanced typescripts concepts so bear with me. I have a number of projects that use objects to map out react components by some common prop (e.g _type).
What I want to do is automatically return the correct type for the component resolved using these object maps, however I just receive a type of any
when I try this.
Many posts online recommend using switch statement (example below). Our company uses the object map pattern so I'd like to avoid using the switch statements if possible. Thanks. For added context, this is our first react project using typescript (moving from javascript).
// types
type AnimalType = 'cat' | 'dog'
interface Cat {
_type: AnimalType
name: string
onMeow: () => void
}
interface Dog {
_type: AnimalType
name: string
onBark: () => void
}
type Animal = Cat | Dog
type AnimalMap = {
[property in Animal['_type']]
}
// THIS WORKS BUT WE DON'T WANT TO USE THIS
// resolving animal type via switch
const CatComponent = ({ _type, name, onMeow }: Cat) => <div>I'm a cat!</div>
const DogComponent = ({ _type, name, onBark }: Dog) => <div>I'm a dog!</div>
function resolveAnimal(_type: AnimalType): React.Component<Animal> {
switch(_type) {
case "dog": return DogComponent
case "cat": return CatComponent
}
return animalMap[_type]
}
// THIS DOESN'T WORK, WE'D LOVE TO USE THIS!
// resolving animal type via object map
const animalMap: AnimalMap = {
cat: CatComponent,
dog: DogComponent,
}
function resolveAnimal(_type: AnimalType): React.Component<Animal> {
return animalMap[_type]
}
function App() {
const ResolvedAnimalComponent = resolveAnimal('dog')
return <ResolvedAnimalComponent onBark={() => console.log('HE BARKED')} />
}
CodePudding user response:
Remove the explicit notation of : AnimalMap
so that the object declaration values are not widened - you want TypeScript to see
const animalMap: {
cat: CatComponent,
dog: DogComponent,
}
not
const animalMap: AnimalMap
(not only because your AnimalMap
doesn't note the values - the components - but also because it doesn't tie the properties to their components)
Use
const animalMap = {
cat: CatComponent,
dog: DogComponent,
}
function resolveAnimal<T extends keyof typeof animalMap>(_type: T) {
return animalMap[_type]
}