Woah! Can TypeScript Do That?

Rate this content
Bookmark

These days, TypeScript is an industry default as it provides amazing DX with autocomplete, confident code refactoring and much more. But most developers only scratch the surface and doesn't use Typescript to its fullest potential.


This talk would dive into the powerful and advance concepts of TypeScript like generics, conditional types, type guard, utility types for type transformations and much more using real world examples to better understand these concepts.

41 min
05 Jun, 2023

Video Summary and Transcription

Today's talk covers advanced concepts of TypeScript including type guards, generics, utility types, and conditional types. These concepts enhance the developer experience and improve code quality by ensuring type safety and reducing errors. The talk also explores the use of generics to make components more generic and reusable. Additionally, it discusses the power of custom utility types and the infer keyword in creating flexible and precise type definitions. TypeScript's string templates are highlighted as a tool for enforcing restrictions on values like margins in CSS. Overall, the talk provides valuable insights into leveraging TypeScript's advanced features for more robust and maintainable software development.

Available in Español

1. Advanced Concepts of TypeScript

Short description:

Today's talk is about Advanced Concepts of TypeScript. Learn lesser-known TypeScript concepts to improve your developer experience. The first concept is typeguards. Typeguards help TypeScript determine the type of a variable. By using typeguards, you can ensure that TypeScript knows the variable's type and can use the appropriate methods. Another concept is assertions, which allow you to tell the compiler that a certain scenario won't happen again. By using assertions, you can prevent errors and ensure the expected behavior of your code.

Hi everyone, today's talk is about Advanced Concepts of TypeScript. Some lesser-known TypeScript concepts that you can learn and then use it in your day-to-day projects that you can dramatically improve your developer experience and you know, the usage of TypeScript itself, so let's continue.

Before we start, a little bit intro about myself, I am Nikhil, I am a Senior Front-end Developer at Syncradi. It's a data automation platform, and we do a lot of TypeScript stuff in there. So I also talk a lot on conferences and meetups, I also write blog posts and technical articles in all things JavaScript, TypeScript and React. So yeah, that's a bit of an intro about myself, and let's just jump into the talk.

So the first concept is typeguards. So let's see what it is. So let's say you have a function that takes in any argument type, and if it is of certain type, we do some kind of operation with it. For example, I'm here checking if it's a string, and if it's a string I'm using some string properties and accessing that. Otherwise, it's not a string, then we do it differently. So in this example, I have a string function that checks for the type of the variable and returns that it's a Boolean, it's a true or false. So with this, if you have it like this, then the typescript won't know if the variable is actually a string. So we have this check, it returns true or false, but there is no way typescript knows the variable is string or not. It just knows it's true or false and comes here and doesn't know about the type of the variable, right? So for that, what you can do is you can do some kind of typecode check here, so you can use the is keyword in typescript, and explicitly state that the variable is string as a return type here. So now what happens is, once this check passes, once it returns true, then typescript surely knows that this variable is of type string and it can use all the string methods that it has. So that's the beauty of this typeguard. So let's see an example in the code, actual example. So this is before adding the typeguard. So now if you see, this returns Boolean, this returns Boolean. And once you come here, now the variable is any and even after it returns true, the variable is any. So you don't get all the type checks, you know, at the compile time. So now after we add the typeguard, now here the variable is any, but once this check passes and comes here, now the variable is string. So which means we are telling the typescript that it is a string and you can use all the string methods that it has and it will be easy for us to do all the string operations within this true condition.

So now let's look at the assertions, so this is the way to tell the compiler that this scenario won't happen again. We are asserting it that it won't happen again. So in this function I'm testing if the variable is string or not. So if it's not a string, we throw an error. So if it's a string then there won't be any errors. So we call this function here with the variable passing into it and if it's not a string then there won't be any error.

2. Type Guards in TypeScript

Short description:

This part explains how type guards work in TypeScript. By using type guards, you can ensure that a variable is of a specific type and use the appropriate methods and properties. Type guards are particularly useful when you want to throw an error if a variable is not of the expected type. This concept is powerful and can improve the developer experience.

Then this console log will happen, so basically after this function execution is done, the variable would be a string and we are asserting that it is a string. So now what happens is, this return type is asserts and once we pass this function call, we know that the variable is a string then we get the variable as string and we can use all the string properties. So this is more powerful if you don't want to do a condition, Boolean condition and you want to throw an error in your example function there when it's not a string, you want to throw an error. So once the error is not thrown then we know for sure, it's a string and use all the string properties. So that's with a type guard.

