Skip to main content

Calling Mandatory Getter props

· 12 min read

hilly landscape in the village of simon, brasov Hilly Landscape in the Village of Şimon.

...there's a lot going on with the attributes and the handlers and the ref and the other properties...

Let's assume that we have the following scenario. We have a custom hook that returns getter props, and we want to make sure that those getter props are called correctly. But, first things first:

What is a getter prop?

It's a function that gets returned from the custom hook, which is supposed to be called and its result used for some reason. Let's take the getInputProps getter prop from downshift:

import * as React from 'react'
import {useCombobox} from 'downshift'

const items = ['red', 'green', 'blue']

const {getInputProps} = useCombobox({
items,
})

return (
<div>
<input {...getInputProps()} />
</div>
)

The getInputProps result is an object with properties such as: aria-labelledby, aria-expanded, role, onChange, onClick etc. These properties are going to make our input more or less acting like a combobox. The combobox logic is kept inside the custom hook, the inputs are retrieved through the event handler functions (onClick, onChange) and the combobox related information is passed through the other attributes (aria-labelledby, aria-expanded). Of course, there are many more handlers and properties, but we are keeping it simple for now.

There's also the ref property that is going to be returned from getInputProps, and this is needed in order to allow useCombobox to access the input element and perform some custom .focus() actions when needed.

The Problem

Given that there's a lot going on with the attributes and the handlers and the ref and the other properties, we want to make sure that the getInputProps getter function is called correctly.

  • First of all, we want to make sure that it is called.
  • Secondly, that is called on an <input> element, or in such a way that it has access to an <input> element.
  • Thirdly, in case it is not called correctly, we want to inform the user through a console error and give them enough information to fix the getter function call.
  • Moreover, we also want to show the console error in the development environment, not production. -In addition, we would like to show this error only on the first render, as we believe it's enough in terms of checks and informations.
  • Last, but not least, we will also provide an escape hatch to avoid getting this error if the consumer just cannot call getInputProps properly on the first render.
    • We are going to document this escape hatch and make sure the consumer knows why we are adding it. Ideally, if a consumer will use the escape hatch, they are aware how getInputProps works, how it should be called, and if they, for some reason, cannot call it on first render (using a Portal for example), they will use the escape hatch to avoid the error, but they will test their implementation to make sure that it works as it would by calling getInputProps normally.

The Solution

Inside the getInputProps function we return, we would like to have a mechanism that checks whether the function is called withing the right conditions. We can do so with a function to which we supply the call parameters. This function will be called at render time, since getInputProps is called on render time. The actual check happens after the first render, so we will involve a React.useEffect hook. After a bit of thinking, the solution is actually simple: a custom React hook that will keep call information inside a React ref. This call information will be supplied by a function which we will return from the hook. The returned function will store the call information inside that ref. And inside the effect function, we will perform the check and show the errors if needed.

The Tests

We actually have a good and simple solution in mind, so let's see what do we actually expect from this solution.

  • we want an error displayed when getInputProps is not called.
  • we want an error displayed if getInputProps is not called with a ref pointing to an element.
  • we don't want an error displayed if getInputProps is not called on subsequent renders.
  • we don't want an error displayed if getInputProps is called correctly.
  • we don't want an error displayed if we use the escape hatch provided and getInputProps is not called with a ref pointing to an element.

We will use React Testing Library renderHook and together with Jest, we will set up our tests suite.

describe('non production errors', () => {
beforeAll(() => {
jest.spyOn(console, 'error').mockImplementation(() => {})
})

afterAll(() => {
jest.restoreAllMocks()
})

test('will be displayed if getInputProps is not called', () => {
renderHook(() => {
// we just render the hook, we don't call getInputProps.
useCombobox({items})
})

expect(console.error.mock.calls[0][0]).toMatchInlineSnapshot(
`downshift: You forgot to call the getInputProps getter function on your component / element.`,
)
})

test('will be displayed if element ref is not set and suppressRefError is false', () => {
renderHook(() => {
const {getInputProps} = useCombobox({
items,
})

getInputProps()
})

expect(console.error.mock.calls[0][0]).toMatchInlineSnapshot(
`downshift: The ref prop "ref" from getInputProps was not applied correctly on your element.`,
)
})

test('will not be displayed if getInputProps is not called on subsequent renders', () => {
let firstRender = true
const {rerender} = renderHook(() => {
const {getInputProps} = useCombobox({
items,
})

if (firstRender) {
firstRender = false
getInputProps({}, {suppressRefError: true})
}
})

rerender()

expect(console.error).not.toHaveBeenCalled()
})

test('will not be displayed if called with a correct ref', () => {
// we supply a mock ref function to getInputProps.
const refFn = jest.fn()
const inputNode = {}

renderHook(() => {
const {getInputProps} = useCombobox({
items,
})

// getInputProps returns a ref function which will make the element
// usable both outside and inside useCombobox.
const {ref} = getInputProps({
ref: refFn,
})

// we call the final ref function received with a dummy node.
ref(inputNode)
})

expect(console.error).not.toHaveBeenCalled()
})

test('will not be displayed if element ref is not set and suppressRefError is true', () => {
renderHook(() => {
const {getInputProps} = useCombobox({
items,
})

getInputProps({}, {suppressRefError: true})
})

expect(console.error).not.toHaveBeenCalled()
})
})

The tests are quite self explanatory given our 5 expected use cases. For now, they will obviously fail, and we will consider our job done once we write the implementation and the tests are green.

The Implementation

To recap, the getter prop is called on render, so we would like our check to be performed after the render. We will store the call information inside a React ref, and we will check it using a React useEffect. Since we need our check to be performed in development mode, not production, we will define the custom hook like this:

let useGetterPropsCalledChecker = () => {}

if (process.env.NODE_ENV !== 'production') {
useGetterPropsCalledChecker = () => {
// the actual implementation.
}
}

First and foremost, we would like to set up our ref object that we will use for the check.

if (process.env.NODE_ENV !== 'production') {
useGetterPropsCalledChecker = (...propKeys) => {
const getterPropsCalledRef = useRef(
propKeys.reduce((acc, propKey) => {
acc[propKey] = {}

return acc
}, {}),
)
}
}

And we will call this hook inside useCombobox like this:

useGetterPropsCalledChecker(
'getInputProps',
'getToggleButtonProps',
'getMenuProps',
)

Notice that we will most definitely want the hook to check that other getter props are called correctly as well. We are going to stick to getInputProps here purely for explanatory purposes. Anyway, for each prop key we pass to the hook, we will create an empty object container inside the ref. We add this empty object as we want, during our checking phase, to be able to tell if the getter prop with that prop name was not called. We cannot perform this check if we do not store any initial information about the getter props. What prop keys should we actually check, right?

Next, we want to give the consumer, which is the getter prop function, to be able to store the call information. For that, we will return a function from the hook, which stores this information within the ref.

if (process.env.NODE_ENV !== 'production') {
useGetterPropsCalledChecker = (...propKeys) => {
const getterPropsCalledRef = useRef(
propKeys.reduce((acc, propKey) => {
acc[propKey] = {}

return acc
}, {}),
)
}

const setGetterPropCallInfo = useCallback(
(propKey, suppressRefError, refKey, elementRef) => {
getterPropsCalledRef.current[propKey] = {
suppressRefError,
refKey,
elementRef,
}
},
[],
)

return setGetterPropCallInfo
}

And the usage within getInputProps is going to be something like this:

// this is going to end up on the input element via getInputProps
const inputRef = React.useRef(null)

const getInputProps = useCallback(
({refKey = 'ref', ref, ...rest} = {}, {suppressRefError = false} = {}) => {
setGetterPropCallInfo('getInputProps', suppressRefError, refKey, inputRef)

// rest of the logic

return {
[refKey]: mergeRefsUtil(ref, inputNode => {
inputRef.current = inputNode
}),
// the rest of the attributes and handlers that will end on the input
}
},
)

In case the above ref logic is not clear, it ensures that all ref objects have access to the same input element. We need the input ref in useCombobox. The consumer might also need the input ref for some additional logic, hence the merge of these ref objects and passing the merged object to the <input> element. Also, suppressRefError is the escape hatch we talked about previously.

Now the checking part. We have the initial object created for each getter prop on render phase, when useGetterPropsCalledChecker is called. We have the call information stored when getInputProps is called, also on render phase. Now we have to check if the function is called correctly, on first render only, so we add a React useEffect hook inside our custom hook:

useEffect(() => {
Object.keys(getterPropsCalledRef.current).forEach(propKey => {
const propCallInfo = getterPropsCalledRef.current[propKey]

if (!Object.keys(propCallInfo).length) {
// eslint-disable-next-line no-console
console.error(
`downshift: You forgot to call the ${propKey} getter function on your component / element.`,
)
return
}
})
})

Our first test should pass. If the object is empty, then it means that we did not call the getter prop at all, so we show an error. If the getter prop is actually called, then we need to check if the element exists, which means that the getter prop is called correctly on an element.

useEffect(() => {
Object.keys(getterPropsCalledRef.current).forEach(propKey => {
const propCallInfo = getterPropsCalledRef.current[propKey]

if (!Object.keys(propCallInfo).length) {
// eslint-disable-next-line no-console
console.error(
`downshift: You forgot to call the ${propKey} getter function on your component / element.`,
)
return
}

const {refKey, elementRef} = propCallInfo

if (!elementRef?.current) {
// eslint-disable-next-line no-console
console.error(
`downshift: The ref prop "${refKey}" from ${propKey} was not applied correctly on your element.`,
)
}
})
})

Our second test should now pass. The element check is, sure, not ideal, since we're not checking for an actual HTML input element, but let's say it suffices for now. The fourth test which checks that there is no error logged was passing already, but now with the actual element check, we make sure that, when it's passing, it does so for the right reason.

To fix the second test, we need our hook to be called only once, on first render, so we add [] as the second parameter to useEffect.

And to fix the fifth test, which checks the escape hatch, we will also involve the suppressRefError parameter from the call information. Our final implementation will look like this.

if (process.env.NODE_ENV !== 'production') {
useGetterPropsCalledChecker = (...propKeys) => {
const getterPropsCalledRef = useRef(
propKeys.reduce((acc, propKey) => {
acc[propKey] = {}

return acc
}, {}),
)

useEffect(() => {
Object.keys(getterPropsCalledRef.current).forEach(propKey => {
const propCallInfo = getterPropsCalledRef.current[propKey]

if (!Object.keys(propCallInfo).length) {
// eslint-disable-next-line no-console
console.error(
`downshift: You forgot to call the ${propKey} getter function on your component / element.`,
)
return
}

const {suppressRefError, refKey, elementRef} = propCallInfo

if (suppressRefError) {
return
}

if (!elementRef?.current) {
// eslint-disable-next-line no-console
console.error(
`downshift: The ref prop "${refKey}" from ${propKey} was not applied correctly on your element.`,
)
}
})
}, [])

const setGetterPropCallInfo = useCallback(
(propKey, suppressRefError, refKey, elementRef) => {
getterPropsCalledRef.current[propKey] = {
suppressRefError,
refKey,
elementRef,
}
},
[],
)

return setGetterPropCallInfo
}
}

Recap

Basically, we initialize an empty object for each getter prop we want to check, using the getterPropsCalledRef React ref object. Then we return the setGetterPropCallInfo function that will store information for each getter function when called. Finally, inside the useEffect function, for each getter prop, we get the call info from the ref, we check for an empty object and show the getter function not getting called error. In case we our object in not empty, we get the call information, and do nothing if suppressRefError is true. Otherwise, we check the actual element ref and show an error if it's falsy.

We may go even further with the tests and check if the hook is actually an empty object on production environments, but at this point I'm not sure if it's possible to implement such a test, or if it's even worth it. Bottom line is that, using this custom hook, we are able to perform the function getting called check, or other checks as well, in order to make sure our consumers are doing the right thing and the solution we ship works for them.

Madrid 2024

· 6 min read

parco del rotiro lake View over the lake in Parco del Rotiro.


If you think you know already the meaning of tasteful luxury, visit this place and reset your standards.

Today, damas y caballeros, we stay in beautiful Spain, but this time we leave the sunny South for Mardrid, the capital of football, culture and, well, Spain. It was a long time coming, and I was super excited to start 2024 travelling season with this one. I had high expectations, given the reviews I received from my friends, and, honestly, I was still amazed by what the city had to offer.

Royal Palace and Surroundings

