Latest Tutorials

Learn about the latest technologies from fellow newline community members!

  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL

How to Use Redux with TypeScript

TypeScript can provide type-safety for reducers in your application, improves the documentation of your code, and overall improves long-term maintainability. Also, Redux officially recommends using static typing in their docs. Let's re-implement a todolist app. It is a basic example that many are familiar with, so it will be easier to focus on TypeScript part of a deal. Create a new React app using Create React App with the TypeScript template: First of all, we need to add dependencies to our app. We're going to need redux , react-redux, and types for the last one. We won't need an additional types package for Redux since it has its own type annotations. When it's done, we can create a state. Define types for the store state and todo items: Then, create a default value for the store: When the state is created, we can create actions that will change the state. To be short, we will have only 2 actions that will add a new todo or mark them complete or incomplete. When typings are completed, we create the actions themselves: Now we can add a reducer for todos: If we had more than one reducer we would want to combine them using the combineReducers function: It would allow us to create a single store instead of many for each feature. When everything is done, we can create a store: The react-redux package has a Provider component that lets you connect your components with the store. Finally, when everything is ready, we can use our actions in components. react-redux has a set of hooks that can access the store and dispatch actions. The useDispatch hook lets us fire actions: For accessing the state value, react-redux has a useSelector hook. It is best to use useSelector than useStore to avoid unnecessary re-renders. This is the basics of typing the react-redux application. There are additional tricks that allow you to throw errors when an unknown action has been fired or to make type-checking even stricter. But we will cover them in a different post later.

Setting Up Dependency Injection with TypeScript in an Object-Oriented Way