3. Generics in TypeScript

Short description:

This part explains the core concept of generics in TypeScript. Generics are essential for creating reusable types and making React components more generic. They allow you to create utility types and work with unions of keys. The keyof keyword in TypeScript returns all the keys of an object, which can then be used to assign values to variables. By understanding generics, you can parse the keys of an object and return all the types associated with it.

So now let's look at generics in TypeScript. So this is the core TypeScript advanced concept that you have to learn to do all sorts of reusable types and also if you are using React, make your React component more reusable and more generic. And if you're using normal JavaScript itself, you can use all sorts of utility types, you can create all sorts of utility types with the core concept of generics.

So before we get into that, I want to show you a few examples before we start the generics. So let's look at a couple of keywords in TypeScript. So let's say this is a person object with name, age, email, and student Boolean. And once you assign the person, this would be the values that you can give to a variable. And this keyof is a TypeScript keyword which returns all the keys of an object. So here all the keys are name, age, email, and student. So it will return all the union of all the keys. So once you assign that key to a variable, all you can see is all the value that you can assign to this variable is all the keys of the person object. So this is more powerful. You will be using it in all the upcoming examples.

So basically it will return all the unions. So you return age, name, email, and student, and you can assign values to it. So this one is similar to how you access a normal object. So you define the object, and you call the key of the object within it, and it will return the value. So in here, since it's a type, it won't return the value, but it will return the type of the key. So this object key. So the type of name is string. This will return string. This can also take in union of keys. So here I'm giving name, which is also a key, and age is also a key. So with these two, this will return both string and number, so because the name type is string, and age type is number. So it will return union of these two. So basically, so now with this, we can parse in the key of person also. So key of person is basically union of all the keys. Now we can parse in that, and return all the types that are part of that particular object. So this object has keys with string, number, and Boolean. That's what it will return.

4. Core Concepts of Generics

Short description:

This part covers the core concepts of generics, including the keyof keyword and using literals to save individual values as types. These concepts are essential for upcoming lessons on Generics.

So these three are core concept of knowing the generics and the other types that are coming up. So one is the key of, which returns the union of keys, and key of the object within this Axis Square Brackets will return all the types of the keys. This is for object. Now this is also useful for arrays. So let's say this is a string array, so if you don't have this const, this will be just a string array. But let's say the roles are, only we have these three roles, roles 0, 1, and 2. Now if you do a const, this will be read-only, so it won't be modifiable. Again, you can use this index signature to get the individual values. Basically these are all literals. Roles 0, 1, and 2 are literals. So using this, you can get the individual literals and save it in a type. So since it's a variable, JavaScript variable, we want to use a type of keyword to convert this JavaScript variable to a type. So that is what this does. And we're using the number index signature to get all the values and save it as a union of types. So this is also useful in upcoming lesson. So these are the main concepts that I want to show you before we jump into Generics.

5. Using State Machine and Generics

Short description:

Now let's look at a simple example of using a state machine. By using the keyof property and generics, we can restrict the initial state to only be A or B. This ensures that we get errors at compile time and resolve them before going to production.

Okay. Now let's look at a simple example of using a state machine. So state machine is something that has a bunch of states and also initial state to start with. So if you want to type this function, primarily what you will do is you will declare a type or interface and define the states.

So basically it takes a state object and also initial as an object. So this will be an object with states and that is basically a Javascript object. So it's an object type and it's an initial. That's a string. So we will type it like this.

This works fine but even we can restrict it more so that it's when we are using the make state it's more easier for us to implement it and use it. So what I mean by that is, since the state is, where properties are A and B, the initial state can only be A and B. It cannot be C, it cannot be D, right? Because the initial state is either of the states that is being defined.

So what you can do is, you can use the keyof property that we just, keyof keyword that we just discussed and we use generics like this. So we define, so we already had a config, we are defining the generic like this. This can be any type and any type. So whatever you pass in, that is passing to the state and the initial value would be keyof state. Basically, all the properties are the keys of the state that can be the initial value. And this is how you pass in a function. So you define the generic in the angular brackets here. And also once you define it, you can pass it down to the config type. So once you have that, now only possible values are A and B. So let's see how it works.

6. Using Generics to Restrict Variable Values

Short description:

By using generics, we can restrict the possible values of a variable and catch errors at compile time. This ensures that only valid values are used and prevents runtime errors. Generics are a powerful tool for improving code quality and reducing bugs.

