prop-types is more of an injected tool that inspects data received from an API to ensure it has the expected type.
The expected onChange method must accept only one argument which must be a string. Each of them is a string value except onChange, which is a function.
The props are conditional such that when props.authenticated is false, props.profile is null and when props.authenticated is true, props.profile is the User type. With the above, we do not get an error because every data type is as expected. This is where the as-prop comes into play. What is Omit
, keyof Props- > doing here? In this post, I'll show you how to use the React techniques "render props" and "as-prop" and how to use them with TypeScript. Using TypeScript with React makes building React components faster with little to no uncaught errors.
However, prop-types is limited in the way you can specify data types compared to TypeScript. This Dot Labs proudly partners with enterprises interested in transforming their digital assets, upskilling their teams, and finding novel avenues for advanced integration. TypeScript is not the only way to ensure expected data types in a React application. Without IntelliSense, you can also verify the data types when you try building (npm run build) your React application. Now the parent controls how the items of the list are rendered. If we would include something like href: MyHrefType in our Props type and use as="a", then we would end up with an error when trying to pass any href: Type 'string' is not assignable to type 'never'.. For an authenticated user, the header would have the user's name, but if otherwise, we have the "Sign in" text. Omit excludes all prop types that we explicitly defined in our Props type from the result of React.ComponentPropsWithoutRef. You can find the finished code on GitHub. But imagine at another place we are either creating a similar list with trainers or a list which is containing more information about the Pokemon.
First of all, what is the React Render Props technique? They are quite similar, but work in different ways. Powered by .css-1wbll7q{-webkit-text-decoration:underline;text-decoration:underline;}Hashnode - a blogging community for software developers. React techniques like render props and the as prop enable us to build our own reusable, generic building blocks.
Render props are a way to achieve Inversion of Control (IaC). If it's a new project, you can create the project like so: The --template typescript installs dependencies that add support for TypeScript in your React application. That is not only true for React components, but for functions in general. If we would now pass as={"a"}, TypeScript autocomplete would suggest props from an tag, like href to us. Now we technically could pass an href from the parent component, but TypeScript would still complain. We can solve this with React.ComponentPropsWithoutRef, which results as the name already implies in all prop types of the As component excluding the ref prop. We keep you up to date with advancements in the modern web through events, podcasts, and free content. Combining the compiler tool and the IDE plug-ins gives a beautiful development experience when building JavaScript applications. This is generally a good approach but after a while, we can up with several components that are similar (e.g. You can further read the TypeScript Documentation to learn more. Often they have some similarities. Typing those generic components isn't that easy (at least this is how I feel about it). This Dot Media is focused on creating an inclusive and educational web for all. Some React frameworks (like NextJS and GatsbyJS) already have support for TypeScript out of the box, but for Create React App, you have a few things you'll need to do. In our case passing as="a" Omit, keyof Props- > would not include the href type anymore. Often we write React components that get bigger and bigger and at some point, we extract parts of it into separate components. We are ready to provide our expertise! It not only is a generic component not, but it also uses a TypeScript generic for the component props. Loves learning, building and teaching tech. // Pokemon is { name: string; url: string; }. This Dot Labs is a modern web consultancy focused on helping companies realize their digital transformation efforts. Here's how we define it with TypeScript: Note that the Post type does not have to be written multiple times in different files. There is still one caveat. For our Input component, we need the following props: defaultValue, onChange, placeholder and name. Instead of having the child component control the rendering of the list items, we reverse control and have the parent component control the rendering of the items. This is what a generic
component could look like: Note that the component now has no reference to Pokemon anymore. Using TypeScript, here's how we define the component: This way, our component is well defined. But if you pass "Next", you'll get this: So our Header component would be a bit complex. For example, prop-types cannot have interfaces, neither can they have the conditional props as we saw for the Header component. But these solutions aren't really reusable either. These techniques might be the topics for future articles. .css-y5tg4h{width:1.25rem;height:1.25rem;margin-right:0.5rem;opacity:0.75;fill:currentColor;}.css-r1dmb{width:1.25rem;height:1.25rem;margin-right:0.5rem;opacity:0.75;fill:currentColor;}7 min read, Subscribe to my newsletter and never miss my upcoming articles. Support Jannik Wempe by becoming a sponsor. You could uppercase the As prop in the first place but I personally find it quite awkward. Wouldn't it be nice to have some basic building blocks that can be reused in order to encapsulate such similarities? This is a great starting guide to learn TypeScript. Okay, let us create a truly reusable
component. This is how we can deal with that (this is the final version): We now pass all props besides items, renderItem and as to Component by using the spread operator for rest. There are also prop-types. TypeScript is a language that supercharges your JavaScript by giving your application's source codes type-checking. This StackOverFlow answer shows a detailed difference between them. We could also pass the single item in renderItem first, but in that case, we have to explicitly type it like renderItem={(pokemon: Pokemon) => (. Either because the component is getting too big or because we need parts of it somewhere else. At the end, we'll also look at the difference between prop-types and TypeScript. There's also more than you can do with TypeScript and React. It is even mentioned in the official React docs: The term render prop refers to a technique for sharing code between React components using a prop whose value is a function. This view is opinionated, but I quite agree with it. We use the generic Item type for the list of itemsand for the single item. While TypeScript has a lot of work (adding typings to almost everything) which can be strenuous, it makes developing React applications faster and with little fear of errors. TLDR; it deduplicates types. Here's how we'll define it: The Header component accepts two props: authenticated and profile. I often still prefer creating something like a which uses the
as a building block: Now we can easily create something like , or whatever or use the
directly. This is the component we are starting with: Note: I know that "Pokemons" isn't the plural, but I use the "s" to distinguish it from the singular. You can play with it, and violate expected types to see warnings. It indicates that the component is doing more than one thing it is violating the Single Responsibility Principle (SRP). A component with a render prop takes a function that returns a React element and calls it instead of implementing its own render logic. It can be a shared type exported from its own file and used anywhere. To learn, visit thisdot.co. For the above, we do something unacceptable. Also, it can be used in libraries that are compiled to JavaScript to be consumed by other applications. We now can pass the href prop of type MyHrefType again. Therefore we also learned how to type those generic components using TypeScript. Some of them utilize React context and composition (rather than inheritance). Our goal: We not only want to reverse control over how a single item is rendered but also for the HTML tag used by
. This is how we would use it to achieve the same output as in our initial example: If we pass items, which is of type Pokemon[] first, then the single item in renderItem is inferred to be Pokemon. Here's what the IntelliSense gives: In this component, we expect a post prop which is an object with the following properties: title, author, date and timeToRead. We could come with a which is also usable for trainers or add an optional prop to this component indicating that it should also render more details. These components will show how TypeScript can be used with React. But the techniques that I have shown here are very relevant and the simple example allowed me to focus on the techniques. Per default
renders an tag. Note: We can't just use the as prop like content because that would not be valid JSX. Non-native HTML tags have to be uppercased. In this article, we'll learn how to use TypeScript to compose React components. If we decide to render an outer a or img tag (which we probably won't in our example, but it is very relevant when dealing with the as-prop in general), then we can't pass required props like href or src to
.
In this article, we'll build four components: an Input, a Button, a Header, and a BlogCard component. What I love most about using TypeScript is that when I use it, I know exactly the structure of data to give to components and when I give a different structure, the IntelliSense immediately notifies me. Here are two things you'd notice on your IDE: As seen above, on entering quotes, the IDE already gives you the acceptable values. authenticated is true, but a different data type for profile is provided. It could also make it not render an outer tag at all by passing as like this
. It could render anything, no matter if Pokemon, trainers, or something else. That is nice, but it has a major flaw:
renders an outer and therefore we must return an - from renderItem in order to end up with valid HTML. Any amount is appreciated! When we pass one of the props to this component, if we use it somewhere, React (or rather TypeScript) knows that the other prop has the same type. Therefore, we get an error from IntelliSense. If a different data type is passed, the IntelliSense immediately yells, or the compile command on the terminal breaks. You're not just limited to single types as with prop-types, but you can also specify objects of objects or literally any pattern as an expected type. Not only TypeScript would complain, but also the props would not be forwarded to the within
. Let's change the data type of the placeholder property to see the warning we get: Our Button component will have the following props: value and processing like so: For the value prop, we're expecting either of three strings: "Submit", "Continue", or "Update", and the processing expects a true or false value. We've seen how the Intellisense provides error messages when types are not valid. It allows you to specify the exact structure of expected props for any component. We would have to remember that and we can't use it for more generic lists where we don't want to use an at all. Boolean flags like showDetails are often a code smell. Therefore our current usage in the parent doesn't have to change at all. This means, even in Vanilla JavaScript, you'll still be able to catch type errors. We can achieve that with the as-prop: Now the parent component can decide what HTML tag
renders. For example, using the Header component like so: Running npm run build for the above code gives the following error in the terminal: The examples above are in this Stackblitz project. For expert architectural guidance, training, or consulting in React, Angular, Vue, Web Components, GraphQL, Node, Bazel, or Polymer, visit thisdotlabs.com. placeholder, name and value (if provided) must be a string. It is just a list of Pokemon which is rendering some links nothing special here. As you'd notice, "Next" is not included in the expected strings for value. Having an IntelliSense makes the development faster as you can easily see the warnings and errors in your IDE. Do you want to have the job done? Now our
is truly generic and reusable for a lot of cases. If you use TypeScript in your application (without doing "illegal" kinds of stuff like passing any everywhere), you'll never have an uncaught error of "x as undefined". There are many other techniques for creating reusable React components. Now let's say we added an extra property to the Post type in the blog posts like so: In the components examples above, we've seen how to add typings to the component's properties such that a parent components using such components would know exactly what the component wants to receive. some kind of list, card, or whatever). These techniques are widely used in libraries like Chakra UI and headless UI which I really enjoy using. To continue with this article, a fair knowledge of TypeScript is required. I admit that this
component is a contrived example as it seems to offer not that many benefits compared to our initial solution. If it's an existing project, then you would need to install the Typescript dependencies: With these, you can rename .js files to .tsx to allow TypeScript codes. Now, items must be of type Pokemon[]. This means, if a user is authenticated, a profile object must also be provided.