Table Of Contents
- The Problem
- Rendering A Link
- Objects And Typing Issues
- Another Solution
- The Better Solution
I’ve been taking more and more tickets with the new gig. This week I was tracking down some text to make some updates, and this was not as simple as I thought it might be, so I decided to take some notes and reflect on some stuff I learned.
The task was simple, update some text on the platform. I quickly discovered that it was not as straightforward as I thought.
The first issue was trying to track down where some of these values which needed changing lived.
The second problem was the updated content included a link to some external docs for our platform.
So I found where the objects storing the text were. That problem is solved. On to the next
So how do I add a link to these strings I mentioned? It seemed easy; you replace the string, but how do you make the link element work?
The solution should have been more obvious to me at that point. But sometimes I forget stuff; I’m human. I’m allowed. So let’s go through my process.
I thought I could just put an href tag into the string value I was updating. Like so.
And I pass it into the JSX like this.
That won’t work since you end up with this.
So we needed something closer to this.
I’m using the prebuilt Link component provided by Material UI, and I needed to get the link passed into this component in our JSX as a string, which solves this problem and takes us to the next problem.
Now I have a new goal.
I created an object literal to hold my values and possibly use it to hold URLs for additional help docs in the future.
The next step was to pass that URL around. Here’s another layer; I wanted to reuse a string value used to grab all the config options to cut down on hard-coded stuff. So I made the key in my object literal match possible values for this string object. Something like this.
We’re using bracket notation to pass in the object key and have it evaluated as the variable
key rather than a standard dot notation, which would throw an error.
Although you undoubtedly noticed the squiggly line yelling at me, that gave me this message that I didn’t understand.
What I initially did confused TypeScript, and thus the error vomit. If we look at the error, though, it’s less error vomit and more a breadcrumb trail back to where I made a mistake.
Our string variable
key is typed as a string, but TypeScript has no idea what the context is since we’re using an object literal without a type. So for TypeScript,
key could be anything in my code, and now I’ve confused it. Here’s where I stepped on a landmine.
My first solution was to cast my object as the
This cleared the error, and I could run the project with the behavior I wanted. Problem solved, correct? Nah.
Why use the language if we’re not going to use the language? I looked for a better solution.
A not great solution would be to use some magic.
A bit is going on here. We’re still using the bracket notation, but in the brackets, we’re casting the variable as type string using the
as operator; this is also called a type assertion. And then, we’re utilizing the keyof operator in TypeScript to create a union type for our
DocMap object, which is passed in using the typeof operator. It’s a solution that confuses me to think about, makes the code harder to read, and introduces a code smell since it seems like a hack rather than a planned solution.
A better way might be to use mapped types and interfaces. As a general rule in my TypeScript adventures, I’ve been sticking with making the correct types or interfaces for objects. So following that, I can do something like this.
This solution creates an interface for the help doc objects, and then I can create a new object with our data using that type. I tested making a mapped type for the first property as a demonstration. Generally, you use those when making types with properties that might not be known ahead of time. It’s a generic type that we can use to denote the types for the value and keys in any
DocMap type object.
My only issue is that it’s still a bit roundabout for what I want. This is one-time use, and it’s not being exported anywhere. So I want something even simpler.
My solution was to use a Record type to create an object type with the required property types.
The Record type is a utility type that uses the passed in types, via the angle brackets
<>, to map the types for the object property names and values. This is type-safe, easy to implement, and checked all the boxes I needed.
This is the strategy for learning the code base. Spend my energy tackling as many problems as I can early. We called this “racking up the cash register” when I was wrestling. The more I take on, the more I learn, and the more I learn, the bigger the challenge I can take on. I hope this helps someone in their learning journey!