Okay. So since I have a generic written here, if I just put the double quotes, the only possible value are A and B. If I give C, there will be an error thrown that's saying C is not part of A and B. That's because of the keyword we use. If we just have it as string, now anything is possible. You can just give C, then you'll be getting a type error in the runtime, because the C is not part of the available states. So with this restriction, we can be sure that we get the errors in the compile time and resolve it before going to the production. That's how generics can be used to restrict more types and then make the errors easily identifiable.

7. Making a List Component More Generic with Generics

Short description:

This part discusses how to make a list component more generic using generics in TypeScript. By defining a generic prop for items and another prop for rendering, the list component can be customized to render different types of items based on the color prop. The rendering logic and item definition are moved to the calling component, allowing for flexibility in rendering and item types. This use of generics enhances the reusability and flexibility of the list component.

So that's one example of generics. Let's take a look at another example with a React component. So this is a simple list component that we have. And this list takes in an item's prop and looks through it and renders the ID and name. So if you want to type it, that's what you usually do. You just list a prop type and the item's signature here, ID and name, and it's an array.

But what if we want to make this list component more generic? Let's say we want to make this list component such that the color of this component should define the type of the item itself and how the item should be rendered. So how we do that? So we do it like this. So now this list props takes in another generic, and takes in items and would be an array of item. But we also defined how the items will be rendered by the color itself. So we define another prop, render item, and which takes in, which is basically a function that takes an item and returns a JavaScript element. So basically the rendering part of it. And this is how you define it in the list.

So similar to the functions, we define the generic in the square, in angular brackets, and give the props and pass the item to it. So now we are just looping through and rendering the item here. But the rendering logic and the item definition would be part of the calling component. So where the component being called. So we are calling it in the form component here. So if you see here, we are defining the item's signature and this signature would be inferred in the render item. So whatever you pass, whatever signature you pass in the first items array, that signature will be maintained in the render item because we have the same t item type in the items render item argument itself. So if you see the example here, so here I have ID name and age. the items would be of the type ID name and age. So if I give this student true, now this will be, this will also be added here. So whatever the, so now the control is given to the calling component. So it's not in the declaration now, when the component is being created now. Now the control is given to the calling component. So now the caller can decide how it want to render and what are the items you want. It can be an item of students, it can be item of, you know, grocery lists and all those things, any kind of items. Now the list component is more generic by the help of the generic types.

8. Utility Types in TypeScript

Short description:

Now the list component is more generic by the help of the generic types. Now let's look at some utility types. TypeScript provides utility types like pick, omit, and partial. Pick allows you to select specific keys from a type, omit removes specific keys, and partial makes all keys optional.

Now the list component is more generic by the help of the generic types. Okay. Now let's look at some utility types.

So these are all, now, so previously we saw generic components and generic functions. Now the types can also be generic and basically can be used to create other, transform some particular type to other type and return that type. So basically, basically transformation of types. That's what the utility types are.

So there are a bunch of utility types built-in available utility types in TypeScript. So let's look at them one by one. So let's say we have a to-do object with title, description, and completer. And we want to define another type, another type to-do preview which only has title and completer. It doesn't have to have the description because we are just previewing the to-do, let's say.

So for that, TypeScript provides a utility type called pick, which basically takes in the base type, which is to-do here and pass in different keys. So here, the keys are title, description, and completer. So I'm passing in title and completer. So we are picking these two keys from this type and then running it here. So now this preview will have only title and completer. It won't have description. So this is a powerful utility that we can use. So this is similar to, we have a, similarly, we have omit utility type. This is just the opposite of pick. It just omits whatever the key that you pass in. But here, I'm just going to omit the description. So now it'll be title and completer. So these two are two powerful utilities that are used quite often. And there's also one more utility that is used quite often is the partial. So here, all the properties are required, title, description, and everything is required here. So what if I want to make a partial basically, make all the keys optional. So use the partial. So once you pass in the to-do, here you'll see all the properties have been marked as optional.

9. Partial, Read-Only, Parameters, and Return Types

Short description:

This part covers the concepts of partial, read-only, parameters, and return types in TypeScript. Partial allows optional fields in a function, while read-only makes properties unmodifiable. Parameters and return types can be obtained using utility types. The upcoming examples will demonstrate how to create custom utility types using these concepts.

So this optional to-do can be used in place of update, so if you want to update a particular to-do item, just the title field or just the completed field and rest of the other feeds are optional, you can just use this in the function.