If you like your trips cultural, you're in the right place. We started the trip with the Royal Palace of Madrid, and, Dios mio, what a start. I've seen palaces and museum, and quite plenty, until that point, but the Royal Palace of Madrid exceeded my expectation by far. If you think you know already the meaning of tasteful luxury, visit this place and reset your standards. Every single piece of furniture, tapestry, design and artwork was exactly where it was supposed to be, and the level of detail for every single one of them was incredible, from engravings to finishing touches. They don't let you take pictures inside, and it's really a shame, as it's probably one of the most exquisite places you could feast your eyes upon.

Catedral de la AlmuedaRoom inside Royal Palace of Madrid
catedral de la almudenainside the royal palace of madrid

We left the palace exactly when it was closing time, so there was no more time left to visit the Almueda Cathedral unfortunately, but we did enjoy a very nice walk around Plaza de la Almeria, and took some pictures with Campo del Moro in the background. Quite close to the palace there's the Mercado de San Miguel, which is quite a great place to stop by for an hour or two and enjoy some empanadas and cervejas. Back to the hotel and ready for another day. We stayed at the Room Mate Alba Hotel, which is located in the city center, but in a very quiet area, and the hotel itself is quite nice. Between the Mercado and the hotel we passed through Plaza Mayor, which is another landmark worth checking out, given its surrounding buildings, coffee shops and vibrant atmosphere.

Prado Museum, El Rotiro Park, Food and Coffee

Prado Museum is probably a must go if you're going to Madrid, and for good reason, since it boasts such a vast collection of art pieces from artists such as Francisco Goya and Diego Velazquez. You could spend a few days here without a doubt, but we also had some other places in mind so we were happy to be done in just a few hours. Outside, there's the beautiful park El Retiro, with its signature pond decorated with the colonnades of the Alfonso XII monument. It was a great walk to bask in the sun and forget that it's the middle of January for a few hours. Right next to the park there's also the botanical garden, which would have been a better pick in any other season, but we still enjoyed the impressive collection of bonsai trees.

Monument of Alfonso XIIMadrid Street at Dusk
monument of alfonso xiistreet in madrid at dusk

After leaving the botanical garden we went for a stroll through the upscale Goya neighbourhood. It's nice over here. All buildings are very, very well maintained, and they are simply beautiful and elegant. The city is just amazing, I don't think I encountered anything that was either bad or at least "could be better". Maybe the coffee was not as great as in other places, but there were some coffee shops that were quite good, for instance the Norah Coffee & Brunch in Goya. Don't forget to try the sweets. Another great option is Pascal Specialty Coffee & Brunch, which was closer to the hotel, and features a brunch selection more on the healthy side. If the coffee could have been better, the food was actually amazing. Spain has great food, without a doubt, and other places we could recommend in Madrid are Los Porfiados, for a cozy dinner, or Fiaschetteria La Saletta, if you crave Italian. Other coffee options worth mentioning are Alchemy and Dale.

Santiago Bernabeu, Sorolla Museum and Gran Via

I'm not much into football, but when I watch it's most probably a Real Madrid game, either in La Liga or Champions League. Visiting the Santiago Bernabeu was something I really wanted to do, especially now with the updates it received. From the outside it's quite a piece of art, I love the facade with its gray shiny blades. On the inside, well, it's huge there are lots of big screens everywhere and a retractable roof, letting you know that it's proudly representing the 21st century. We could not enter the locker rooms, which was quite a shame, but at least we saw the hall of trophies, and there are a lot of them. This team knows what winning is about.

Santiago Bernabeu StadiumGran Via
santiago bernabeu stadiumgran via view at night

After we left the stadium we went back towards the city center by foot and we stopped at the Sorolla Museum on the way. It's actually the former house and studio of Joaquin Sorolla, who travelled throughout Spain in order to create a considerable collection of paintings. The art pieces inside the museum are organised in a timeline manner, so we could follow along his interests and favorite places as he aged, from his home city of Valencia, to the Spanish countryside and the capital of Madrid, where he was very passionate about his garden. The garden itself is a great place to relax on a bench, looking at the pond and enjoying the shade of the trees.

Sorolla Museum GardenSorolla Museum Interior
sorolla museum gardensorolla museum interior

The last but not least landmark I would like to mention is the Gran Via, and I would not miss it especially during the night, when I believe it really shines. Both the buildings, the landmarks and the street itself are spoiled by huge amount of light and it's a great way to end the day with a stroll to the shops and just enjyoing the vibrant heart of this otherwise amazing city. It's trully a great city, and probably one of my favorites so far. It's amazingly beautiful, it does not seem to be that crowded, the people are friendly, the food is great, the weather is pleasant and there are so many things to do. I would definitely come back here one day, definitely on a Real Madrid match day. Looking forward, hasta luego!

Malaga 2023

· 8 min read

view of Malaga from the Miradon de Gibralfaro View of Malaga from the Mirador de Gibralfaro.


Truth be told, I don't mind palm trees with Christmas lights. I could live with that.

Finally, the South of Spain. It took a while to get here, but here we are. It's December, sure, but not in Malaga though. Good thing I brought a couple of T-shirts, otherwise it would have been a tough time. Christmas decorations while the weather's so good is just out of this world. Truth be told, I don't mind palm trees with Christmas lights. I could live with that.

So far so good. It turned out that going to Malaga at the beginning of December is a great idea. That was the good part. The bad part was that also half of Spain thought it was a good idea, and the place was packed with visitors. I believe they also had a day off during the week we chose to visit, and everyone took advantage of it. Our apartment was in the center (Be Mate Malaga Centro, great place, check it out) and we had to park somewhere, but, really, there was absolutely no place to park a bicycle, yet alone a car. We finally found a payed multi level car park nearby, barely. Inside it, we found an empty spot on the last floor. Lucky us.

Malaga by Day

I believed that using a rental car was the way to go, since we planned to visit at least some other town besides Malaga, but we did not leave the city eventually. However, the car was cheap to hire, and since I used it only to drive from the airport and back, I did not even bother to refuel. Anyway, we got to our apartment, super nice, way above what we got in Naples or Catania. Yes, it was a touch more expensive, but we got a lot for our money. Totally recommend the place, it was spacious, modernly furnished, right in the city center, but in a very quiet area.

Now the city itself. The historical city center is, I would say, a pretty standard Spanish city, and that's a very good thing. It's clean, it's very well maintained, the buildings are superb, and the amount of restaurants and coffee shops is insane. Spain does not offer the best coffee in the world, not even in the specialty coffee shops. It's not bad, by any means, but certainly not the best. On the other hand, the food, well, that's something else. From the standard brunch toasts, Benedicts and avocados to the seafood, meats and deserts, the food in Spain is just glorious. I think Portugal still tops it up, but Spain is definitely top 3 in my book. Definitely check out Next Level Specialty coffee, and you must, absolutely must, get the French Toast: toasted bread with cream, bananas, strawberries, blueberries and honey. Combined: magic.

Walkway to AlcazabaCatedral de la Encarnacion
walkway to alcazabacatedral de la encarnacion

Obviously, there are some sights to absolutely deserve a visit. But just walking through the city center is pleasant enough, while going to the stores, getting ice cream, the usual stuff. As we strolled around, we got to the Catedral de la Encarnacion, which is Malaga's main church, and it's imposing both on the outside and on the inside. Definitely worth paying for the entrance. From there, the Alcazaba is just at "a stick throw" distance, and it's the main atraction of the city. For good reason, to be sure. The castle itself is very well preserved, and they are obviously very proud of their monument. And walking through the courtyards is a great experience, especially because of the many beautiful gardens and beautiful architecture. And, of course, the views over Malaga are simply gorgeous.

Right next to the Alcazaba there's the Gibralfaro Castle, and since we visited Alcazaba, we might as well do both simultaneously. Gibralfaro is not as special as the Alcazaba, but it has better views, especially from the Mirador de Gibralfaro. We could not see the Malagueta from there, due to the buildings around the Plaza de Toros. But we did, of course, enjoyed a great view over the stadium for the bullfighting shows.

Gibralfaro view to MalaguetaAlcazaba view to Malagueta
gibralfaro view to malaguetaalcazaba view to malagueta

Another point of interest is the Malaga Museum, which definitely has a lot to offer. I found the painints from Moreno Villa particularly interesting, and there should be enough art for everybody. Actually, I think the Spanish museums are the best I visited so far, so if art is your thing, make Spain your priority. I enjoyed museums not only in Malaga, but also Barcelona, Madrid and Zaragoza. One thing that's actually a bit not so great is the fact that, when it's 15 minutes to closing time, they smiply kick you out, without any sign of politeness. It happened to us in Malaga and also in Madrid, and the fact that they insist for you to leave is just, well, not great. On the bright side though, once you exit the Malaga museum, there's a very nice terrace with palm trees that screams Instagram and Vice City, so we definitely took a few pics with the palm trees at dusk.

Malaga by night

Remember the part when I mentioned half of Spain was in Malaga for the weekend? That was not immediately obvious by day, save for the parking situation. However, by night, it was a completely different story. The whole city center, from the Plaza del Constitution, all the way down the Marques de Larios and towards Malaga park, including it, was so crowded it was just impossible to move. It was quite scary at times since I was not used to these kinds of crowds, but apparently, in Spain, it's completely normal. Nobody was even remotely mad about the whole thing.

Every person in the crowd was happy, everyone was singing, there was a smile on each and everybody's face, and I realised just how happy people are over there. In lived in Bucharest and Prague all my life, and I am mostly used to seeing gloomy faces that were quick to snap and constantly one small second away from getting angry. And it felt good to see happiness, just randomly manifesting itself on the street.

Marques de Larios with Christmas DecorationsHistorical Center Building
marques de larios with christmas decorationshistorical center building in malaga

Probably the holiday also helped to create all this joie de vivre, and we were lucky enough to be in the city center when they blasted music through the speakers, along with a light show using the Christmas decorations. Everyone, obviously, knew the songs, so they were singing along. It was absolutely amazing, probably one of the best feelings I had for a moment, and I will always remember Malaga for that show and for how it made me feel.

One evening we also met with a couple of friends who happened to be around Malaga at that time, and we went for a walk towards the Malagueta and then back to the city center, where we went to a ramen place. I'm not a fan of the soup, but luckily they also served sushi, so it worked out well for me as well.

Since I am also watching games in La Liga from time to time, I know that Malaga has a very famous football team. Consequently, I could not leave before going for a walk to the La Rosaleda stadium. Sadly, it was already dark outside, and could not see much of the stadium, and since it was already evening, visiting it on the outside was not possible either. It did not seem to be as grand as the Bernabeu or the New Camp, but I was happy to see it anyway, as I'm also a fan of its name, La Rosaleda.

Wrapping up

It was a very short trip, and I'm quite OK with the fact that we did not go other places we planned to, like the Caminito del Rey or Granada, but this leaves us with the opportunity to go back and make up for it. And, most probably, I will be back in Spain multiple times from now on, given its rich history, great Western architecture and Moorish influences, incredible museums, incredible food and good enough coffee. Next on the list was, obviously, Madrid, for a strong 2024 start in the travelling department.

Catania 2023

· 5 min read

view of Etna from the ancient theater in taormina View of Etna from the Ancient Theatre in Taormina.


The food was delicious, from the Tagliere di Salumi e Formaggi to the Pesce Spada a Siciliana.

I had Sicily in mind for some time, and going to Catania was definitely something I looked forward to. Initially, Palermo was the preferred destination, until I realised I bought the tickets for Naples instead. Anyway, Catania was supposed to be better as it was closer to Etna and Taormina, so off we went to this place full of history. And cannoli.

Catania

After arriving at the airport and getting into the car, I realised that I'm about to drive in Siciliy and that came a bit scary. Oh, and the parking. Bad move. However, after leaving the airport and arriving into town, I realised it's actually pretty straightforward. People are actually quite nice, since I did not know the way and struggled at times. If I was doing the same in Bucharest, outward chaos whould have ensued. Parking was a bit of a hassle, due to the limited space, but once we found a spot, we payed at a nearby parking meter and went on with our business. Quite nice.

The apartment was near the Teatro Massimo Bellini, a very popular and charismatic place with a plaza in front. Apparently, we stayed in (or near, I did not quite understand) a building that was built by Mussolini. Yeaaah. Anyway, it was close to the center, where we could stroll on the Via Etnea and explore the shops and restaurants, and there were quite a few of them. The place was quite popular all day long, and we enjoyed the very lively atmosphere, as well as the nearby monuments of Sant'Agata church, University Square and the Elephant Fountain.

Basilica Cattedrale di Sant'AgataTeatro Massimo Bellini
basilica cattedrale din sant&#39;agatateatro massimo bellini