The last letter in SOLID is a Dependencies Inversion Principle . It helps us decouple software modules so that it is easier to replace one module with another. The dependency injection pattern allows us to follow this principle. In this post, you will learn what dependency injection is, why it is useful, when to use it, and what instruments and tools can help frontend developers use this pattern. At the end of this post, you will learn what dependency injection is useful for, how to set it up in your TypeScript application, in what cases you're going to need it, and which tools can make it easier to do. We assume you know the basic syntax of JavaScript, and familiar with basic concepts of object-oriented programming such as classes and interfaces. Although, you don't need to know the TypeScript syntax for classes and interfaces in detail, since we will look at it in this post. In general, the concept of a dependency depends on a context, but for simplicity, we will call a dependency any module which is used by our module . When we start using a module in our code, this module becomes a dependency. Without going into academic definitions, we can compare dependencies with function arguments. Both are used in some way, both affect the functionality and operability of software that depends on them. In the example above the random function takes 2 arguments: min and max . If we don't pass one of them, the function will throw an error. We can conclude that this function depends on those arguments. However, this function depends not only on those 2 arguments but on the Math.random function as well. This is because if Math.random isn't defined, the random function also won't work—so Math.random is a dependency too. We can make it clearer if we pass it as an argument into our function: Now it is clear that random function uses not only min and max but some random numbers generator as well. This kind of function will be called like that: ...Or if we don't want to manually pass Math as the last argument every time, we can use it as a default value in function arguments declaration: Of course, it is not yet “canonical”, it is very primitive and it has to be done by hand, but the key idea is the same: we pass to our module everything it needs to be working . The code changes in the random function example may seem unnecessary. Indeed, why would we extract Math into an argument and use it like that? Why wouldn't we just use it as it were, in the function body? There are 2 reasons for that. When a module explicitly declares all the things it's going to need, this module is much simpler to test. We see what needs to be prepared to run the test right away. We know what affects this module's functionality and, if needed, can replace it with another implementation, maybe even fake implementation . Objects that look like a dependency but do something different are called mock objects . When running tests, they might keep track of how many times some function was called, how a module's state changed, so that later we could check the results with expected. They, in general, make it simpler to test a module, and sometimes they are the only way to test a module. This is the case with our random function—we cannot check the final result that this function should return since it is different every time this function is called. However, we can check how this function used its dependencies and derive the results from that. Replacing a dependency while testing is only a special case. In general, we may want to replace a module with another for any reason. And if a new module behaves the same way as the previous, we can do that without any problems: It is very convenient when we want to keep our modules as separate from each other as we can. However, is there a way to guarantee that a new module contains the random method? (It is crucial since we rely on this method later in function random .) Apparently yes, there is. We can do it with interfaces . An interface is a functionality contract. It constraints of a module behavior, what it must do, and what it must not. In our case, to guarantee random method existence we can use an interface. To fixate that a module should have a random method that returns a number, we define an interface: To fixate that a concrete object must have this method, we declare that this object implements this interface: Now we can declare that our random function takes as the last argument only a object that implements the RandomSource interface: If we now try to pass an object which doesn't implement the RandomSource interface, TypeScript compiler will throw an error. At a first glance, this might seem like overkill. However, this helps us achieve many perks. When we design a system beforehand we tend to use abstract contracts. Using those contracts we design our own modules and adapters for 3-party code. This unlocks the ability to interchanges modules with others without changing the whole system but only a changing part. Especially it becomes handy when modules are more complex than those in the examples above. For instance, when a module has an internal state. In TypeScript, there are many ways to create a stateful object, such as using closures or classes. In this post, we will use classes . As an example, we will take a counter. As a class, it would be written something like this: Its methods give us a way to change its internal state: It's getting though when some objects like this one depend on others. Let's assume that this counter should not only keep and change its internal state but also log it into a console every time it changes. There we see the same problem as we saw at the beginning of this post. Counter uses not only its state but also another module— console . Ideally, it should also be explicit, or in other words, injected . We can inject a dependency in a class using a setter or a constructor. We will latter. A constructor is a special method that gets called when an object is being created. You would usually specify all the actions to perform at the object initialization. For example, if we want to log a greeting into a console when an object is created we can use this code: Using a constructor we can also inject all the required dependencies. We want to “teach” a class to work with dependencies the same way as functions from examples before. So, our class Counter uses the method log of a console object. That means that this class expects as a dependency an object that has a method log . It doesn't matter whether it will be a console object or another, the only condition here is for the object to have a log method. When we want to fixate the behavior we use interfaces, so the Counter 's constructor should take as an argument an object that implements an interface with method log : To initialize a class instance we would use this code: ...And if we would want to, let's say, alert instead of logging into a console, we would change the dependency object this way: Right now our Counter class doesn't use any implicit dependencies. That's good, however, this injection is not convenient. In reality, we would want to automate it. There is a way to do that, and it's called a DI-container . On the whole, a DI-container is a module that does only one thing—it provides dependencies to every other module in a system. Container knows exactly which dependencies a module needs, and injects them when needed. Thus we free other modules of figuring out this stuff, and the control goes to a special place. This is the behavior that is described in SRP and DIP principles of SOLID. In practice for this to work, we need another layer of abstraction—interfaces. (Thus TypeScript, JavaScript doesn't have those.) Interfaces here are a link between different modules. A container knows what kind of behavior a module needs, knows which modules implement it, and when creating an object it will provide access to them automatically. In pseudocode it would look like this: Despite the fact that this code is not real, it is not so far from reality. There is a great tool for TypeScript, that does exactly the thing we described above. It uses generic-functions to bind an interface and implementation. The code uses this tool would look like this: Now, if we want to access a dependency in our Counter class, we can do that by writing this: The last line registers the Counter class in the container itself. That way the container will know that Counter can ask for dependencies from it. First of all, we can now change the implementation of the whole project by changing only one line . For example, if we want to change the logger implementation in every place that uses it, it is enough to change only the module registration: Also, we don't pass the dependencies by hand, we don't have to keep the order of dependencies anymore, so modules become less coupled . This container's killer-feature is that it doesn't use decorators (on the contrary for let's say Inversify.js). Type-parameters registration makes it easier to distinguish infrastructure code from the production code. singleton and transient here are lifestyle types of an object. registerSingleton creates a single object once, which later will be passed in every place that requires it. And registerTransient creates a new object every time. Transient-objects are used for dealing with some unique entities like network requests—objects that should be created from scratch every time. Singleton-objects are used when we can use the same instance, for example, for logging. I wrote a small application , which alerts a unique ID of a click, its time, and a position on the screen when a user clicked. Also, it logs into a console “Hello world” every 5 seconds. It is quite dumb, but that's not the point :–) I want to show using it how we can use DI with TypeScript on the frontend. (There is also the source code .) We will use @wessberg/di as a container and @wessberg/di-compiler to make the magic happen at compile time. We don't want to overload the client code with lots of infrastructure code. This toolchain is the best I tried, it doesn't increase the build bundle much and is very convenient to use. the entry point's code is: All the interesting things are in the class constructor. There we ask a container for all the dependencies. Those are dependencies that the main module depends on: To get access to date and time, we use BrowserDateTimeSource which is registered as the implementation for DateTimeSource . Notice that when we ask for this dependency we use an interface because that's the key point—everything should depend on an abstraction. A unique ID generator is an adapter for nanoid . Notice that we refer to this 3-party module only once, when registering the adapter. This is handy if we decide to replace nanoid with another UUID generator. An event handler uses a generic-interface EventHandler<MouseEvent> . It is important to request exactly this dependency from a container later. If we pass another type-parameter in this interface the container will search for a module that is registered with that parameter. It is convenient when we work with similar object types. This one we have already seen :–) Those are dependencies of dependencies, as, for instance, env in the ClickHandler class or adaptee in the IdGenerator . It doesn't matter for a container what level a dependency of. A container provides all the dependencies with no problems. (Unless there are cyclic dependencies, but that's a topic for another post :–) The main issue with DI-containers is that when you're using it you have to register all the dependencies there. It sometimes is not as flexible as we might want. Another downside is that access to the entry point becomes available only from the container and it might seem a bit dirty. (Although, for the entry point it is acceptable.)