So that's about the partial. Now let's do it read only. So now this to-do type can be modifiable. So if you assign it to a variable, that can be modified, you can modify title, description and competitor. But if you want it to be read only and unmutable, then you can use read only. Now this will mark all the properties are read only and can be assigned only once and cannot be modified. That's read only.

And now let's look at couple of things, parameters and return types. So let's say this is a function, right? So I'm getting a type of the function and storing it here using the type of keyword. Now I'm wanna get the type of the arguments that are being passed to this function. So using this parameters utility type you can get that. So it will return a tuple of type argument types. So here we have to do and it's up to do type and we have updated to do fields this of partial to do. And same way we can also get the return type using the return type utility. Now we will return, so here we are returning the exact to do itself. So we are getting title, description and computer. So this is more powerful. These utilities are more powerful. In the coming examples I'll show you how you can create your own utility type using these two concepts. Before that, custom utility types. Before that we want to see, we want to learn two concepts. One is the map types and conditional types. So first let's look at map types. Okay so this basically is a syntax for map types. So what it does is, we use the same key of keyword to get all the keys of a particular object type and this is like a iterator. So if you see foreign loop, right? So it will take all the keys individually and loop through it and then return something else. So that's what this, you can think of it as the same analogy. So this in, it's like a iterator. So this, all the individual key of the object will be stored in key, stored in K and you can use this K anywhere in the, in the right-hand side of the colon.

10. Making Objects Read Only and Partial

Short description:

So let's take an example. We have a person and want to make it read only. By using the key of person, we can loop through each key and return its type. To make it read only, we add the read only modifier to the map type, making all the keys read only. The same concept applies to partial, where we loop through the keys and make them optional. To make them required, we use the minus modifier. The same applies to non read only, where we use the minus modifier to make all the keys required.

So let's take an example. So we saw read only UDT type, right? Let's see, let's see how it is implemented. So we have a person and I want to make this person read only, read only person. How I'll do that is the same thing. I'll use K in key of person. So this will return all the key of this person type and I'll loop through one by one. And what I'll do is, I'll just return whatever the type it has. So I'm not modifying anything. So this will just, if I just do this and not add read only, it will just return the same thing that is in the person. So basically I'm just looping through it and then sending, so this key, person of key will just return string, person of age will just return number and since and so on. Now I'm just want to make it as read only, so I'll just add this modifier read only to this map type and this will have add read only to all the properties of the key, all the keys basically. So now this is read only. So once I assign it, I can't change it, change the age. So it will throw it as read only. Same thing for partial. So we are looping through it and saving all the keys individually and then making it as optional. And then, you know, this one is unmodified. We just return whatever the type is here. So now all the person keys are partial, optional basically. And if you want to make this as required, right? So now it's partial. So what if you want to make it as required? So we'll just use the minus in front of the modifier. So these are all modifiers. So the question mark, is read only, these are all called modifiers. So if we add a minus then it would be negating the initial purpose. So now we are passing partial, this is optional. Now we are using minus. Now this will be, all will be required. Same thing goes for non read only. So we already had read only person, this is read only. And if we add the minus in front of read only, now this would be, all would be required.

11. Understanding Conditional Types in TypeScript

Short description:

Now let's dive into conditional types. They are similar to ternary operators and are used to return non-empty types from a union of types. By using the extends keyword and the ternary operator syntax, we can check if a type extends null or undefined and return the appropriate result. Let's break down how it works. We start with a union type and individually check each type. If a type extends null or undefined, it returns never. Otherwise, it returns the original type. This allows us to filter out null and undefined types from a union and return only the non-empty types.

I mean, all will be non read only. So this is for map types.

Now it's conditional types. So conditional types. Okay. So this conditional types, is basically similar to a ternary operator. So, this is non empty.

Let's make, so the example I wanna show you here is, if we pass in, this is basically a utility that we wanna create using conditional types. What it does is, what it should do is, if we pass in multiple union of types, it would return the non empty types. So non empty types are non undefined and null types. So if it is string, Boolean, or number, then it will be returned, otherwise it won't be returned. So now, if the result will be string, if I just have Boolean, now the result would be string and Boolean. So basically non-empty types.

So for that, we use the extends keyword and use the question mark and colon, ternary operator syntax. So what it does is, whatever the union that we pass in, that would be in T, and we're checking if T extends, null, or undefined. So basically what it means is, it will see if the type that we pass in is null or undefined. If it is null or undefined, then it will return never, otherwise, if it's not, if it's non-null, then it will return whatever we pass in. String, Boolean, or number. So let's break down how it works. So this union type we have, this would be expanded something like this. So individually it'll be called. It's equal to Boolean for now. And after this, the string will be passed here. So the T would be string. So this would be extended basically. So in place of T, we have string, extends, null or undefined, never. Instead of T, we have string. Same goes for undefined, same goes for null. Now this check will happen. So string extends null or undefined, so no, it doesn't extend, so it will return string here.