Near the Etnea we found a very good (quite excelent, actually) restaurant, Deliziosa, and we enjoyed it so much we went there twice. The food was delicious, from the Tagliere di Salumi e Formaggi to the Pesce Spada a Siciliana. Again, most excelent, would totally return. Also near the center is the fish market, and it's exactly what you would expect from a good ol' Sicilian market. If you're into fried fish, make sure to check out Scirocco. If you're into a coffee spot with a quite charming host that does magic tricks, go to Ciao. I must say, overall, the whole experience was pretty unique.

We also walked away from the center a few times, but the sights were not as impressive. Sure, the city does have its charm, and there's no denying that it has rich history and charm, but it does feel that it needs a little more maintenance. And it's such a shame, given the city's potential. We walked towards the waterfront then through San Cristoforo all the way to the Porta Garibaldi, and although it was a relaxing walk, there was nothing much to see. Also, towards the north, the Piazza Carlo Alberto di Savoia is, again, not the best of sights. We had a pretty standard Italian coffee at a nearby coffee shop, ate a brioche and went back towards San Berillo.

Taormina and Aci Trezza

The weather proved to be better than expected, so we took the car one day for a trip to Taormina, which was top of the go-to list. Once there, we parked and went into town, and again, even though the place was undenyingly beautiful, it felt that that it was not as great as we had hoped. Maybe the fact that we went there in November did not help either, and many places and restaurants were closed. We did find the Ancient Theatre open, and it was a great sight to see the Etna from this impressive monument built by the ancient Greeks. The weather was sunny and we were lucky to see the wonderful volcano in the distance very clearly. And it was incredible, I could've stared at it forever. The trip was totally worth it, even though we could not find much to do in the town itself.

Taormina BuildingAci Trezza
taormina buildingaci trezza

Consequently, we went back in the car and drove towards Catania, only to stop on the way in Aci Trezza, a small town on the beach. We went for a walk on the waterfront, enjoyed the town'n port and took pictures of the Cyclops. Unfortunately, apart from this, there was nothing else to do, so we turned back and drove all the way to Catania airport.

Wrapping up

I'm going back to Sicily for sure, and will try to visit Palermo and the surroundings next time, maybe even Syracuse, given its rich ancient history. I did like the trip, for sure, although it was not my favorite out of 2023. Maybe the Palermo option will be different, let's see, there's only one way to find out.

My 2023 in Review

· 11 min read

silviu hiking in the baiului mountains View over the Baiului Mountains.

I've learned to do the Corpse Reviver #2 and the Paloma.

I plan to write each of my year in review articles at the end of December. This one lands at the end of February, so things are not really going as planned so far. To be honest, during the whole year I felt that I've pushed many deadlines, and at times it felt quite overwhelming, but, looking back, my 2023 was not as bad as I thought it would be. Motivation was low throughout the year, sure, but consistency did help quite a lot, and I'm thankful for the habits that helped me decisively.

Goals for 2023

In my 2022 year in review, I set a list of goals for myself, and I am curious how many did I manage to accomplish. Let's start this article with a disappointment, shall we?

  • update Downshift to v8

    Actually, we're at v8.3.1 and, even though we still have some important things to fix, we are React 18 compatible, we support fully the ARIA 1.2 pattern, we have TS type support for the getter props (a long time coming) and overall API improvements. Actually, I'm not very mad with the current of the library.

  • finish Marcy's course and 2 more Frontend Masters web development courses.

    The biggest fail for 2023 was in fact the learning aspect. I did not finish Marcy's course, I still have a lot to go, and, obviously, the Frontend Masters courses were out of reach.

  • read at least 10 books, starting with Don Quixote.

    I fell short of the number 10, but not by far, and the books I've read were actually quite impressive. More on that later.

  • improve to 3 times per week gym schedule.

    Done. Big win. Not that big gains, but still fine.

  • attend at least one dancing congress.

    I am going to my first salsa congress in Brasov at the end of January, so let's consider it done.

  • visit the south of Spain and New York.

    2023 main achievement was travelling, and yes, I did check Spain and New York, among many others. More on that, later.

  • revive the Tab Order Testing library I worked at in Adobe.

    I reviewed the current state of the art in Microsoft and decided that the library is not going to be useful anymore.

Overall, not half bad. Yes, motivation was not my gratest 2023 asset, but it wasn't motivation that helped me achieve my initial 2023 plans, or the things I achieved on top of them. It was consistency, it was habit. Motivation comes and goes. Habit is there once it's built. I heard about it in most motivational content, and 2023 helped me actually understand why it is so valuable.

Coding Stuff

I've enjoyed quite a successful year at Microsoft, and so far I'm quite happy with the projects I'm contributing to. Microsoft Teams is a very used product, and even though it does have its reputation, it's packed with features and it became better through the years, and I'm happy to contribute to that effort. My favorite part was the March hackathon when I successfully presented my project to the leadership, which got very favorable reviews and we might even see it one day fully implemented in Teams. Super excited about that.

Apart from my normal job, I also continued to code for open source, and updated Downshift to include React 18 and ARIA 1.2 pattern support, among many other fixes. What I'm also proud about is that I continued to write on this blog, and not just tech related articles, but also from my trips, and everything is coming along nicely. Oh, and I also achieved something quite big in the work department, but, at least for now, it's classified.

Hobbies

Quite a few updates here as well. I've started to go 3 times a week to the gym, and it feels so good. I've also resumed basketball once per week and also running, even though it became mostly a once per week event as well. Overall, I'm quite satisfied with my current active shape, and I look forward too keeping it. I only wish that I've been more times on hiking trails, as 2023 was not my best, so I hope to improve the hiking frequency in 2024.

A big change for me was giving up bachata classes, but, on the flip side, I continued my salsa classes, and I'm having a blast. I'm super happy at my current dance school and I feel that I'm improving. To top it off, I went to my first salsa congress in Brasov in January 2024 and, even though I dislike staying awake at night, doing only that while not doing anything else during the day is, let's say, manageable. The congress itself was super fun, I feel like going again next year.

Algarve Beach HikingGuns 'N Roses Concert
selfie over a beach in algarve while hikingguns &#39;n roses concert view from the stage

Another event worth mentioning for me was the Guns 'N Roses concert from July at the Arena Nationala. I was lucky to receive tickets for the concert and wow, what a show. It was an incredible experience, and a top notch performance from the band. I won't forget it anythime soon. Even though the sound from their microphones was annoyingly cut out many times, the event was unlike anything else.

Oh, and did I mention that my banana bread is probably the best in the world? I perfected my technique quite a bit. Also, I added the lemon and like cakes to my portfolio, so the coffee shop does not sound like a bad idea at all. Oh, and cocktails! I've learned to do the Corpse Reviver #2 and the Paloma.

Books

I aimed to read at least 10 books during 2023, and I fell short of that number, but not by far. Here's my list:

  1. Don Quixote, Miguel de Cervantes. I had so much fun reading this, even though it was quite a long book. It wasn't only fun, but a great insight into human nature, idealism, and reality versus imagination. The other stories inside the book are fun as well, especially the one with the husband that used his friend to check on his wife's loyalty.
  2. The Little Prince, Antoine Saint-Exupery. This tiny book is a great opener into subjects such as human relationships, love and innocence.
  3. Augustus, Adrian Goldsworthy. I'm a sucker for ancient history and I've previously read Caesar from the same author. Augustus did not disappoint, as it tells the story of Octavian, with his early blunders and not so many achievements, as he took advantage of his situation in the context of the late Roman Republic and became the de facto ruler of the Roman world.
  4. Lord of the Flies, William Golding. As with 1984, it reminds us of what human nature really is when left unchecked.
  5. Myth of Sysyphus, Albert Camus. I'll be honest, I got nothing here.
  6. Invisible Man, Ralph Ellison. I've enjoyed this one quite a lot, as the narrator grappled with racism, injustice and political manipulation as he endlessly searches for his personal identity.
  7. The Richest Man in Babylon, George S. Clason. It was a very useful read to refresh my own ideas related to wealth and budgeting.
  8. Jane Eyre, Charlotte Brontë. A very refreshing book, as it goes beyond the love story into feminism, the search for identity and social justice.

So, not really 10 books, but not very far off. My favorite was probably Jane Eyre, given the main character's complex journey and the very deep insight of her thoughts. The Invisible Man was not very far off.

Travelling

If there was a personal highlight of 2023, travelling would have been that one. I love travelling, but 2023 was on a whole different level for me, and, to be honest, it felt really good. I enjoy spending both a few days in a different place, as well as a full 2 week vacation far from home. It helps me clear my thoughts, re-energise and even become more creative within my daily work. I only wish 2024 to be quite similar in this regard. Here it goes, the list of all the places I've been to:

  • Prague, January. It "happened" for me to be in Prague for Microsoft's Winter Party. What a coincidence.
  • Perugia, March. One of those random destinations you pick because plane tickets are cheap, and it proved to be a very good idea. The biking along the Lago Trasimeno was the highlight, for sure.
  • New York & Seattle, April. Best vacation for a while, maybe the best ever. I now have a new favorite city and can't wait to go back there. Seattle is also great, given its laid back atmosphere, greenery and nearby hiking spots.
  • Oslo, April. Another random destination, can't wait to go back to Norway for a more hiking & nature oriented experience. Oslo was quite nice as well, and it has great museums too.
  • Prague, June. Business trip with a little bit of fun. The biking trip to Karlstejn was, well, quite something.
  • Malta, August. It was so hot, but everything else was great. Can't wait to go back to the island, it's full of fun stuff to do. Need to book that Katamaran experience in advance, though.
  • Naples & the Amalfi Coast, September. Naples is a great city to visit, as it has a quite strong personality. Also, the beauty of the Amalfi Coast is unrivaled. Can't wait to go back there again, as Capri and Amalfi are next on the list.
  • Prague, October. Yeah, it's my favorite place to visit. This time there was no hardcode bike trip, just coffee, food and walks. And I finally went to visit the Prague Castle.
  • Lisbon & Algarve, November. The other long 2 week trip, and what a trip it was. Everything was perfect, I hiked on the sea shore, I climbed on top of castles, I rested on the beach surrounded by dramatic cliffs. I also missed Web Summit this year, but really, whatever. I made the most out of it. Oh, and that entrecote, oh my.
  • Catania, November. Maybe my hopes for this one were quite high, and it was maybe a bit disappointing, but I would still return to Sicily, maybe in the spring is better.
  • Malaga, December. I'm going to return to the south of Spain, for sure. This place is marvellous, the weather is incredible, the people are smiling, and I loved it.
Central Park Selfie
selfie in central park with horia

11 trips in total. Not bad. I want more. More is better.

Goals for 2024

Let's see.

  • Finish the A11y course and do 2 more courses on Frontend Masters. Same as last year, but I'll actually do it.
  • Read at least 10 books. Again, same as last year.
  • Go on a trip to Asia. Anything really, Japan, China, Thailand. All three. I don't care, but I want to go there.
  • Bump Downshift to v9. We do have in plan some API changes, apart from the fixes we want to implement.
  • Cook 3 new recipes.
  • Hike at least 6 times. Once every couple of months. Should not be too difficult.
  • Make a big move. It has been quite some time since I did not do anything radical, ever since I came back from Prague in 2020. I feel that it's time I changed something dramatically about myself.
  • Start doing yoga.

Lagos & Lisbon 2023

· 19 min read

praia de vale figueiras at sunset Praia de Vale Figueiras at sunset.


I deserved the pizza for dinner that evening.

Portugal in November has already become a tradition for me. It's the third time in a row when my friend and I use the Lisbon Web Summit as an excuse to go surfing in Lagos, visit Lisbon and its surroundings, and just enjoy everything that the south of Portugal has to offer. This year was no exception, and we had a blast of a time spanning a couple of weeks, full of surfing, visiting, hiking and just laying on the beach. Are we going to continue the tradition in 2024? Probably.

Lagos Surfing

This is the main spot where we spent most of our two weeks, in the middle of the Algarve, one of the most beautiful areas I've ever seen, with spectacular scenery, eye candy beaches, the best food in the world (sorry Italy) and great weather. My priorities were, of course, surfing, hiking on the Fisherman Trail, eating the best pancakes in the world and reading on the beach. Not necessarily in that order.

This year, as in previous years, we chose the Surf Academy surf school for our surfing sessions during the weekends. They are great and provide a convenient way to organise the surf sessions, as they will know pretty well which beach to choose during each day. They also know which spot on the beach is better to catch waves, and during which times the tide is the best. I, for one, don't have such expertise, and apparently neither does my friend, as we both found out when we went one day on the beach on our own. It was terrible, we caught nothing, except huge waves straight to the face. Never again.

