I have different animals
enum ANIMAL_TYPE {
dog = "dog",
cat = "cat"
}
interface CommonAnimalProps {
animalType: ANIMAL_TYPE
}
interface Dog {
common: CommonAnimalProps
breed: string,
alive: boolean
}
interface Cat {
common: CommonAnimalProps
origin: string,
height: number,
furious: boolean
}
In the future, there will be more of them. I want a dynaic type definition that respresnt the following map (let’s call it AnimalTypeToAnimalMapping
)
{
ANIMAL_TYPE.dog: Dog[],
ANIMAL_TYPE.cat: Cat[],
}
So that whenever there is another animal in ANIMAL_TYPE
, I also get another entry with its corresponding type in AnimalTypeToAnimalMapping
. I have tried this
type AnimalTypeToAnimalMap = {
[K in keyof typeof ANIMAL_TYPE]: { common: { animalType: typeof ANIMAL_TYPE[K] } }
};
export type AnimalsGroupedByAnimalType = {
[K in keyof typeof ANIMAL_TYPE]: AnimalTypeToAnimalMap[typeof ANIMAL_TYPE[K]][]
}
Background: I want to use lodash’es groupBy
function and then iterate through the result like this
const dog1: Dog = {
common: {
animalType: ANIMAL_TYPE.dog
},
breed: "pudel",
alive: true
}
const cat1 = {
common: {
animalType: ANIMAL_TYPE.cat
},
origin: "EG",
height: 20,
furious: false,
}
const variousAnimals = [dog1, cat1];
const [groupedAnimals, setGroupedAnimals] = useState<AnimalsGroupedByAnimalType>(groupBy(variousAnimals, "common.animalType"))
But this gives me
TS2345: Argument of type
Dictionary<(Dog | Cat)[]>
is not assignable to parameter of type AnimalsGroupedByAnimalType | (() => AnimalsGroupedByAnimalType)
Type Dictionary<(Dog | Cat)[]>
is missing the following properties from type AnimalsGroupedByAnimalType: cat, dog
Here is Playground
Why?
0
Your problem is that groupBy
returns Dictionary<T>
, you can see the implementation here.
So when you call groupBy
, you get a Dictionary<(Dog | Cat)[]>
:
groupBy(variousAnimals, "common.animalType"); // Dictionary<(Dog | Cat)[]>
Then when you pass it to useState<AnimalsGroupedByAnimalType>
you will get an error:
const [
groupedAnimals,
setGroupedAnimals
] = useState<AnimalsGroupedByAnimalType>(
groupBy(variousAnimals, "common.animalType") // ERROR
);
This is because the types AnimalsGroupedByAnimalType
and Dictionary<(Dog | Cat)[]>
are not compatible.
import { Dictionary } from 'lodash';
// ...
declare var x: Dictionary<(Dog | Cat)[]>;
declare var y: AnimalsGroupedByAnimalType;
x. // <-- no autocomplete suggestions
y. // <-- suggestions for x.cat and x.dog
Your best option is probably to create a wrapper around groupBy
:
const variousAnimals = [dog1, cat1];
function groupVariousAnimalsBy(path: string): AnimalsGroupedByAnimalType {
return groupBy(variousAnimals, path) as any;
}
const [
groupedAnimals,
setGroupedAnimals
] = useState<AnimalsGroupedByAnimalType>(
groupVariousAnimalsBy("common.animalType") // OK
);