12. Exploring TypeScript Conditional Types

Short description:

Undefined extends null or undefined, then it will return never. And same thing, null extends null or undefined, yeah, it extends, so it will return never. If it is an AND, right, if it's, let's say if it is intersection, now everything will be line. That's how we get non-empty types. This is the turn-in syntax that we have for conditional types.

Now this here, undefined extends null or undefined, yes. Undefined extends null or undefined, then it will return never. And same thing, null extends null or undefined, yeah, it extends, so it will return never. So the one cool thing about TypeScript is, of the never keyword is, it would be ignored by TypeScript if it is a union. So this is union. So now, the never will be ignored, and only the string will be written. So that's how we get string here. But if it is an AND, right, if it's, let's say if it is intersection, now everything will be line. It's similar to the AND operator and OR operator. Similar to zero or ones, right? So zero, zero, zero, and one is, AND one is zero, and one and zero OR one is one. That's what it means. So that's how we get non-empty types. So basically, this is the turn-in syntax that we have for conditional types. So let's see one other example.

13. Excluding Types with Conditional Types

Short description:

We can use conditional types to exclude specific types from a union. By declaring an exclude type and passing in the types we want to ignore, we can eliminate them from the resulting type. Conditional types allow us to check if the base type extends the exclude type and return the appropriate result. This powerful feature improves type safety and ensures that only the desired types are included.

So we have a list of statuses here. We want to exclude, so we declare an exclude type, it will type mistakes in the base type and a union of exclude types. So that will exclude whatever we pass in. Similar to omit, but this is for union types. So omit is for objects, and this is for union types. So we pass in the status, basically this entire thing, and we pass in the types that we want, the literal types that we want to ignore. So these two. So now this will return pending progression status. It will eliminate the negative statuses. So basically, it's the same syntax. So we check if the base type extends the exclude type. If it extends, then we return nothing. We will never basically, and if it's not in this possible types, then we return whatever the base type is. So it will look through individually, so it will check for pending and warning, pending and error, in progress warning, in progress error, all the condition would be checked, and it would be returned accordingly. So that's conditional types.

14. Combining Map Types and Conditional Types

Short description:

Now let's combine map types and conditional types to create a custom util type. We want to create a type similar to omit, but with a different functionality. Instead of providing the exact keys to omit, we want to specify the types of keys we want to eliminate. By using the map type, we can loop through the base object and check the type of each key. If the type extends the type to remove, we return the key itself. Otherwise, we return never. This allows us to convert the type to the actual keys and create the desired custom util type.

Now let's combine these two, map types and conditional types, and create a custom util type. So the util type that you want to create is similar to omit, but a little different. So omit takes in the key of, so this is what omit does. Type omit keys, omit person, comma, so it will take in all the person keys, let's say h, and it'll omit all these things and just return whatever the left, whatever the keys are left. Now what you want is, instead of giving the person, instead of giving the keys as a second argument, we wanna give the types that we wanna eliminate. So we don't wanna give the exact name of the key, but we wanna give the type of the key that you wanna eliminate. So we wanna eliminate here, Boolean and numbers, we don't want this, and we don't want this, we just want name and email. So once we give that it should return the string variables only. So how we do that? String keys only, so how we do that? So we just use the same signature that we have for omit, so omit takes in the main object as a base, and we also take in all the union types. And we use the same omit but with a different type, so basically omit expects keys as a second argument, right, that's what it expects, keys as second argument. But we are sending number, and we are sending that actual type as a second argument. So we want to convert this one to the number, we want to convert the type to the actual keys. So that's what is being done here. So we are using the map type to loop through the base object and get all the keys, and what I'm checking is checking the type. So this main object of key will return name or number based on what the key is, if it is name, then it's string. So it will be string extends the type to remove is number or Boolean, let's say string extends Boolean, it's not right, so it's not extend Boolean. Then we return the key itself, so we return name. So for name, it's a string, if it's extends, we return that, so in this example, let's say this is a string extends Boolean, it's not extends Boolean, so it'll be never, so that's what it's being here, and next is age. So age, a type of age is number, so this is number extends number or Boolean, yeah it extends, then it will return the number, the key itself, so it will be age. So I'm returning key, I'm not returning the type, I'm just returning the key directly. Again, email, the type of email is string, they will be never, then is student, so this one, type of is student is part of Boolean or number, yeah, then it'll return the type, basically is student, it'll return the key, basically is student, so this is what it returns after this is being executed. Again, now we want, we don't want this object. What we want is we want name and age to pass, right? So how we pass that? With this one, so if you remember this example we saw, this person can take in, this type, can take in keys of person, basically union of all the keys, right? So it'll return all the type of those. So if I pass in, let's say this is Boolean, right? It'll also return name, number and Boolean. What are all the type of these keys that'll be written. So in our example, it's a little bit different. It'll return the same thing, but what type we have? We have all the literal types, we have never, we have age as literal type, and never. And again, student is a literal type. So that's what being written. So this key of this is like this, and it will return all the actual types that's being given.