Since it was already mid November, we avoided the West Coast beaches, as the waves there were pretty huge. The surf school chose a couple of beaches in Lagos, Porto Mos and Meia Praia, where the weaves were a bit more calm and you could actually surf. I did catch quite a few green waves, and I think I improved my technique overall, so next year I actually look forward to be able to also steer on the wave, not just go straight on to the beach. Fingers crossed!

The West Coast

Praia de Vale Figueiras View
view over the praia de value fugueiras

If you're not drinking, then you're not playing. It's my favorite place in the Algarve. The beaches there are just out of this world. We went one evening the Vale Figueiras Beach, and we reached it during the sunset. Wow. Just wow. The lightning was perfect to take the best shots, and I took quite a few. First of all, the ocean put on quite a show for us, the spectators with the jaws dropped. It's probably one of the most relaxing experiences to gaze at the neverending lines of waves, and each and every one of them performing right down the beach. The sleepy sun rays made everything even more spectacular, and even the seagulls seemed to participate in the whole ocean choreography. It was perfect, probably one of the best experiences of my life.

Praia de Vale Figueiras Rocky HillsView towards the Atlantic from the top of the hill
rocky hills next to the praia de vale figueirasview towards the atlantic from the top of the hill on the praia de vale figueiras

Another great beach is Praia da Arrifana, and this one was more surfing friendly, as when we got there it was quite full of people, most of them with surf boards. However, the beach is quite huge, so I did not feel crowded or anything. On the hill overlooking the beach there's a small town where we had lunch and coffee, at the Sea You Surf Café, and the whole experience was complete. My friend tried to catch a few waves there, but without much success. I settled just for some beach time and a few pictures on the left end of the beach, where I found a spectacular terrain with rock formations raising up from the shallow waters. It was time for some pictures.

Praia da Arrifana Rock FormationsPraia da Arrifana Steep and Rocky Hills
rock formations on the praia da arrifanasteep and rocky hills over praia da arrifana

Trilho dos Pescadores

The Fisherman's Trail was one of my main objectives for the trip. It's quite a long hiking trail on the West and South coasts, starting at Praia de São Torpes and ending in Lagos. It consists of 226,5 km of trail that takes you through breathtakin scenery on the Atlantic Ocean's coast. Theoretically, you need quite a few days to do it all, maybe 12-15, and pick accomodation in the towns along the way. It does not sound easy, even if it's not taking you through the high mountains, but next to the sea instead. I wasn't planning to go from start to finish, I'm not there yet, but instead I planned to hike specific parts of it, starting backwards from Lagos, march as much as I could until I ran out of daylight, and call my friend to pick me up with the car.

Ponta da Piedade near LagosPraia da Luz from near Rocha Negra
rock formations on the ponta da piedade near lagospraia da luz seen from the hill with rocha negra

I did a couple of such trips by myself, and it was refreshing. Just being on the trail with only a small backpack full of water, sandwiches, sunscreen and oat biscuits is both exciting and relaxing at the same time. My first trip started in Lagos and I managed to go all the way to Praia da Boca do Rio, even though I was hoping to reach the town of Salema. Unfortunately I ran out of sun, and I was quite exhausted, so I called it a day just before the city. It's interesting that this whole trip involves different types of scenery, and no two parts of the hike were the same. I enjoyed steep cliffs and grottos from Lagos to Porto Mos and quite arid cliffs up until Praia da Luz. Starting from Luz and all the way to Burgau, the terrain is still quite arid, but I was delighted to see some beautiful gulfs, and it was quite something to just sit on top of the hills and rest while the ocean was throwing its waves towards the land, over and over.

Gulf near Praia da ZoraUphill view of a climb near Praia das Furnas
a gulf near praia da zorauphill view of the climb near praia das furnas

I arrived in Burgau, a very nice town which reminded me of a typical Greek town on the sea, with similar white houses that exuded the salty air of vacation, surrounded by palm trees and paperflower vines. After exiting Burgau, the trail tood me through a field of cacti, and it was pleasant for me to see them out in the wild, as I also have quite a few at home. This part of the trail was my favorite, since it had more greenery and a few spots of forest. It also helped that, being near the end of my trail, the sun was setting and the light became perfect. However, it's also the time I realised that I need to finish the trail or at least go to some place where I could call my friend to pick me up, as ending on the trail during the night, without proper equipment was no joke. So I raced to the finish line, which was the town of Salema, but it was really too late, so I settled for Praia da Boca do Rio and called it a hike. I deserved the pizza for dinner that evening.

Praia das FurnasGulf near Zavial
praia das furnas with an art piece made of rocksgulf near zavial
Gulf near ZavialCactii in the wild near Burgau
gulf near zavialcactii in the wild near burgau

A few days later it was time for part two, so I took the bus that left me in the middle of some road, and I walked from there to Salema and resumed the trail. The plan was to go all the way to Sagres, but I arrived simply too late to start the hike and I was unable to reach it. On the flip side, I did arrive to some great beaches that were absolutely fantastic to look at. The trail also became even better for my taste, as it was even greener and I started to also go through forests and shrubbery. Praia da Figueira was quite a sight, and afterwards the trail had to exit the seaside to go through some countryside instead. Quite an interesting change of scenery, I liked it. After that part of the trail I ended on the Praia das Furnas, and I had the chance to enjoy some art as well. There are some circles made of stone, overlooking a grotto, and the whole scene is picture perfect. Back on the trail and the scenery simply just did not stop amazing me. The highlight was Praia do Zavial, and I had to make a couple of stops to gave upon it, on each of its ends. The lines of waves were pefect, hence the number of surfers in the water.

Praia do ZavialUphill trail near Praia do Zavial
praia do zavial with surfers in the distanceuphill trail near praia do zavial

After the beach, I went back on the trail and I started to feel the overall exhaustion. I started to realise I was not going to reach Sagres, so I just admitted the fact and did not hurry up the pace, as I was content with the experience up until that point. Nevertheless, I found more spectacular gulfs, like the Forte e Bateria do Zavial, and more beautiful beaches like the Praia da Ingrina, where I raised the white flag and stopped for good. It was enough hiking for one trip, and I enjoyed every bit of it.

Sky seemed to be on fire at sunset, near Praia da Ingrina
beautiful sunset near praia da ingrina

Lisbon

My friend, we meet again. There are some feelings in this wonderful city that are simply unique in the world. Driving on the Vasco da Gama bridge is one of them. Climbing to one of the many view ponints, or miraduros, and enjoying the view of the bay is another. With some pasteis de nata, it's even better. But the best feeling is enjoying them on the spot, with a dash of cinnamon. You can confortably skip the coffee, save it for later. It so happens that each time I'm in Lisbon I discover completely new things about it, and that makes me want to return again and again. This time, for instance, I used the bay area for jogging and it was a breeze. Dad joke out of the way, checked.

Since our apartment was located near the Pantheon, my walks were focused in that area, even though, this time, I did not spend as much time in Lisbon as I din previously. The Pantheon area might seem a bit strange, but it has one of the best places to eat in the city. Hear me out. I tried a couple of local, no fuss restaurants, and the food was delicious. When in Lisbon, always go for seafood and fish. I ordered octopus, shrimp and tuna steak, and all of them were fabulous. These couple of places I tried are called O Tasco do Vigário and A Parreirinha do Paraíso. The people were super friendly and I was treated really well.

Lisbon PantheonLisbon alley
the pantheon in lisbonan alley in lisbon

However, the cherry on top was actually nothing related to fish or seafood. When in Lisbon, you must, and believe me, you must go to Affair Restaurante & Bar and get the entrecôte. I never had one in my life, at least not a full one, I am not a fan of beef or fat. But this one, oh my Lord. It was pudding of magic in the mouth. A-ma-zing. The other things I ordered were really good as well. You must try this restaurant when you visit Lisbon, otherwise the trip is a waste.

Equally great about the neighbourhood were the brunch spots, and my favorite was Augusto Lisboa. Not that much to choose from, but everything was spot on. And the coffee, equally perfect. Try the iced latte. Thank me later. Quase Café is also nice, but not nearly as good. You'll figure this out when you'll see the queue.

Now, I did mention that I did not spend too much time in Lisbon this time. That's because I chose to visit a couple of towns near Lisbon that are equally famous and everyone recommended them to me previously: Sintra and Cascais.

Sintra

Picture this. You are a noble. You have tons of money, lots of style, blue blood and you like castles. You also like going to the beach, get a tan, enjoy the waves. But you also like hiking through forests, maybe go hunting from time to time. You don't want your castle to be isolated either, you also want to go out from time to time, greet the crowds and whatnot. And you want some place to have all of this possible. Welcome to Sintra. It's a hilly landscape, surrounded by trees, 15km from the Atlantic Ocean. And it has, you guessed it, a lot of castles.

Fortunately, getting to Sintra is super easy. You just get the train from Rossio station, and it's a nice ride that lasts less than an hour. Once I got there myself, I quickly understood why it was such a popular place. It's gorgeaus. The town itself is not very big, but it's cosy, with stylishly decorated houses on curvy streets that hug the hills full of forests. The bad news is that the nobles who commissioned the castled did so on the very hilltops. And the train station is at the base of Sintra, so you kind of need to go up and climb a lot. Of course, there's the option of taking a cab.

The Park in Sintra on the way to the castlesThe forest surrounding the Sintra Castles
the park part of the way to the castles in sintrathe forest surrounding the castles in singra

But there's no fun in that, so I grabbed a bottle of water and went for the climb. The first part was the trickiest, since it involved trying to correctly pick the streets in town. I believe at some point the road went straight through a bar. I'm not even joking. But at some point I made a left and I was out of the normal roads and on the actual trail. This first part of the hike was very beautiful, as it went through a botanical garden, and I love them botanical gardens. Sadly, I could not enjoy the place that much, as I had to reach the castles as well, so I went further on the trail and took pictures for later. After a while, the park ended and I found myself in the forest. The trail was still there, but now the landscape turned out to be more natural, and it was equally satisfying. Imagine hiking through the woods, and from time to time you encounter a view point, where there's a clearing, and seeing the castles of Sintra in the distance. Quite a unique experience, if you ask me.

I reached the first of the two main objectives of the day, the Castelo dos Mouros. It's more like a fortress, capable of defending the area as it sits quite high and has great views of its surroundings. It's well worth the visit, not only for the views, but also for admiring a very well maintained fotress, built by the Arabs in the 10th century. It's incredible how well the site has been preserved, you could swear it was built just recently. I ended up doing a full castle circle and admired all the views, since all of them were both incredible and unique. You have a view of the Atlantc Ocean, which is right there, you can probably see Cabo da Roca. Then there are views over Sintra, obviously, and also towards the other atraction of the day, Palácio Nacional da Pena.

The Moorish CastleView of the Atlantic from the Moorish Castle
view of the moorish castlea view over the atlantic ocean from the moorish castle

Now, this second castle is indeed an actual proper chateau, built for the actual Portuguese royalty. On the exterior, the National Palace of pena is marvelous and it definitely gave me Disneyland vibes, given its architectural style and the rich combination of colours. It's also surrounded by a very large domain that acts as a park, and even though there is more climbing to be done, it's a very pleasant walk. Inside the castle it's nothign that special, but it's nice enough, as there are many rooms that belonged to king Ferdinand and queen Maria and display a generous collection of furniture and decorations. Unfortunately, I was in a queue of people that moves quite slowly during the whole tour, and that part was not exactly my cup of tea, but it's understandable due to the structure of the tour and the number of people wanting to visit.

A view of the Pena Palace from belowPena Palance from its courtyard
pena palace photographed from belowpena palace viewed from one of its courtayrds

With the tour done, I returned to Sintra by the same road, only this time it was downhill, and stopped at the local Starbucks for some late lunch and a glass of iced matcha latte. It was a very well spent day, I enjoyed the town so much, the castled were impressive and the views even more so. I took the train back to Lisbon and searched for dinner.

Cascais

My second recomandation to visit near Lisbon is the coastal town of Cascais. The next day after the Sintra trip, I boarded the train from Cais do Sodré and enjoyed a similar trip to the one I had the day before. It was great to be able to use well thought transportation infrastructure in order to get around, so kudos to Portugal for that. In places such as the Amalfi Coast or Sicily, the lack of proper public transportation is pretty annoying, at least to me, but in Lisbon everything was spot on.