I got a job offer, thanks in a big part to your teaching. They sent a test as part of the interview process, and this was a huge help to implement my own Node server.

This has been a really good investment!

Advance your career with newline Pro.

Only $30 per month for unlimited access to over 60+ books, guides and courses!

Learn More

    Deploying Your React App & API to the Cloud

    After you have taken your first step with React on your web-dev journey, you'll eventually reach a point where you'll need to deploy something to the World-Wide-Web for everyone to see! The  create-react-app  team has already created some amazing documentation on  deploying a React app as a static web site using Heroku . However, if you have ever wondered how you would deploy your React app with some bundled API, this tutorial is just for you. The first step is to sign up for  Heroku . Heroku offers a  Free  plan, which is perfect if you are just starting out as a web-developer. The next step is to build your React app. If you used  create-react-app  this will be super simple! Just run  npm run build  in your terminal at the root of your React app directory. This process should yield a directory with a production build of your app. Inside, you'll find your minified HTML, CSS, JavaScript, and some media files if you have images in your app. Next, you'll need to tell your backend to serve your React app when the user hits a specific route. If you are using Node and Express, this can be achieved in two lines of code: Finally, the last step is to deploy your React app with some bundled API to Heroku. Just log into Heroku, create a new application, and pick the region of the world you want your application to be deployed in. If you navigate to the dashboard of your newly created Heroku application and select the  Deploy  tab. You can now connect your Heroku app with an actual GitHub repo hosting your application's source code. Once connected, you can configure Heroku to automatically deploy your application whenever you push an update to a specific branch in your repo! And that's it! Hopefully you have found this interesting & helpful. If you would like to see how this is integrated into a fullstack application created using React, GraphQL, Node, and TypeScript, checkout our  TinyHouse Masterclass.

    Thumbnail Image of Tutorial Deploying Your React App & API to the Cloud

      Autogenerate TypeScript Definitions for GraphQL

      If you have completed our  Free GraphQL Course , you would have built your own GraphQL API using Apollo, Node, and TypeScript. 🎉🎉🎉 Hopefully, you have taken this a step further and tried to create some sort of client application to consume your API. If so, you probably needed to write a couple of TypeScript definitions for your GraphQL queries & mutations on the client side. This isn't too bad for a simple API like the one from our free tutorial. However, in a large scale production application, there could be hundreds of GraphQL endpoints & types. Take a look at  GitHub's v4 GraphQL API , no joke, there is almost 1000 endpoints & types. Creating TypeScript definitions for those would be a nightmare! Not only that, changes in the server means you will have to find and update your TypeScript definitions over and over again. If you think about it,  every  GraphQL API is already type defined! Wouldn't be cool if there is something out there that can translate GraphQL types into TypeScript automatically? And yes there is! 🥁🥁🥁 Ladies & gentleman, let me introduce to you,  Apollo CLI . 🥁🥁🥁 The  Apollo CLI  is a robust command line interface that allows for a variety of different things such as schema validation, generate static types, and etc. And we'll use this amazing tool to autogenerate TypeScript definitions from our GraphQL API. To use the Apollo CLI, we can install it globally with the following command: There are two commands we are especially interested in: We'll set up both of these steps as two separate script commands in our application's  package.json  file. We'll label these scripts  codegen:schema  and  codegen:generate . To download the schema, we'll need to run the  apollo client:download-schema  command and specify the options we would want. In our case, we'll specify the single minimum option we need - the endpoint and pass in the value of our local GraphQL endpoint ( http://localhost:9000/api ). We'll run the newly created  codegen:schema  script in our command line. After a brief period, we'll notice success messages that state  Loading Apollo Project  and  Saving schema to schema.json . If we look at the root of our  client/  directory, we'll notice a  schema.json  file be generated that represents our entire GraphQL schema! With the GraphQL schema available in our app, we can now look to generate the static types for the  listings  query and  deleteListing  mutation in our GraphQL API. This can be done with the Apollo CLI  client:codegen  command. We'll specify a few options as we set up the script. The first option we'll add is the  --localSchemaFile  option, which is used to specify the path to the schema file in our  client/  directory. Since the  schema.json  file is in the root of our project, the value for the  --localSchemaFile  option will be  schema.json . The second option we'll specify is the  --includes  option which is used to state the files that contain the GraphQL operations we'll want to generate static types for. In my case, all of my GraphQL requests live in TypeScript files within my  src/  folder. There fore, I'll specify a value of  src/**/*.tsx  which entails looking through our entire  src/  folder and for any files that have the  .tsx  file extension. The final option we'll specify is the  —-target  option, which is required and allows us to specify which code generator we'd like to use.  swift ,  flow ,  scala  are all different options but in our case we're interested in the  typescript  option. We'll have the above  apollo  command as part of the  codegen:generate  script command in our application. Upon success, we'll see the  Loading Apollo Project  message followed by  Generating query files with 'typescript' target - wrote 3 files . By default, the Apollo code generator creates static typings for the GraphQL documents it finds in  __generated__/  folders. For example: If we take a look at one of these auto generated files, we can see TypeScript interfaces for the return data and input variables! And that's it! Hopefully you have found this interesting & helpful. If you would like to see how this is integrated into a fullstack application created using React, GraphQL, Node, and TypeScript, checkout our  TinyHouse Masterclass .

      Thumbnail Image of Tutorial Autogenerate TypeScript Definitions for GraphQL

        Adding Custom Domains to Heroku

        In one of our previous tutorials, we showed you how to deploy an application to Heroku. In this tutorial, we will show you how to configuring a custom domain for you newly deployed application! First, we will need to register a custom domain. There are many domain registration companies that offer this service (for example GoDaddy, HostGator, etc.). The one we will be using in this tutorial is Google Domains. However, the steps below can be applied to any other registrars. From your Heroku application’s dashboard, select the   Settings   tab. On the settings page, navigate to the  Domains  section and click the  Add domain  button. Next, enter your domain into the prompt, like so: Note: the  www  characters are required! Once you’ve added your domain, copy the  DNS Target  provided by Heroku. You will need to provide this to your domain registrar in the following step. Next, you will need to tell your domain registrar that your application is running at this exact DNS target provided by Heroku. To do this, go to your domain registrar's dashboard and create what is known as a  CNAME  record. Here is how it's done in Google Domains. On the  DNS  page, scroll to the  Custom resource records  section. Enter  www  inside the first input. Next, select  CNAME  from the drop-down. Skip the input labelled  TTL . Inside the last input, paste in the  DNS Target  from Heroku. Click  Add . You should get something that looks like this: Just one last step to complete! If you try to access your application using your custom domain,  www.your-domain.com  works, but  your-domain.com  does not. However, when you enter  google.com  into your browser, you are automatically redirected to  https://www.google.com . Similarly, when you enter  youtube.com  into your browser, you are automatically redirected to  https://www.youtube.com . To replicate this behaviour, you will need to setup a subdomain forward! Here is how it's done in Google Domains. On the  DNS  page , scroll to the  Synthetic records  section. Select  Subdomain forward  from drop-down menu. Inside the  Subdomain  input, enter the "at" symbol:  @ . Next, in the  Destination URL  input, type your domain name like so: Click  Add . And you should get something that looks like this: And that is it. You should be able to access your application using both  www.your-domain.com  and  your-domain.com !!! Hopefully you have found this interesting & helpful. If you would like to see how this is integrated into a fullstack application created using React, GraphQL, Node, and TypeScript, checkout our TinyHouse Masterclass .

        Thumbnail Image of Tutorial Adding Custom Domains to Heroku