15. Custom Utility Types and Infer Keyword

Short description:

Actual types are being used to omit specific types and create custom utility types. The infer keyword extracts types and stores them in a different type for use in conditional types. We can pass a function type to check if it extends a specific function and infer the return type. These concepts enhance the power and flexibility of TypeScript's type system.

Actual types that's being in, so it will be after this, it will be never, age, never, and your student. Okay, that's what it will return. Now, if you know, in the previous example I saw, I told never can be, it would be ignored. So the age and the student would be left, and that's what being passed to omit. So omit, what we pass to omit? The base type and the age and the student. So if you pass that, then it will omit those two types, and will return, just name and email. So that's what is being done. So to recap, we created omit kind of utility type, but with actual types, not the keys, and it would omit the same way how it omits the actual keys. So this is more powerful if you combine with, that's how it's powerful to combine with the key map types and the condition types. So you can do much more like these utility types on your own.

Now let's look at infer keyword. So infer is also used along with the conditional types. Basically infer extracts out the types and store it in a different type and you can use it in either of the conditions that we have in the conditional types. So let's assume this is the function that returns name and age. And this is how the return type works. So we saw the return type, built-in utility type return type So this is how it's been implemented. So this is just the function signature. So consider, so basically you wanna pass in, so we wanna pass in the type of the function, right? So basically this t is basically a function. So we wanna check if this t is of the function type. So that's what this is. So for now consider this as any. Right, so what the function is, it function has arguments, any number of arguments of any type and it also returns any type of value. So that's how it done is. But while we are returning it, we are also inferring the value. So whatever the value being returned, we are inferring the type of that value and storing it in R. And we are returning it in the true condition basically. So if t extends this function, then we are returning the return type of the function. Otherwise we are not returning anything. We are taking never.

16. Infer and Template Return Types

Short description:

We can infer the return type of a function by using the type inference feature of TypeScript. By passing the function type, TypeScript can infer the return type based on the function's implementation. Similarly, we can infer the prop types of a component by using the component type utility in React. By checking if the passed property is of the component type, we can infer the prop type. This allows us to get all the prop types of a component. Lastly, let's explore template return types, which are used to define the return type of a function component. By specifying the input types and using index signatures, we can create more precise type definitions for our components.

We are taking never. So once we pass the type of the function, if it's a function, yeah, it's a function, getUser is a function and it will then further return type, so it will infer this and store it in R and we are returning the R in the true condition. Then if it's a function, then we return the return type of the function. So we'll return name and age. That's how the return type is being calculated.

So similarly, we can calculate the prop types of a component. So let's say this is a functional component and this is the prop type, name and age. And that's how the component is defined. So let's write it a type, all prop type, and which takes in a type p and we are checking for if this p is of component type. So React has this component type utility to check if it's a component. So instead of we defining the function, React also has its own component type checker. So we are checking that and while checking it, so this is how we pass the function type in React. So we are inferring the passed property. So similar way we inferred the return type, we are now inferring the prop type. So we're inferring that and saving it in p and if this condition is satisfied, you're returning the prop type otherwise, you are never. So now if you call it with the component, we just get all the prop types of the component. So this is about infer.

Okay. So on the final thing, this is a lot more exciting when I just learned this. So let's see what it is. Template return types. Okay, I think I have a slide also. Okay. So let's say we have a function. It's a react component, it is a tag component. And it takes in color, label, margin, and pass it down to the, and then render the tag of the label. So how would you type this? Let's say we have also have a status colors, which is a list of colors that we have. And the colors can contain either of these colors. So remember, ascons, we'll make this as read-only. And we can use this index signature, number index signature to get the individual colors.

17. Extending Color and Restricting Margins