I arrived in Cascais and immediately felt in love with it. It's a place where you immediately feel like you're on a proper holiday, and start thinking only about laying in the sand, playing beach volleyball, surfing and long walks by the sea. The town is very pretty overall, and there's a lot of shopping to be done in the center. What I liked very much was the Marina, and I took my time to walk around it and admire the boats that were moored at that time. I continued my walk around the coast and eventually reached Boca do Inferno, which is a very beautiful display of oceanfront cliffs that were carved by the relentless waves into an open cave. A great spot to admire, but, to be fair, the whole coast is equally beautiful, so I exited the main road in order to hop on the cliffs and try to get closer to the water, so I could get a better view.

The Cascais MarinaBoca do Inferno near Cascais
the cascais marinaboca do inferno near cascais

After walking for some time on the coast, I reached Guia Lighthouse and decided to head back to town, as there wasn't anything else on the way to visit, at least not within walking distance. I rented a bike on my way back, parked the thing in a designated parking lot, and went to have a very late brunch. Afterwards, it was back to Lisbon, as I was already feeling a bit tired from all the trips I had during those two weeks.

The End

Portugal is probably my favorite country to travel to, so far, even though I hardly had a chance to explore it further. On my list there's Madeira, the Azores and Porto at the very least, and I hope to travel to these places soon. It's a very beautiful country, with very friendly people, great infrastructure, the best food in the world (again, sorry Italy), impressive history and with so much more to offer. I love it, and I look forward to visit it at least once every year, kind of like a tradition. Thank you, Web Summit, for giving me the excuse to discover such a great place!

TDD a Downshift feature request

· 12 min read

praia da arrifana, portugal Praia da Arrifana, Portugal.

I don't always do TDD, but when I do, I write about it.

From the GitHub issue to the next library update on npm, we are going to push a feature request via the magic of Test Driven Development. It's easier than you think, and next time when the interviewer asks if you've heard about TDD, you will smile, say yes, then test drive their Leetcode puzzle and bring home the biggest offer they could make. TDD is also great in day-to-day work when adding features for your products, fixing issues and solving open source tickets, which is what we're going to do here.

The Problem

Let's take the following small feature request from Downshift:

Select element doesn't receive focus when the label is clicked.

Test driving this feature means that we need to write the tests before the feature. And that's a good thing, because writing the tests first will make us ask the most relevant question, what exactly do I want to achieve here.

That usually means drafting a list of requirements, and based on that list of requirements, we will write the tests. Running the tests will result in test failures (at least they should) and by implementing the feature the tests will start turning green. Once all the tests are green, it means our feature is complete. This is called red-green refactoring.

Before making the list of requirements, let's also visualise how this select element is built with Downshift's useSelect.

const {getToggleButtonProps, getLabelProps, getMenuProps, isOpen, ...rest} =
useSelect({
items,
})

return (
<div>
<label {...getLabelProps()}>Books:</label>
<div {...getToggleButtonProps()}></div>
<ul {...getMenuProps()}>
{isOpen ? items.forEach(/* render books if open */) : null}
</ul>
</div>
)

This will build a markup similar to:

<div>
<label id="label-id-1" for="toggle-id-1">Books:</label>
<div
role="combobox"
aria-expanded="false"
tabindex="0"
aria-controls="menu-id-1"
aria-haspopup="listbox"
aria-activedescendant
aria-labelledby="label-id-1"
></div>
<ul role="listbox" id="menu-id-1" aria-labelledby="label-id-1">
</div>

The Requirements

  1. Clicking the <label> should place the focus on the combobox element.

This would have been done automatically if the labelled element would have been an <input> or a <button>, given how the label's for attribute works by default. However, if the labelled element, here the combobox, is a <div> (ARIA 1.2 spec), the focus must be added manually via a click event. We would have the same issue if we replace the <label> with something else, so another reason to add this behaviour.

  1. Passing an onClick to getLabelProps should not interfere with the default focus behaviour we will be adding.

For instance, calling the code below should focus the toggle button and display the log.

<label
{...getLabelProps({
onClick() {
console.log('Clicked!')
},
})}
/>
  1. Passing an onClick to getLabelProps adds the preventDownshiftDefault attribute on the click event object should not focus the toggle anymore.

It's a practice similar to the event's preventDefault, where we can control the default behaviour of the event. In Downshift's case, we want to be able to stop the Downshift default behaviour.

<label
{...getLabelProps({
onClick(e) {
e.preventDownshiftDefault = true

document.querySelector('#better-element').focus()
},
})}
/>

The Tests

That's the beauty of drafting a list of requirements, you could use it to write the tests. Downshift is a React library, so we are going to use React Testing Library and Jest in order to check our changes will be correct.

Our first test is going to be easier, since we only want to render the Select, click on the label, and check if the toggle has focus. To render the component, we will use RTL render method with a JSX similar to the example when describing the problem.

function renderSelect() {
const utils = render(<Select />)

return utils
}

function Select() {
const {getToggleButtonProps, getLabelProps, getMenuProps, isOpen, ...rest} =
useSelect({
items,
})

return (
<div>
<label {...getLabelProps()}>Books:</label>
<div {...getToggleButtonProps()}></div>
<ul {...getMenuProps()}>
{isOpen ? items.forEach(/* render books if open */) : null}
</ul>
</div>
)
}

With these abstractions in place, our test becomes:

test('clicking the label moves focus on the toggle element', async () => {
renderSelect()

// RTL's user-event tool
await user.click(screen.getByText('Books:', {selector: 'label'}))

// RTL jest-dom extends Jest's expectations to include "toHaveFocus".
expect(screen.getByRole('combobox', {name: 'Books:'})).toHaveFocus()
})

And we're done. We render, we click the label, we check if the focus is where we need it to be. We run the test, it will fail, it's a success, we go grab lunch.

Now, something about the other 2 requirements. These are part of Downshift's API for some time now, and they already have a utility function that chains callbacks together and calls all of them on a event trigger. This utility also knows not to call Downshift's default event handler if "preventDownshiftDefault" has been passed. We are not going to test this utility now, we just want to make sure it works for our callback. Sure, we can just mock that utility and check the call, since we also test the utility in isolation to make sure that it works. But it's better to test for the actual user consequences rather than implementation details, so let's write the tests for these last requirements.

For the second requirement, if we pass our own onClick to getLabelProps, it should get called along with the default handler that sets focus. For this particular test, we don't need to render the whole component, we can just render the hook, like this.

export function renderUseSelect(props) {
// renderHook from RTL
return renderHook(() => useSelect({items, ...props}))
}

Now, we need to find a way to check that our custom onClick is called when the label gets clicked. Which, in turn, means that we need to actually trigger that click, since we are not going to render actual markup, we are just testing the hook. We know that getLabelProps will return an onClick that should end on a label element, so all we have to do is to pass a Jest spy as an onClick argument to getLabelProps, then call the onClick returned, and check the spy.

test('event handler onClick is called along with downshift handler', () => {
const userOnClick = jest.fn()
const {result} = renderUseSelect()

const {onClick} = result.current.getLabelProps({
onClick: userOnClick,
})

onClick()

expect(userOnClick).toHaveBeenCalledTimes(1)
})

Simple! Now we test that whatever we pass in the onClick, it will be called with Downshift's handler. Which is something we don't test at the moment, and that's a huge potential problem over there. We don't want a regression to slip in one day and ruin everyone's Select elements if they also wanted to pass their own event handlers to our prop getters, which is a very common use case.

This is the part of the TDD where we need to think about the implementation. To manually focus the toggle element, we need to use a React ref on the combobox toggle JSX element, and use that ref object to perform a manual .focus(). Consequently, there's going to be a ref object returned by getToggleButtonProps, as it needs to be passed to the toggle element. We will use the ref in the useSelect code in order to perform the focus action. In our test, we just need to grab this returned ref and call it with a mocked object that has a focus function attached to it, which will be a jest spy. If our implementation works, the object we pass as argument to the ref function call is going to be used by the internal code to perform the focus. The test becomes:

test('event handler onClick is called along with downshift handler', () => {
const userOnClick = jest.fn()
const mockToggleElement = {focus: jest.fn()}
const {result} = renderUseSelect()

const {onClick} = result.current.getLabelProps({
onClick: userOnClick,
})
const {ref} = result.current.getToggleButtonProps()

ref(mockToggleElement) // simulate that React will add the toggle element in the ref.
onClick() // now we should have the ref containing the toggle element, we can click the label.

expect(userOnClick).toHaveBeenCalledTimes(1)
expect(mockToggleElement.focus).toHaveBeenCalledTimes(1)
})

We also need to check that setting "preventDownshiftDefault" will not focus the toggle element. The test is going to be similar to the previous one, only that the userOnClick implementation will set this attribute on the event object.

test('event handler onClick is called along with downshift handler', () => {
const userOnClick = jest.fn(event => {
event.preventDownshiftDefault = true
})
const mockToggleElement = {focus: jest.fn()}
const {result} = renderUseSelect()

const {onClick} = result.current.getLabelProps({
onClick: userOnClick,
})
const {ref} = result.current.getToggleButtonProps()

ref(mockToggleElement) // simulate that React will add the toggle element in the ref.
onClick() // now we should have the ref containing the toggle element, we can click the label.

expect(userOnClick).toHaveBeenCalledTimes(1)
expect(mockToggleElement.focus).not.toHaveBeenCalled()
})

We are in a very good spot right now. We have written great tests that communicate exactly what our goal is, and that will only smoothen the implementation process. While deciding on the requirements and writing the tests we can also get better feedback from all stakeholders, since we already have a list of objectives, and it's easier to collaborate on that. We could get extra requirements (more tests) or, even better, some may decide that some requirements are superfluous. So what we may need to remove some already written tests? Less code is good.

Implementation

The implementation is rather easy. Given the current code, we will add another onClick function to be returned from getLabelProps, and we will use the toggleButtonRef we already have in order to focus the element.

Before:

const getLabelProps = useCallback(
labelProps => ({
id: elementIds.labelId,
htmlFor: elementIds.toggleButtonId,
...labelProps,
}),
, [elementIds]
)

After:

const getLabelProps = useCallback(
({onClick, ...labelProps} = {}) => {
const labelHandleClick = () => {
toggleButtonRef.current?.focus()
}

return {
id: elementIds.labelId,
htmlFor: elementIds.toggleButtonId,
onClick,
...labelProps,
}
},
[elementIds],
)

Success! One test is passing already, with 2 more to go. Once these are green, we can agree that our implementation is a success. And that's the easiest part. We will also use our callAllEventHandlers utility in order to chain the callbacks and also check for the "preventDownshiftDefault" property.

const getLabelProps = useCallback(
({onClick, ...labelProps} = {}) => {
const labelHandleClick = () => {
toggleButtonRef.current?.focus()
}

return {
id: elementIds.labelId,
htmlFor: elementIds.toggleButtonId,
onClick: callAllEventHandlers(onClick, labelHandleClick),
...labelProps,
}
},
[elementIds],
)

Utility Function for Reference

The callAllEventHandlers utility will call the functions passed to it, in order, until one of them passes the "preventDownshiftDefault". It's important to pass the focus setting handler at the end. If you need such a function in your life, here it is:

/**
* This is intended to be used to compose event handlers.
* They are executed in order until one of them sets
* `event.preventDownshiftDefault = true`.
* @param {...Function} fns the event handler functions
* @return {Function} the event handler to add to an element
*/
function callAllEventHandlers(...fns) {
return (event, ...args) =>
fns.some(fn => {
if (fn) {
fn(event, ...args)
}
return (
event.preventDownshiftDefault ||
(event.hasOwnProperty('nativeEvent') &&
event.nativeEvent.preventDownshiftDefault)
)
})
}

You also need to properly compose the ref objects. In our case, the toggle element is going to be used by useSelect, and it may also be used in the component using useSelect. Also for reference, here's the ref composing function and its usage.

const toggleProps = {
// refKey could be ref, could be innerRef, up to the user
[refKey]: handleRefs(ref, toggleButtonNode => {
toggleButtonRef.current = toggleButtonNode
}),
// ... the rest of the props returned by getToggleButtonProps
}

function handleRefs(...refs) {
return node => {
refs.forEach(ref => {
if (typeof ref === 'function') {
ref(node)
} else if (ref) {
ref.current = node
}
})
}
}

Last Changes and Merging

We can create a new branch and commit our new changes. Given the nature of Downshift, we have TS files separately, and sometimes they also need to be updated. Now it's such a case, given that we changed the type of a return value:

export interface UseSelectGetLabelPropsReturnValue
extends GetLabelPropsReturnValue {
onClick: React.MouseEventHandler
}

