Two weeks ago I landed my first job, a front-end role, and I was surprised by how much typescript was used in their products, my first thought was that I needed to improve my typescript skills, and in the past two weeks, I've been grinding typescript all day to feel confident about my skills.
Where did I Start and my first steps
So, I already knew about the basics of typescript, how a type and interface works, primitive types, type a react component, and a little bit about Utility types, but I wasn't satisfied, and I felt like I needed to know more things to get the job done in a property way, so how do I start?
My first step was revisiting all the free workshops that Matt Pocock provides on his website and see if I let something slide out of my eyes, in this process I learned how to property type a Reducer because was the most complex hook I faced in react and the first time a saw his webpage the react with typescript course was not available, here some code snippets of what I did to improve my knowledge with reducer.
type ReducerState = {
age: number;
name: string;
};
type ReducerAction =
| {
type: 'updateName';
newName: string;
}
| {
type: 'updateAge';
newAge: number;
};
const initialState = {
age: 42,
name: 'Joao',
};
const reducer = (state: ReducerState, actions: ReducerAction) => {
switch (actions.type) {
case 'updateName':
return {
name: actions.newName,
age: state.age,
};
case 'updateAge':
return {
age: actions.newAge,
name: state.name,
};
default:
throw new Error();
}
};
const App = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const updateAge = () => {
dispatch({ type: 'updateAge', newAge: 20 });
};
const updateName = () => {
dispatch({ type: 'updateName', newName: 'George' });
};
};
If you are already familiar with typescript you noticed that I use Discriminated Unions to type a reducer action but if you aren't, let me show how it works.
type Props =
| {
type: 'Title';
title: string;
}
| {
type: 'No-Title';
};
const CustomComponent = (props: Props) => {
if ((props.type === 'Title')) {
return <div>{props.title}</div>;
}
};
const App = () => {
//This gives us an error because 'No-title' doesn't have a title property called title
return <CustomComponent type='No-Title' title='aaa' />
}
We use Discriminated Unions when we want different properties based on a property (here we call type 'Title' or 'No-Title') this gives the power to typescript infer a more accurate type for my dispatch based on the action I choose in the last example. So this guided me to think can I build a full generic component that makes sense? This was the door opener for the hard drugs!
Generics
So it's time to start learning the most terrifying feature of typescript, Generics. I didn't have too much experience with generics until now, and my first step was revisiting my first custom hook using generics, let me show you.
export function useRequest<T>(endpoint: string) {
//... a lot of logic stuff
const response = await axios.get<T>(endpoint);
//... a lot of logic stuff
}
It was a simple and naive implementation of generics and I feel like at this moment of my career I can do more complex stuff than that. With this in mind, I wrote a simple List component that uses generics to render an unknown list.
interface Props<T> {
renderItem: (item: T) => React.ReactNode
keyExtractor: (item: T) => string
data: T[]
}
export const GenericList = <T extends unknown>({ data, renderItem, keyExtractor }: Props<T>) => {
return (
<ol>
{data.map(item => (
<li key={keyExtractor(item)}>{renderItem(item)}</li>
))}
</ol>
)
}
Cool stuff using generics
Utility Types is a cool thing to use in your project to handle your types, but you know what is cooler than that? Build your Custom Types.
But first, we need to be humble, how do we know if we are capable of building some utility types for our codebase? before building custom stuff I took a step back and tried to rebuild all the utility types built-in in typescript and let me share what I learned in the process.
//This is how Exclude works in typescript
type MyExclude<T, K> = T extends K ? never : T;
In the code snippet above I use Conditional Types and two Generics to make a logic with types and create a new type from that, if the right generic of extends - in this case a Letter K -, is a subtype of the left side - the letter T -, we exclude all properties of letter K in the type T, if not, we just return properties of T.
With just this level of knowledge of typescript we can build many many things but let me share one more thing that I learned that opened up a lot of possibilities, Mapped Types.
//This is called Mapped Types, we can map over all properties in a type, and create another one
type MappedType<T> = {
readonly [P in keyof T]: T[P];
};
In the code snippet above we re-create the Readonly utility type, isn't fancy stuff in reality is much simpler than I thought initially, so why not push my limit? I don't have money right now to buy all of the typescript wizard curses but to my luck, the community created an open source repo called typescript challenges, with many challenges to sharpen your skills in typescript
https://github.com/type-challenges/type-challenges
This was the last step I took in my journey, I spent 2 days taking some challenges to see what I really knew, what I did not have any clue how to solve and so on, my objective in these 2 weeks was to improve my typescript skills in a front-end role and I think I did a good job, I know that when we created a lib we use a lot of complex types, but I will not create a lib or something in the next months, so I'm glad about my typescript skills right now.
Conclusion
I'm astonished by how much I can learn in only 2 weeks and I will repeat this same process to other topics to be a better swe, if you read this far, thanks for your time, have a good day, and good luck with your Types :)
Top comments (0)