Short description:

We can extend the color property to include any hash colors. The margin can be any string, but we want to restrict it to actual spacing properties like 12 pixel, 12 rem, one rem, two em. We use string templates to enforce these restrictions.

And there can be set individual types, literal types, and can be set to the color property. So this works. But what if we want to, and the margin also string. So what if you want to extend the color, not only to these four colors, but also any hash colors, right? How would you do that? So we want to have these four, and you want to have autocomplete for these four. And we also need to allow the users to give any other colors other than these four. So, and this margin is now a string. It can have any string, it can have just have green also. But we want to restrict the margins to have the actual spacing properties, right? Like 12 pixel, 12 rem, one rem, two em, and those spacing values. So how would you restrict that? So this is how we use the string template to restrict it. So this one we already had, we already had the four built-in, four status colors. But it can also have any string that contains, that starts with hash. So all the colors will start with hash. So all the string that we want to send to this color prop should also start with hash. That's how we restrict the colors.

18. Restricting Margins with String Templates

Short description:

Margins in CSS can be restricted using string templates in TypeScript. By defining the acceptable units and values within the backticks, you can enforce restrictions on the margin values. For example, margins should start with a number and end with pixel, rem, or em. If a value does not meet these requirements, TypeScript will throw an error. This feature enhances the developer experience by providing autocomplete suggestions and compile-time warnings for type-checking.

And what about the margins, right? So margins end with pixel, rem, or em. Those are the spacing units. So that's how it ends with. And what it starts with? It starts with a number. So it's like 12 pixel, one rem, two rem, like that. So it starts with a number. So within this backticks, you can give what you want to give. I want to read number, and I also want it to end with pixel, rem, or em. So now let's look at the example. It would be in, yeah, this one. So, now once you have that, let's say color. So if I do this, I'll get the autocomplete for the status colors, because that's all it's what we get. We can give either of one colors, or we can just give any color just starting with hash. But if you give something else that's not starting with hash, then we'll throw an error, saying it's not assignable to the property color. Same thing goes for margins. So margins is optional, that's why it's not throwing any errors. But once you start giving that, the value that you can give is, let's say, dot pixel. That you can give, because that's the accepted value. But if you try to give something, some A in between the friend, it'll throw an error saying it's not of type, because it should start with a number. And it ends with pixel, so if you give something else, then it will say, no, it doesn't end with that. So that's how powerful the string templates are, so you can restrict even more, so that when you are using the component, let's say, when you're using the tag component, then the user knows, okay, this is the exact value that this prop requires to make the component work. So the developer experience is even more improved with all these restrictions and compile-time warnings that you get doing all these type-checkings.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Day Berlin 2023React Day Berlin 2023
21 min
React's Most Useful Types
We don't think of React as shipping its own types. But React's types are a core part of the framework - overseen by the React team, and co-ordinated with React's major releases.In this live coding talk, we'll look at all the types you've been missing out on. How do you get the props type from a component? How do you know what ref a component takes? Should you use React.FC? And what's the deal with JSX.Element?You'll walk away with a bunch of exciting ideas to take to your React applications, and hopefully a new appreciation for the wonders of React and TypeScript working together.
Vue.js London 2023Vue.js London 2023
30 min
Stop Writing Your Routes
The more you keep working on an application, the more complicated its routing becomes, and the easier it is to make a mistake. ""Was the route named users or was it user?"", ""Did it have an id param or was it userId?"". If only TypeScript could tell you what are the possible names and params. If only you didn't have to write a single route anymore and let a plugin do it for you. In this talk we will go through what it took to bring automatically typed routes for Vue Router.
TypeScript Congress 2023TypeScript Congress 2023
31 min
Making Magic: Building a TypeScript-First Framework
I'll dive into the internals of Nuxt to describe how we've built a TypeScript-first framework that is deeply integrated with the user's IDE and type checking setup to offer end-to-end full-stack type safety, hints for layouts, middleware and more, typed runtime configuration options and even typed routing. Plus, I'll highlight what I'm most excited about doing in the days to come and how TypeScript makes that possible not just for us but for any library author.
React Advanced Conference 2021React Advanced Conference 2021
6 min
Full-stack & typesafe React (+Native) apps with tRPC.io
Top Content
Why are we devs so obsessed with decoupling things that are coupled nature? tRPC is a library that replaces the need for GraphQL or REST for internal APIs. When using it, you simply write backend functions whose input and output shapes are instantly inferred in your frontend without any code generation; making writing API schemas a thing of the past. It's lightweight, not tied to React, HTTP-cacheable, and can be incrementally adopted. In this talk, I'll give a glimpse of the DX you can get from tRPC and how (and why) to get started.
TypeScript Congress 2022TypeScript Congress 2022
10 min
How to properly handle URL slug changes in Next.js
Top Content
If you're using a headless CMS for storing content, you also work with URL slugs, the last parts of any URL. The problem is, content editors are able to freely change the slugs which can cause 404 errors, lost page ranks, broken links, and in the end confused visitors on your site. In this talk, I will present a solution for keeping a history of URL slugs in the CMS and explain how to implement a proper redirect mechanism (using TypeScript!) for dynamically generated pages on a Next.js website.