We also need to update the documentation, to make it clear to our users that we added an event handler to the label props. We also want to mention what the event does.

#### Label

- `Click`: It will move focus to the toggle element.

Finally, we run the validation script, which in Downshift's case, it runs all the unit tests, the coverage check, the e2e tests, linting and all that stuff. Afterwards, we push the changes, create a PR, let the same validation script run via GitHub actions, and if the changes look good, we will merge the PR, close the issue, close the laptop and run. We should get an email from npm that the library has been updated successfully. In our case, it should be a minor version bump, since it's a feature.

Conclusion

I don't always do TDD, but when I do, I write about it. It's a very neat process, and I am super thankful to Kent and his Testing Javascript teachings. I was always passionate about automated testing, but his course just completely changed everything for me. If you haven't done it yet, I strongly recommend it, it's so worth it. Tip: try to get purchase parity for it if you aim to use it in your own home country only. You will get a discount.

I hope my Downshift TDD experience helps you write better and test better in the feature. If it sparked your interest in using TDD more or just to learn to test better, I declare myself happy for it. Good luck in writing great code and improving the world through your work!

Prague 2023

· 17 min read

view of the old town from the Prague castle View of the old town from the Prague Castle.


So, picture this. Silviu, one protein bar, some water, 25% phone battery, no waterproof jacket, pink bike with a basket, soaking wet, in a God forsaken town called Roblín, where the only bus station was served at some point during that day, towards some destinations I had no interest in.

Prague is special to me. It's the city I lived in for almost 3 years, and in many ways, it has shaped me into the person I am today. It's a great city to live in as an expat, with a mix of eastern, western and central Europe, pretty much a melting pot of cultures. Some people choose Prague to be their home, others will move to a different city after a few years, and there are also some who choose to return to their home country. I met all of them, and I am not aware of anyone regretting their experience of relocating to the Czech Republic.

I am not going to focus on what Prague means to me as an experience, although there is a lot to say here. Instead, I am happy that I've visited the city 3 times this year, mostly because most of my team at work is based in Prague, and there have been quite a few occasions to visit. My first visit was in January, which is probably the least recommended time of year to schedule a visit. The subsequent trips were in June, which is way better weather wise, and the last one was in October, which turned out to be better than expected. All in all, I would probably recommend visiting Prague during the summer, as it's not very hot during that time, and you would get the most out of your trip. You don't want to be in Prague when it's cold, or when it rains, or both. Trust me on that one.

Prague City Center

It's no surprise that the City Center is the main stop when going to Prague. Even when I was living in Prague, most of my walks were done in this area. The reason? It's gorgeaus. Almost all the buildings in Stare Mesto, but also around it, are old buildings that have been beautifully restored, and the result is incredible. Everything you see just looks as if it belonged there for a very long time, with a successful blend of many architectural styles, such as Gothic, Baroque, Art Nouveau and even Moorish Revivial. It's not just the monuments themselves, but everything really, including the streets and sidewalks, where they stubbornly insist in using cobblestone.

I try to avoid staying in the city center, given the constant noise, so most of the time I book accomodations next to the center, either around the I.P. Pavlova metro station, which is a great connection hub for public transport, or somewhere in Vinohrady, which is a pretty popular neighbourhood right next to the center, usually preferred by expats with better financial means. Consequently, my first stop on my way to the city center would usually be Václavské náměstí, with the Národní Muzeum at its start. It's a great museum to visit, with an impressive minerals collection, a prehistory collection with mammoths and all the usual art museum stuff. They shot the first Mission Impossible movie inside the building, then closed it for what it turned out to be a long time of restoration. It was still closed when I lived in Prague, so I only got to see it last year for the first time.

Narodni MuzeumView of the Narodni Divadlo from the Vltava
narodni muzeumview of the narodni divadlo from the vltava river

After crossing the square, I usually take a right on the Jindřišská street, until the Náměstí Republiky square, and admire some impressive buildings, such as the Prašná brána, the Obecní Dům and the façade of the Palladium mall. Quite close to the square are some of my favorite places in Prague, such as the EMA Espresso Bar or the Vinograf Senovážné. If you go to EMA, make sure to also take a buchta along with your coffee.

Going towards the mall and then making a right on the Dlouha street, we are suddenly in the party part of town. Prague is a pretty famous party destination, especially for stag or hen parties, and most of them are happening in Dlouha, in places such as James Dean, Moonclub and others. After crossing Dlouha, you end up in the Staroměstské náměstí, probably Prague's point zero, with the famous Prague Astronomical Clock and the Municipal Library. It's also very close to the other point zero, which is Karlův most (Charles Bridge). There are so many other places to check out in this area, such as the Rudolfinum concert hall or the Klementinum library. The tour continues on the Charles Bridge, obviously, or if you already been there, I recommend also the Mánesův most, which is the next bridge across the Vltava and offers great views over the Charles Bridge.

Once we cross the river, there's again a lot to do and a lot to see. Welcome to the romantic part of town! If you're in luck, there's going to be swans in Park Cihelná, and that's probably on of my favorite places in the city. Once we're done admiring, the next most important things to see are the Waldstein Palace, which is actually the Czech Republic Senate building, and if you're not visiting during the winter, you will find the gardens open to the public. Don't miss the gardens as they are quite pretty, with Baroque statues, pools full of giant fish and pleasantly groomed shrubbery and flowers.

With this final checkpoint acquired, it's time to make the climb to the Prague Castle. Inside the castle there's nothing spectacular to see, so you could totally miss visiting it, but there are some garden views that make the tour worth it, and there's also the St. Vitus Cathedral, which is the actual attraction to see. After exiting the castle, I always like to take a few moments and enjoy the Hradčanské náměstí, as it's probably one of the most impressive places in the city, featuring the Šternberský Palace and many other beatiful palaces and churches all around the place. Also here it's my favorite view point in Prague, right next to the Starbucks, where you could enjoy a coffee in the garden if you happen to find an empty table, as the view is totally worth it.

Old Town View from the Petrin TowerView of the Charles Bridge from below, in Park Cihelná
a view of old town from the petrin towercharles bridge view from park cihelná

Going further on the Loretánská, we eventually reach the Strahov Monastery and the Brewery, and both of them deserve a visit, for different reasons. The monastery features an impressive library, but unfortunately you are not allowed inside, and can only just look at it from the door. Quite unfortunate. And you are probably aware that Czech beer is pretty good. There are many beer varieties in the Strahov Brewery, and all of them are worth trying. Maybe not in the same sitting, or hey, why not, be a hero. Supposing that you don't plan to be a hero, once we exit Strahov, the next point of interest is the Petrin Tower, which offers great city views, since it sits quite high and the tower itself is quite tall. And no, it's not shaking because of the wind. It's the beer.

Once we take all 100 Prague view photos, it's time to descent through the Petřín Gardens. There's also a tram that takes you down back to the city, but I would not use that, and instead just walk and enjoy one of the best parks in Prague. There's also the Kinsky Garden nearby, which is the park that was closest to my place when I lived in Prague and one of my favorite running tracks. Most likely, after the descent, we will end up in Ujezd, and here you must try the artic bakehouse, with the best pastry stuff in town. Don't miss my favorite, the Cherry Bomb. Also nearby there's Cantina, another favorite place, with the best Fajitas that I never manage to finish, and believe me, I tried. They also serve another personal favorite, the Strawberry Frozen Margarita. Try to book before going and have cash at hand. We can now cross the Vltava again via the Most Legií, and here we have the Střelecký and the Slovansý ostrovs. If you are lucky, apart from swans, you will meet a few cuddly river rats on the river banks. Once we cross the bridge fully, we arrive at the Národní divadlo, and from here, we could pretty much go anywhere. We just finished the essential Prague City Center Tour, congratulations! As reward, go for coffee and waflles at the SmetanaQ Café.

Around the City Center

Prague has a lot to offer outside the city center as well. It would be a shame to keep your walks focused around the Charles Bridge. One of my favorite pastimes was to grab a drink and sit on the bank of the Vltava River, called the Naplavka. It's a great meeting spot for people especially in the summer, and all the ships that are docked are going to be open either as terraces or as bars. Sitting on the river bank is also nice, since the area is very lively. As we're in the area anyway, make sure to take a picture with the Dancing House, one of Prague's landmarks. After a small walk upstream on the Vltava, we will find another Prague landmark, Vyśehrad, a fortified castle overlooking the river, which offers great views towards the old city center, but also to the communist parts of Prague, to the south and southeast. If you like beach volleyball and happen to be in Prague for the summer, you're in luck, since the sport is actually quite popular in Prague, and you can play it right next to the river, in Žluté lázně. Oh, there's also a pretty large swimming pool right next to the complex, the Podolí swimming pool.

Charles University Botanical GardenVyšehrad
charles university botanical gardenthe church in vyšehrad

I did mention Vinohrady as the perfect place to book a hotel or an apartment, and it's true for many reasons. First of all, it's quiet. Second of all, it's right near the city center. Last, but not least, it's quite chic and very upmarket. This is one of the expensive neighbourhoods to rent, and your neighbours are probably going to be expats working in tech. It's also very well connected by tram and metro, so it's easy to reach I.P. Pavlova then you could go pretty much wherever you want. It's not just about having a place to stay and leave immediately, as the area is quite nice to explore for a few couple of days. You get one of the best parks in Prague, Riegrovy Sady and Havlíčkovy sady. Actually, to be perfectly honest, all parks in Prague are beautiful, and the city shines in the green area per capita statistics.

Apart from the parks, there are the coffee shops and restaurants. All the good places are here, whether you are craving for coffee, brunch, lunch or dinner. Some of my favorites are Happy Bean, Coffee Corner Bakery, Chilli & Lime and Per Te, for great Italian dishes. To the north of Vinohrady there are also the Žiżkov and Karlín neighbourhoods which are both worth exploring. The theme of great places to hang out continues here as well, although the neighbourhoods look a bit different from Vinohrady. Žiżkov has a more of a working class vibe, but it has more pubs per square kilometer than any other place in the world. Make sure to check out Tiky Taky Bar. Karlin, on the other hand, is a mix of old and new, since much of it is being redeveloped after it suffered from heavy flooding a few years back. Across the river from Karlinn is Holešovice, another neighbourhood that has a lot to offer, like the Stromovka park, the Planetarium or the DOX Centre for Contemporary Art. If you are in the area, make sure to go to Letna for another gorgeaus view of Prague, from the Prague Metronome. This one's another very good meeting place in the summer, with a lot of people gathering for a drink and music, sometimes with DJs performing.

Even Further from the Center

The further you go from the city center, the more you realise that the city has gone through many years of communist rule. However, due to the rising cost of living, many people choose to live here or even further, on the outskirts of the city. It's not just communism towards the outskirts, however, and there are many places which are worth visiting. One of my favorite places is Troja, an upscale neighbourhood, where apartment buildings give way to premium houses and vineyards. Two of best places to visit are here, and I highly recomment both of them: The Botanical Garden and the Prague Zoo. Both of them are placed on large swathes of land and you will most probably spend the whole day in both, so be prepared for that. They are organised like parks, and it's a pleasure to walk and admire so many varieties of plants and animals that are very well taken care of.

Prague ZooVltava near Zbraslav
elephants at the prague zoothe vltava river near the town of zbraslav

Now, of course it's not just Prague. The Czech Republic has so much more to offer. It's a very nice country with an abundance of scenery and beautiful places, and the people take very good care of it, so it's well preserved. The most popular day trips from Prague include Kutna Hora, Brno, Karlovy Vary, Česky Krumlov and, the one I will ellaborate on, Karlstejn. This town is pretty close to Prague, at about 30km, and it's easily reachable by car, by train or, the best one in my opinion, by bike. I did the trip twice using the Rekola bikes, which you could rent in Prague like you would rent scooter. Once you reach the town and enjoy the scenery, you could come back by train, if you are pretty tired from the trip.

Once upon a time it was a not so beautiful morning of Monday, on the 5th of June, I had a gread idea of a bike trip to Karlstejn. I rented a Rekola for a full day quite close to the Karlovo Namesti. Armed with my phone, a couple of protein bars, some water and high hopes, I started my journey on the Vltava River upwards towards Zbraslav. I was too lazy to set up the proper bike map beforehand, and would was very soon to realise my mistake, since I was supposed to cross the river near Zbraslav, but I ended up in Vrané nad Vltavou, paused for a few minutes, and performed a Gandalf "no memories of this place". No biggie. I turned around, crossed the river at Zbraslav, but it seemed that it was a totally different road from the one I picked a few years back. The Gandalf feeling was still strong. Anyway, time was ticking, so I went on through some not so beaten tracks of countryside, like I was chasing a band of orcs on my pink bike.

