This is a pattern I've found incredibly helpful of late. Let's say you have a collection of fruit in a basket. You may make a type for all the possible fruits. 🍐🍍🍈🥭🍒🥝🍇
type Fruit = 'pomegranate' | 'pear' | 'persimmon' | 'guava' | 'jackfruit'
Let's say the basket is represented by an object literal, consisting of key-value pairs, the key being the fruit id.
const fruitBasket = {
1: 'jackfruit',
2: 'guava',
3: 'pomegranate',
4: 'pear',
5: 'guava'
}
Every fruit basket will be different, and random to a degree. They will all contain different amounts of fruit, although we expect the baskets to contain only the fruits outlined in the Fruit
type. To create an interface for the fruit basket, we need to use an index signature in the interface.
type Fruit = 'pomegranate' | 'pear' | 'persimmon' | 'guava' | 'jackfruit'
interface FruitBasket {
[key: number]: Fruit
}
const fruitBasket: FruitBasket = {
//...
}
This way, the fruit basket can have an innumerable amount of fruit items, the keys can all be unique numbers or ids and the fruit will be safely typed.
I find this pattern helpful when needing to type objects or components where they may have a prop or key-value pair where I don't know the key ahead of time.
You could take this a step further, say I don't know exactly what kind of fruit is acceptable, or perhaps there are different iterations of fruit baskets, one for fall, spring, and winter fruits. We can adjust the fruit basket interface to accept a parameter.
type ClassicFruit = 'apple' | 'banana' | 'orange' | 'strawberry'
type TropicalFruit = 'pineapple' | 'mango' | 'papaya' | 'lychee'
interface FruitBasket<T> {
[key: number]: <T>
}
const classicBasket: FruitBasket<ClassicFruit> = {
//...
}
const tropicalBasket: FruitBasket<TropicalFruit> = {
//...
}
This way, we could swap out the specifics of the fruit, depending on the type of basket.
Dive deeper into this in the TS documentation! Happy coding 🤖
Top comments (0)