Add to the talk notes: https://github.com/ondrabus/kontent-boilerplate-next-js-ts-congress-2022 

Workshops on related topic

React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
React Advanced Conference 2022React Advanced Conference 2022
148 min
Best Practices and Advanced TypeScript Tips for React Developers
Top Content
Featured Workshop
Are you a React developer trying to get the most benefits from TypeScript? Then this is the workshop for you.In this interactive workshop, we will start at the basics and examine the pros and cons of different ways you can declare React components using TypeScript. After that we will move to more advanced concepts where we will go beyond the strict setting of TypeScript. You will learn when to use types like any, unknown and never. We will explore the use of type predicates, guards and exhaustive checking. You will learn about the built-in mapped types as well as how to create your own new type map utilities. And we will start programming in the TypeScript type system using conditional types and type inferring.
Node Congress 2024Node Congress 2024
83 min
Deep TypeScript Tips & Tricks
Workshop
TypeScript has a powerful type system with all sorts of fancy features for representing wild and wacky JavaScript states. But the syntax to do so isn't always straightforward, and the error messages aren't always precise in telling you what's wrong. Let's dive into how many of TypeScript's more powerful features really work, what kinds of real-world problems they solve, and how to wrestle the type system into submission so you can write truly excellent TypeScript code.
TypeScript Congress 2023TypeScript Congress 2023
131 min
Practice TypeScript Techniques Building React Server Components App
Workshop
In this hands-on workshop, Maurice will personally guide you through a series of exercises designed to empower you with a deep understanding of React Server Components and the power of TypeScript. Discover how to optimize your applications, improve performance, and unlock new possibilities.
 
During the workshop, you will:
- Maximize code maintainability and scalability with advanced TypeScript practices
- Unleash the performance benefits of React Server Components, surpassing traditional approaches
- Turbocharge your TypeScript with the power of Mapped Types
- Make your TypeScript types more secure with Opaque Types
- Explore the power of Template Literal Types when using Mapped Types
 
Maurice will virtually be by your side, offering comprehensive guidance and answering your questions as you navigate each exercise. By the end of the workshop, you'll have mastered React Server Components, armed with a newfound arsenal of TypeScript knowledge to supercharge your React applications.
 
Don't miss this opportunity to elevate your React expertise to new heights. Join our workshop and unlock the potential of React Server Components with TypeScript. Your apps will thank you.
TypeScript Congress 2022TypeScript Congress 2022
116 min
Advanced TypeScript types for fun and reliability
Workshop
If you're looking to get the most out of TypeScript, this workshop is for you! In this interactive workshop, we will explore the use of advanced types to improve the safety and predictability of your TypeScript code. You will learn when to use types like unknown or never. We will explore the use of type predicates, guards and exhaustive checking to make your TypeScript code more reliable both at compile and run-time. You will learn about the built-in mapped types as well as how to create your own new type map utilities. And we will start programming in the TypeScript type system using conditional types and type inferring.
Are you familiar with the basics of TypeScript and want to dive deeper? Then please join me with your laptop in this advanced and interactive workshop to learn all these topics and more.
You can find the slides, with links, here: http://theproblemsolver.nl/docs/ts-advanced-workshop.pdf
And the repository we will be using is here: https://github.com/mauricedb/ts-advanced
TestJS Summit 2023TestJS Summit 2023
78 min
Mastering Node.js Test Runner
Workshop
Node.js test runner is modern, fast, and doesn't require additional libraries, but understanding and using it well can be tricky. You will learn how to use Node.js test runner to its full potential. We'll show you how it compares to other tools, how to set it up, and how to run your tests effectively. During the workshop, we'll do exercises to help you get comfortable with filtering, using native assertions, running tests in parallel, using CLI, and more. We'll also talk about working with TypeScript, making custom reports, and code coverage.