I enjoyed a coffee, a cake and a proper Czech hospitality in the town of Černošice, and continued on the road to Karlštein. This road was properly called Karlšteinsk, but, as I found out in the meantime, it was a road actually meant more for agricultural purposes, rather than recreational ones, and I suddenly found myself in the middle of rural Czech country, still with a lot of road to cover. To add the cherry bomb on top, it just started to rain, and I was in the middle of the road with no waterproof anything. Not good.

So, picture this. Silviu, one protein bar, some water, 25% phone battery, no waterproof jacket, pink bike with a basket, soaking wet, in a God forsaken town called Roblín, where the only bus station was served at some point during that day, towards some destinations I had no interest in. And I had two options, to either continue on the normal road, or take a shortcut through the woods, on some sort of a hinking trail, that would shorten the way by quite a bit. It was still raining quite a lot, and, looking at the weather app, it was not going to stop until the next day. Maybe I should have checked the app in the morning, that might have helped.

Prague to Karlštejn bike trip which you should not take
a strava map of the bike trip from prague to karlštejn

But mom didn't raise no quitter, so I took the short route, through the woods. Everything was wet, I was on a pink bike, with a basket, on a slippery dirt road, riding downhill. Was it dangerous? It was outright stupid. I soldiered on through the woods, it was quite dark all around, the rain was not stopping, and I somehow reached Mořina, from where there was a straight road to Karlštein, surrounded by woods, a very nice road to ride on, if it wasn't for the rain. I was not feeling the rain anymore, actually, as I was wet all the way to my skin, and I really did not care for anything, except to reach the town and hope that one tavern would receive out of sheer mercy. I arrived in Karlštejn, after the most terribly planned trip in my life, in the most terrible state, and some nice people offered me a table at Karlštejn 34, where I enjoyed some hot soup, the best pizza in my life, and a cup of coffee that managed to ressurect my soul.

There would not be any sightseeing that day, since it was still raining quite heavily. I actually intended to visit the Castle and the Velká America pit, but that had to be saved for another day. I went to the train station, bought a ticket for me and my pink bike, with a basket, and went back to Prague.

Now, should you go to Karlštejn from Prague by bike? Absolutely. Should you be utterly careless about the trip like I was? Absolutely not. Set up the proper route beforehand, check the weather, and have a rainproof coat. You're in the Czech Republic, it's famous for it's rainy weather. I should have known better, but I survived, and what does not kill you makes you wiser. Or not.

Wrapping Up

I will always be grateful to Prague and everything about it, and I will always return there with the warmest of thoughts. And if you hadn't been there yet, it should definitely be on the top of your list. It has so much to offer for everyone, and it's a great place to live abroad, if you're considering such an experience. It was life changing for me. It helps a lot that most of my team at work is based in Prague, so there will be plenty of opportunities to return in the future, but, honestly, I don't really need an excuse to go. And you shouldn't need one either. Happy travels!

Naples 2023

· 12 min read

view of the Vesuvius volcano from the sant&#39;elmo castle in naples View of Naples and Vesuvius from the Sant'Elmo Castle.


There's something about this town and football.

If you've read my travelling plans for 2023, I mentioned only a couple of places that have been on the top of my list. As 2023 went by and I travelled quite a lot until now, I added Sicily to the top of my list, so I started to look for tickets during the summer. Since both the tickets and the accomodation were great value for money, I decided to go ahead and seal the deal for the trip to Naples. Just as I was getting ready to pay, I realised that I wasn't actually going to Sicily at all. In my mind, Naples and Palermo sounded to be the same thing, and that sparked a great deal of confusion. After I paused for a few minutes, I realised "what the hell", and bought the trip anyway. Yolo.

Naples

I was expecting the city to be a little different from the other cities I've been so far in Italy, and I was not disappointed. Naples is not boasting the same architectural wonders as Rome, and it certainly does not have the ritzy attitude of Milan. It's not very clean, either, and the traffic can become quite a nightmare, if you're not used to that. All things considered, I believe Napes is a city that should be on everyone's bucket list, with a small tip, which I will share towards the end.

I don't know about others, but when I choose to travel to Italy, it's not only for the sights or the history, even though there's a lot of that to choose from. I also go for the food, for the coffee and, overall, for the laid back lifestyle. A lifestyle filled with espresso shots, drank alongside a croissant con crema (if there's pistacchio, even better) in a busy coffee shop where everyone just orders pretty much the same thing, s a quick chat, and leaves after 5-10 minutes to handle their business. It's also about great local food, served alongisde glasses of Aperol Spritz and with a Tiramisu to top it off. As we left our hotel room in Naples, somewhere close the central train station, the first thing I did was to check out the nearby coffee shop, which was marked on the map ahead of our arrival. Caffeteria I Servino has great Italian coffee and one of the best croissants I ever had, which provided a great start to the trip. After this quick stop, we made our way towards the city center.

Staying near the central train station is very convenient if you consider taking the train to nearby destinations. For the Naples area, there are sp many places to choose from, like the Amalfi Coast, Capri and Pompeii. However, the neighbourhood itself is not really quite the most exquisite. It's nothing to be afraid when going out, anyway. On the other hand, the area between the central train station and the city center is maybe worse. There's garbage everywhere, many people on the street, and I've seen some buildings that could easily belong in the Ferentari. Not a great sight, to be super honest. We eventually found Via dei Tribunali, where things became a bit better.

Museo Del Corallo AscioneVia dei Tribunali
museo del corallo ascioneview from the via dei tribunali

This very long street sums up a lot about the city. It's quite narrow, so they made it a one-way street, although it could be easily be designated for pedestrians only. It's filled with bars, shops, and an array of flags, coats and signs of the local football team, Napoli FC. There's something about this town and football. Actually, Via dei Tribunali isn't the only street where you can see references of the team. There's football everywhere, it's just that Via dei Tribunali has way more. Naples is literally a Papal State, where the pope is Maradona and the council of cardinals are Osimeh and the Napoli players. The previous season they just won the championship, and they are really proud about that.

We followed Via dei Tribunali all the way to Via Enrico Pessina, and then went south towards the coast, through Toledo. The Spanish Quarter is definitely something different than the neighbourhoods we walked through so far, even though it was way too crowded. The main street, Via Toledo, is what you would normally expect from an Italian street with stores, and we stopped in a few places to check normal Italian things, like sunglasses. What we definitely missed along the way were the Murales Maradona, which would have been the icing on the football cake we had up until that point. Completely forgot about the place, but you always a need a reason to go back, right?

Eventually, we reached the Umberto I Gallery, which resembles the Vittorio Emmanuele Gallery in Milano, miinus the high end stores. After a brief photo session, we exited the gallery and went towards the San Carlo Theatre and finally arrived in Piazza del Plebiscito, with the Royal Palace right next to it. The square has quite a pretty view of the Basilica Reale Pontificia San Francesco da Paola *inhales, even though when we arrived there was a concert setup in place and it marred the sight a little bit. It was quite late when we got there and the palace was about to be closed, so we had to satisfy for the palace gardens. This park with a free entry is a welcoming green oasis in a part of the city that is pretty crammed with buildings, streets and concrete in general.

Naples Waterfront View over Vesuvius
naples waterfront view over vesuvius

As we left the park, we arrived in the San Ferdinando neighborhood, which is significantly different from the neighbourhoods we've seen so far. It's near the shore, its buildings are all beautifully restored and the streets offer great places to enjoy dinner or a few drinks at sunset. However, probably an even better idea is to just grab a few drinks from a supermarket and go straight to the shore. When we arrived there, the sun was close to setting and the light was absolutely gorgeous. We took a seat on one of the stones that were above the water and enjoyed the picturesque view of the Vesuvius volcano. Happy and quite tired, we walked back home by the waterfront and prepared for next day's trip.

Sorrento

In order to reach te Amalfi Coast, things are not so straightforward, as you might expect from such a notorious place. There is the option of renting a car, although the road along the coast is said to not be quite narrow and full of twists and turns. Consequently, the remaining option is to take the train to Sorrento and, from there, take one of the boats to Capri, Positano or Amalfi. Apparently, there is also a bus that goes along the Amalfi Coast, but we lost quite some time trying to find it. In the end, we decided to take the boat to Positano. Since the train to Sorrento took an hour, and we lost at least another hour searching for the bus, it became quite late to reach Positano that day and come back to Sorrento, as each boat trip takes 45 minutes. As a result, we decided to stay in Sorrento for the day and visit Positano the next day. And it turned out to be a great call.

This small town on the coast, in addition to being a transportation hub for the region, is probably one of the most beautiful towns I visited so far, on par with Portofino and the Cinque Terre. Sorrento sits quite high on the coast but it also features a few beaches on its shore, so it can definitely be a spot to relax by the sea. Its streets are a joy to walk through if you like to lazily stroll around and enjoy coffee and ice cream along the way. You should also definitely try the Limoncello, since the region claims to being the birthplace for the drink.

Sorrento Vesuvius ViewSorrento Hills
sorrento vesuvius viewhills of sorrento

We had a great lunch at the Fuoro51, went for an aimless walk through the streets, then headed towards the beach and enjoyed the views towards the town from down below. As we arrived on the beach, we bought drinks from a local grocery store, opened them on a bench and enjoyed the sea view with the boats. That evening, we happened across what seemed to be a formal event that took place right on a pier, in a place called Bagni Sant'Anna. The whole setup made the evening perfect, and we enjoyed it right until it was time to leave and catch the last train to Naples.

Sorrento is impressive, and since the town looked so good, you could imagine our expectations for Amalfi and Positano. But, make no mistake, Sorrento is a gem, and you should not miss it. Actually, given the views, the places and the transportation options, I believe that Sorrento is actually the better place to book accomodation when going to Naples and the Amalfi coast. It's conveniently situated in case you want to go anywhere, as you can take the train to Naples and Pompei, or the boat to Capri, Positano and Amalfi. It's also a great spot to just relax on the beach, enjoy the views and have a nice dinner on the waterfront. Our friends chose to stay in Sorrento instead of Naples, and it was a much better decision. On our next trip in the area, lesson learned, we will definitely do the same.

Positano

Finally, the cherry on top, Positano. We were quite enthusiastic about the town, and our hopes were quite high, given that we enjoyed Sorrento very much. Even with these expectations, Positano did not disappoint. It's simply stunning. It's also quite crowded, at least around the harbour area, so the first objective was to escape and head up towards the hills, in order to find great viewpoints towards the sea. We found quite a few, really fast, and took great photos of both the city, the sea, the hills and boats. Everything matched perfectly and it was hard to take bad shots, honestly. We still went uphill, for even better views, but the shots were not as good, so if you're aiming for the perfect view, higher is not necessarily better here.

Positano HillsPositano View from Above
positano hillsa view over positano and the amalfi coast

The second objective was to have lunch, so we went to the Casa e Bottega restaurant, which featured a meanu that was quite brunchy for the location, but nevertheless it has probably the best Tiramisu in the world, so definitely worth going there. Re-energised, we resumed our uphill journey and headed towards the final objective, Le Tese di Positano, a hiking trail that starts in the Northwest part of town. We did not go very far on the trail, unfortunately, as we had to return back to the coast and catch the boat back to Sorrento, but I think it would have been a vey nice hike. We also did not have any water, which was quite a huge mistake, given that it was also quite hot during the day. Overall, not much more to say about the town, but it's definitely a great spot to relax for a few days, just like Sorrento, so maybe an option for the future. We took the boat back to Sorrento, the train back to Naples, and, needless to say, we were exhausted.

Back in Naples and Final Thoughts

During our final days in Naples, we took it easy given our accumulated fatigue, so we went for some easy strolls throughout the city. We went to the Botanical Garden and then to the Royal Palace, since we missed it during the first day. Both attractions are pretty good, especially the palace, which has an impressive collection of art. For dinner, we went to Pizzeria Pavia, which is quite popular in Naples, although the place does not look flashy in any way. As we waited for our flight, we went to Caffè Sansone for some speciality coffee, and since we thought that we still had time until taking off, we visited the Sant'Elmo Castle, which was pretty close to the coffee shop. The castle has really great views over Naples and Vesuvius, and it's not very crowded. It does not boast any art collection or something of the sort, but the views are really worth it.

Overall, it was quite a long trip, and we visited quite a few places. We would still do it again, but next time we will heed our own advice and stay in Sorrento, since it's definitely the better option. There's still Capri on the list, along with Amalfi and Pompei, so there is still lots to do in the area. The flight from Bucharest is short, cheap and direct, so there's absolutely no reason not to return. So, until next time, happy travels!

Overwriting Property Types in TypeScript

· 14 min read

the library in the morgan museum, new york The Morgan Library Museum in New York. Photo by Silviu Alexandru Avram

TypeScript is a great alternative to JavaScript if you feel the need for that extra safety net of strong typing. Most of the tyme, TS is pretty straightforward, as we are familiar with strong type languages like Java. However, when we do require a tiny bit of dynamic type magic, things can stop being straightforward, and we can end up being very creative. But when we actually get the job done and even improve on the result, we realise how strong TS can be, and we are super thankful for its existence.

In this article, we are going to touch concepts like TypeScript as a language in general, but also Generics and some TS utilities that are available globally. Solving the problem below helped me understand TS better, and I hope it helps you as well. Let's begin.

The Use Case

The JS code below is the one that required some creativity from my part, when improving Typescript types for downshift. For simplicity, I removed some React specific details, since they are not relevant to the topic.

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
} = {}) {
function toggleButtonHandleClick() {
dispatch({
type: stateChangeTypes.ToggleButtonClick,
})
}
const toggleButtonProps = {
[refKey]: handleRefs(ref, toggleButtonNode => {
toggleButtonRef.current = toggleButtonNode
}),
'aria-controls': elementIds.menuId,
'aria-expanded': latestState.isOpen,
id: elementIds.toggleButtonId,
tabIndex: -1,
}

if (!rest.disabled) {
if (isReactNative || isReactNativeWeb) {
toggleButtonProps.onPress = callAllEventHandlers(
onPress,
toggleButtonHandleClick,
)
} else {
toggleButtonProps.onClick = callAllEventHandlers(
onPress,
toggleButtonHandleClick,
)
}
}

return {
...toggleButtonProps,
...rest,
}
}

Our function, getToggleProps, receives some props as an Object, which is destructured directly.

  • we are using an empty object as default parameter (= {}), otherwise our destructuring will fail for undefined. Extra safety.
  • we are grabbing a few properties from the object, such as onPress, onClick, ref and refKey, as we are using them in our function.
  • we are using a prop without grabbing it from the object, rest.disabled.
  • we are returning our computed props as toggleButtonProps, along with rest, which are the rest of the props we did not change. We bundled them together by object spreading and returned them.

The Goal

Since this function is written in JS, in order to convert it to TS, or at least provide TS types for it, we need to define the types for both the function parameter and the function return value. The function's purpose is to return attributes that are going to be applied to a HTML button element, but not always. It could be a React Native button as well, or a custom React button component from any UI Library. Consequently, our types requirements are the following:

  1. The parameter should accept HTML button props, in the case of an HTML button, or any custom UI component that also accepts HTMP button props.
  2. The parameter should accept refKey, a string prop used for those rare cases where the component we are passing toggleButtonProps to has a different name for the ref prop, for instance innerRef.
  3. The parameter should also accept an optional onPress, in case we are in the context of React Native.
  4. The parameter should also accept any prop that needs to end up on the element, by being passed through with the rest object.
  5. The return value needs to return the props that are being computed and guaranteed to be returned in toggleButtonProps: aria-controls, aria-expanded, id and tabIndex.
  6. The return value needs to optionally return either onClick or onPress, depending on whether we are on React Native or not.
  7. The return value needs to return those props from #4 that could be anything, but we should also include their type in the return type.
  8. In case there is a type overlap between a prop from the parameter and the one from the return value, the parameter prop type wins.
  9. We cannot do anything for refKey, since that can be any string, with a 'ref' default, so the most we could do here is an optional ref prop.

Implementation

Let's nail the easy static types first, then we will work towards the dynamic override aprt.

HTML Button Props

The parameter should accept HTML button props, in the case of an HTML button, or any custom UI component that also accepts HTMP button props.

For this first part, the implementation is really simple, we just need to make the parameter accept HTMLButtonProps.

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: React.HTMLProps<HTMLButtonElement> = {}) {
// implementation
}

The generic-based React.HTMLProps<HTMLButtonElement> is a great way to achieve our goal, since it will return all the props that could end up on an HTML button. And all of them are marked as optional.

Very easy so far, but there's one problem. TypeScript will complain about refKey, since the prop is not part of React.HTMLProps<HTMLButtonElement>. And there's also onPress. That's not part of the HTML Button either, since it's a prop specific to React Native. Let's fix that.

The refKey Prop

The parameter should accept refKey, a string prop used for those rare cases where the component we are passing toggleButtonProps to has a different name for the ref prop, for instance innerRef.

In order to fix our code, we can just add the two props with a type intersection, like so:

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: React.HTMLProps<HTMLButtonElement> & {
refKey?: string
} = {}) {
// implementation
}

Done! Now the props are the intersection between the button props and the ref type we just created, the only thing we need to accept is onPress.

The onPress Prop

The parameter should also accept an optional onPress, in case we are in the context of React Native.

The most obvious fix would be to add onPress to the type we just created to support the refs.

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: React.HTMLProps<HTMLButtonElement> & {
refKey?: string
onPress?: (event: React.BaseSyntheticEvent) => void
} = {}) {
// implementation
}

For simplicity, we are using React.BaseSyntheticEvent, which is goint to be a common interface for both web and native event handler props in React, since we don't plan to also import React Native types.

The errors are gone and we handled the first 3 use cases, which is great. Since we may want to support other functions as well, not just for toggle buttons, we may want to split the above type into several, which could be used independently. Also, we may want to extend these types, so we should consider using interfaces instead of types. Consequently, our code will become:

interface GetPropsWithRefKey {
refKey?: string
}

interface GetToggleButtonProps
extends React.HTMLProps<HTMLButtonElement>,
GetPropsWithRefKey {
onPress?: (event: React.BaseSyntheticEvent) => void
}

function getToggleButtonProps({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps = {}) {
// implementation
}

Now the refKey part is abstracted away in GetPropsWithRefKey, and can be used by other functions, while the button specific types are bundled together in GetToggleButtonProps, along with the refKey part, through extension.

Pass-through Props

The parameter should also accept any prop that needs to end up on the element, by being passed through with the rest object.

Now comes the hard part. We want to accept anything else the user may need to pass through our function, but still keep our previous GetToggleButtonProps definition for the props. Since we have no idea what the user is going to pass in addition to the types we already defined, we will use a generic type, which we will intersect with GetToggleButtonProps, such that it will include stuff from both. Let's actually write it down:

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}) {
// implementation
}

Rest can be anything, and it does not have to be specified directly when calling the function. For example, this call will be considered correct:

function onClick() {
console.log('clicked')
}

const toggleProps = getToggleButtonProps({onClick, foo: 'bar'})

onClick is part of the GetToggleButtonProps interface, while the foo string property is part of the Rest, and, according to the function implementation, it will be passed directly to the return value. The Rest generic will be super valuable when defining the return value type, as we shall see in a moment.

Guaranteed Returned Props

The return value needs to return the props that are being computed and guaranteed to be returned in toggleButtonProps: aria-controls, aria-expanded, id and tabIndex.

Of course, this part is the easy one, and we will create an interface that defines the props above and their types, according to the implementation.

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}): {
'aria-controls': string
'aria-expanded': boolean
id: string
tabIndex: -1
} {
// implementation
}

Each property is defined as non-optional, since it is guaranteed that we are returning it in the returned object. We can also be super specific with our types, for instance tabIndex is -1 instead of number, as we are going to always return -1, while the other properties are dynamic.

Optional Event Handler Props

The return value needs to optionally return either onClick or onPress, depending on whether we are on React Native or not.

Let's also add the couple of optional handler props and also abstract the whole return value prop into an interface.

interface GetPropsWithRefKey {
refKey?: string
}

interface GetToggleButtonProps
extends React.HTMLProps<HTMLButtonElement>,
GetPropsWithRefKey {
onPress?: (event: React.BaseSyntheticEvent) => void
}

interface GetToggleButtonReturnValue {
'aria-controls': string
'aria-expanded': boolean
id: string
onPress?: (event: ReactNative.GestureResponderEvent) => void
onClick?: React.MouseEventHandler
tabIndex: -1
}

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}): GetToggleButtonReturnValue {
// implementation
}

Looks great! We now have interfaces for both the function parameter and the return value. We are almost at the finish line.

Rest in the Return Value

The return value needs to return those props from #4 that could be anything, but we should also include their type in the return type.

Now it's time to use again the Rest generic we defined previously, and include it in the return value, since it contains the pass-through props. We will use the intersection here, again.

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}): GetToggleButtonReturnValue & Rest {
// implementation
}

Now, everything extra that is passed as rest will be reflected in the type for the return value.

TypeScript VSCode snippet reflecting the rest prop being present in the return value

We just crossed the finish line with half a leg.

Prop Overrides

In case there is a type overlap between a prop from the parameter and the one from the return value, the parameter prop type wins.

Suppose that we want to make our toggle button focusable and add it to the tab order of the page. We will need to pass tabIndex as 0, or any other positive value (big anti pattern, but you can). With our current type definitions, if we pass tabIndex: 0 as a prop to the function, the return value type of tabIndex will stay as -1, since that's what we defined in the GetToggleButtonReturnValue interface.

TypeScript VSCode snippet reflecting the tabIndex prop type being -1 though it has the value 0

Sure, we can just make the type to be number and move on, but that's not what we are actually returning by default. And it's not just about the tabIndex. We can have, for instance, another prop returned by default, such as aria-haspopup, with a listbox default value. But what if the user needs to display the popped out menu as a modal? They would need to pass aria-haspopup: 'dialog' to the function, and the return type for aria-haspopup should reflect the parameter type.

For this reason, we need to create a type that overrides the type we define by default for the props that are passed as parameter and have a different type. Of course, this is not required if those props passed as parameter are destructured away from rest, and in this case we can keep our own type, as the value won't be overriden by pass-through. It's not the case for tabIndex, so we need to override the type here. And the type definition I found to solve the issue is the following, from this thread:

type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U

Whoa, whoa, what? Ok, let's try to remember what we want to achieve. If we pass a prop with the same name as the function parameter, then it should override the type from GetToggleButtonReturnValue.

Let's consider GetToggleButtonReturnValue to be T and Rest to be U. Overwriting T with U means picking from T only the prop types that are not common between T and U. We exclude from T the props from U, which means there will be no common props as a result of this exclusion, and then we pick these exact props from T. Finally, we intersect these non-common props with U, giving us back the common props (if any), but this time with the types from U. Remember, U is Rest, our pass-through props type.

Consequently, our return type will become:

type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U

function getToggleButtonProps<Rest>({
onClick,
onPress,
refKey = 'ref',
ref,
...rest
}: GetToggleButtonProps & Rest = {}): Overwrite<
GetToggleButtonReturnValue,
Rest
> {
// implementation
}

And voilà, the result:

TypeScript VSCode snippet reflecting the tabIndex prop type being number in the returned value due to type override

Also important to point out, due to the current type of the parameter GetToggleButtonProps & Rest, you cannot pass just any type to the properties that are statically defined, such as tabIndex, onClick, refKey and the others. Passing a number for the onClick prop will fail since it's clearly defined in the React.HTMLProps<HTMLButtonElement> as a function with certain parameter types. You could pass tabIndex as 0 due tot the fact that it's a number type in the React.HTMLProps<HTMLButtonElement>, even though we made it -1 in our return type, as a result of our function implementation.

The Ref Prop

We cannot do anything for refKey, since that can be any string, with a 'ref' default, so the most we could do here is an optional ref prop.

This is going to be our only limitation. Passing a custom string as a refKey will not reflect a property with the key as that string value in the return type. There is no way (that I know) to get the string value from an object key and use that as a key in a type. Consequently:

TypeScript VSCode snippet reflecting the customInnerRef string value for refKey not ending in the return type

There's no customInnerRef property in the return value, just the ref optional property that is going to be passed by default, in case we don't pass any value for refKey (refKey = 'ref',).

Conclusion

In this post, we went through defining static types for a function's paramater and return value, as well as allowing dynamic types to override previously defined static types, where such a case was needed. We also defined an initial set of expectations, starting from a working example, then we went through the use cases one by one and altered the solution accordingly. We also saw a few usages of TS helper types, such as Pick, Exclude and others.

Improving the Types in Downshift was a great experience, as there were quite a few use cases to consider for the getter prop functions. I found the experience so useful that I considered to write in detail about it, and I hope you will find it useful in some way as well.