Categories
JavaScript TypeScript

Introduction to TypeScript Generics — Classes

One way to create reusable code is to create code that lets us use it with different data types as we see fit. TypeScript provides the generics construct to create reusable components where we can work with a variety of types with one piece of code. This allows devs to use these components by putting in their own types. In this article, we’ll look at the many ways to define generic classes and also validate properties by defining interfaces and the extends keyword and also force the code to only accept property names that are in an object by using the keyof keyword.

Defining a Generic Class

To define generic classes in TypeScript, we put the generic type marker in between the <> after the class name. We can have more than one type marker separated by a comma. Also, we can use the same type marker to mark the type of the function to let us change parameter and return type of methods within our class. For example, we can write the following code to define a generic class with a single generic type marker:

class GenericPerson<T> {    
  name: T;  
  getName: (name: T) => T;  
}let person = new GenericPerson<string>();  
person.name = 'Jane';  
person.getName = function(x) { return x; };

In the code above, we passed in the string type inside the <> . We can also change to any other type we want like number, boolean, or any interface like in the following code:

class GenericPerson<T> {    
  name: T;  
  getName: (name: T) => T;  
}let person = new GenericPerson<number>();  
person.name = 2;  
person.getName = function(x) { return x; };

We can also insert multiple types within the same class as in the following code:

class GenericPerson<T, U> {    
  name: T;  
  getName: (name: U) => U;  
}let person = new GenericPerson<string, number>();  
person.name = 'Jane';  
person.getName = function (x) { return x; };  
person.getName(2);

In the code above, T and U may or may not be different types. As long as we put them both in and that we pass in and assign data with the types we specified in the class definition, then the TypeScript compiler will accept it. The examples above are only useful for a limited amount of cases since we can’t reference any properties in our class definition since the TypeScript compiler doesn’t know what properties T or U contains.

To make the TypeScript compiler aware of the properties that may be used in our class definition, we can use an interface to list all the properties that can be used with the class and the use the extends keyword after the generic type marker to denote the that type may have the list of properties that are listed in the interface. For example, if we want to have different complex types in our class methods, we can write something like the following code:

interface PersonInterface {  
  name: string;  
  age: number;  
}

interface GreetingInterface {  
  toString(): string;  
}

class GenericPerson<T extends PersonInterface, U extends GreetingInterface> {    
  person: T;  
  greet(greeting: U): string {  
    return `${greeting.toString()} ${this.person.name}. You're ${this.person.age} years old`;  
  }  
}

let jane = new GenericPerson();  
jane.person = {  
  name: 'Jane',  
  age: 20  
};  
console.log(jane.greet('Hi'));

In the code above, we defined 2 interfaces, the PersonInterface and the GreetingInterface to denote the properties that can be referenced with T and U respectively. In the PersonInterface, we have the name and age properties listed so we can reference these properties for data with type T. For the data with U type we can call the toString method on it. Therefore, in our greet method, we can call toString on greeting since it has the U type and since this.person has the T type, we can get the name and age properties from it.

Then after the class definition, we can instantiate the class and then set values for the name and age properties on the jane object that we created. Then when we run console.log on jane.greet(‘Hi’) then we should see ‘Hi Jane. You’re 20 years old’ since we set the values for jane.person.

We can also put in the types explicitly when we instantiate the object to make the types more clear. Instead of what we have above, we can change it slightly and write the following code:

interface PersonInterface {  
  name: string;  
  age: number;  
}

interface GreetingInterface {  
  toString(): string;  
}

class GenericPerson<T extends PersonInterface, U extends GreetingInterface> {    
  person: T;  
  greet(greeting: U): string {  
    return `${greeting.toString()} ${this.person.name}. You're ${this.person.age} years old`;  
  }  
}

let jane = new GenericPerson<PersonInterface, string>();  
jane.person = {  
  name: 'Jane',  
  age: 20  
};  
console.log(jane.greet('Hi'));

The only difference is that we add the <PersonInterface, string> after new GenericPerson. Note that we can add interfaces or primitive types in between the brackets. TypeScript only cares that the type has the methods listed in the interface we defined. Now that the types are constrained by these generic types, we don’t have to worry about referencing any unexpected properties. For example, if we reference something that doesn’t exist like in the following code:

interface PersonInterface {  
  name: string;  
  age: number;  
}

interface GreetingInterface {  
  toString(): string;  
}

class GenericPerson<T extends PersonInterface, U extends GreetingInterface> {    
  person: T;  
  greet(greeting: U): string {  
    return `${greeting.foo()} ${this.person.name}. You're ${this.person.age} years old`;  
  }  
}

let jane = new GenericPerson<PersonInterface, string>();  
jane.person = {  
  name: 'Jane',  
  age: 20  
};  
console.log(jane.greet('Hi'));

We would get “Property ‘foo’ does not exist on type ‘U’.(2339)” since we didn’t list foo in our GreetingInterface .

Constraining Retrieval of Object Properties

TypeScript also provides a way to let us get the properties of an object safely with generics. We can use the keyof keyword to constrain the values of the than an object can take on to the key names of another object. For example, we can use the keyof keyword like in the following code:

function getProperty<T, K extends keyof T>(obj: T, key: K) {  
  return obj[key];  
}

let x = { foo: 1, bar: 2, baz: 3 };console.log(getProperty(x, "foo"));

In the code above, we constrain the generic marker K to only accept the keys of whatever object is passed in to obj as the valid values of key since K has the extends keyof T marker after K . This means that whatever keys the T type has, then the keys are valid values for K . With code like the ones above, we don’t have to worry about getting values for properties that don’t exist. So if we pass in a key name that doesn’t exist in obj , like in the following code:

getProperty(x, "a");

Then the TypeScript compiler will reject the code and give the error message “Argument of type ‘“a”’ is not assignable to parameter of type ‘“foo” | “bar” | “baz”’.(2345)“. This means that only 'foo' , 'bar' and 'baz' are valid values for key since it has the type K , which has the extends keyof T marker after it to constrain the valid uses to be the key names of obj .

We can define a generic class easily with TypeScript. To define generic classes in TypeScript, we put the generic type marker in between the <> after the class name. We can have more than one type marker separated by a comma. Also, we can use the same type marker to mark the type of the function to let us change parameter and return type of methods within our class. Also, we can use the extends keyword to define the properties that can be referenced with our data marked by generic types. We can use the keyof keyword to constrain the values of the than an object can take on to the key names of another object.

Categories
Angular JavaScript

A guide to styling Angular Components

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we’ll look at ways to style Angular components.

Component Styles

Angular components are styled with CSS. Everything about CSS applies to Angular components.

We can also compound component styles with components, which allows for more modular designs than regular stylesheets.

Using Component Styles

We can define CSS styles in addition to template content in our components.

One way to do it is to use the styles property in our component.

For example, we can write that as follows:

app.component.ts :

import { Component } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styles: [  
    `  
      h1 {  
        font-size: 50px;  
      }  
    `  
  ]  
})  
export class AppComponent {}

app.component.html :

<h1>Foo</h1>

Then we should see ‘Foo’ that’s 50 pixels big on the screen.

Styles in styles isn’t inherited by any components nested within the template or any content projected into the component.

We can use CSS class names and selectors that make the most sense in each component.

Class names and selectors don’t collide with class names and selectors in other parts of the app.

Changes elsewhere in the app don’t affect changes in the current component.

We can co-locate the CSS code of each component with TypeScript and HTML code of the component, which makes the project structure cleaner.

Also, we can change or remove CSS code without searching through the whole app to find where else the code is used.

Special Selectors

Angular apps can use special selectors to style components.

They come from selectors for styling the shadow DOM.

:host

The :host pseudoclass selector targets styles in the element that hosts the component rather than the elements inside the component’s template.

For example, we can write:

:host {  
  display: block;  
  border: 3px solid black;  
}

We can style host styles with the given selector by using the function form as follows:

:host(.active) {  
  border-width: 1px;  
}

:host-context

We can use :host-context to apply styles on some condition outside of a component’s view.

It works the same way as the :host selector, which can use the function form.

It’ll look in ancestor components all the way up to the document root for the given selector.

For example, we can write:

:host-context(.theme-light) h2 {  
  background-color: #fff;  
}

/deep/, >>>, and ::ng-deep (Deprecated)

We can use /deep/, >>>, and ::ng-deep to apply styles to outside of the component by disabling view encapsulation for the rule.

For example, we can write:

:host /deep/ h3 {  
  font-weight: bold;  
}

Style Files in Component Metadata

We can set the styleUrls to point to a stylesheet file to style a component.

For example, we can write the following:

app.component.ts :

import { Component } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {}

app.component.css :

h1 {  
  font-size: 50px;  
}

app.component.html ;

<h1>Foo</h1>

In the code above, we put our styles in app.component.css and point our styleUrls to that file in app.component.ts .

We can specify more than one style file in both styles and styleUrls .

Template Inline Styles

We can put style tags in our templates to add template inline styles.

For example, we can write:

app.component.html :

<style>  
  h1 {  
    font-size: 50px;  
  }  
</style>  
<h1>Foo</h1>

The code above will set the h1’s font size to 50 pixels.

Template Link Tags

We can add link tags to templates to reference other styles.

For example, we can write the following code:

app.component.ts :

import { Component } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html"  
})  
export class AppComponent {}

app.component.html :

<link rel="stylesheet" href="./app.component.css" />  
<h1>Foo</h1>

We see that we removed the styleUrls from AppComponent and put a link tag to reference the CSS file.

The styles should be applied from the file we referenced in the link tag.

CSS @imports

We can import CSS files with the standard CSS @import rule.

For example, we can write the following code:

foo.css :

h1 {  
  font-size: 50px;  
}

app.component.css :

@import url("./foo.css");

app.component.html :

<h1>Foo</h1>

External and Global Style Files

We can add external global styles to angular.json to include them in the build.

To register a CSS file, we can put in the styles section, which is set to styles.css by default.

Non-CSS Style Files

Angular CLI supports building style files in SASS, LESS or Stylus.

We can specify those files in styleUrls with the appropriate extensions (.scss, .less, or .styl) as in the following example:

app.component.scss :

h1  {  
  font-size: 70px;  
}

app.component.html :

<h1>Foo</h1>

View Encapsulation

We can control how view encapsulation works by setting the encapsulation setting in out component code.

The following are the possibilities for view encapsulation:

  • ShadowDom view encapsulation uses the browser’s native shadow DOM implementation. The component’s styles are included in the Shadow DOM
  • Native view encapsulation uses the now deprecated version of the browser’s native shadow DOM implementation
  • Emulated is the default option. It emulates the behavior of the shadow DOM by preprocessing and renaming CSS code to effectively scope the CSS to the component’s view
  • None means that Angular does no view encapsulation. The styles are added to global styles.

We can change the encapsulation setting as follows:

app.component.ts :

import { Component, ViewEncapsulation } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.scss"],  
  encapsulation: ViewEncapsulation.Native  
})  
export class AppComponent {}

Conclusion

We can use CSS to style Angular components. In addition, it supports SASS, LESS, and Stylus for styling.

By default, the scope of the styles is local to the component. However, we can change that to be different.

We can also include inline styles in our templates via the style and link tags.

Categories
JavaScript React

Introduction to React Hooks

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at how to use React hooks to make function components smarter.

Introducing Hooks

Hooks are introduced with React 16.8.

We can use hooks to make function components keep and change dynamic states.

For example, we can write the following code to add a hook to our app:

import React from "react";  
import ReactDOM from "react-dom";
function App() {  
  const [count, setCount] = React.useState(0); 
  return (  
    <div>  
      <button onClick={() => setCount(count + 1)}>Count {count}</button>  
    </div>  
  );  
}

In the code above, we have the React.useState hook with the default 0 passed in. It returns an array with the state, which we called count , and a function to set the state, which is called setCount .

Then in the onClick handler of the button, we can the setCount function to update the count.

Other packages like React DOM also has to be updated to 16.8 or later.

React Native since 0.59 also supports hooks.

No Breaking Changes

Hooks are completely opt-in. They coexist with class components. Therefore, we don’t have to change any existing code. They’re also completely interoperable with class components.

Class components will be available in the future. They also don’t replace our knowledge of existing React concepts.

Why do we need Hooks

We can use gooks to reuse stateful logic without creating higher-order components or doing other things to change our component hierarchy.

Complex Components Become Hard to Understand

Complex components have many methods which are lifecycle hooks and also our own user-defined functions.

They all have a mix of unrelated logic. This makes it too easy to introduce bugs and inconsistencies.

It’s impossible to break them into smaller components because stateful logic is everywhere. It’s also hard to test them because of the complexity.

We can use hooks to split one component into smaller functions based on what’s related.

Classes are Confusing

We have to understand a lot about how JavaScript classes work, which is different from most languages since JavaScript classes are just syntactic sugar on top of its own prototypical inheritance model.

Also, we have to make sure the value of this is correct so we don’t introduce errors.

Classes can introduce patterns that make optimizations difficult. They don’t minify well and they make hot reloading flaky and unreliable.

Hooks are used without classes, so we don’t have to worry about any of these issues.

Gradual Adoption Strategy

We can create new components with hooks without affecting anything existing code.

Therefore, we can try them on non-critical parts of an app first.

Class components will be supported in the foreseeable future.

Conclusion

Hooks are the new way to keep dynamic states in function components.

We can use function components with hooks the same way that we write class components.

They coexist with existing class components and they’ll still be supported in the foreseeable future.

Hooks remove the confusion that arises from JavaScript classes and also let React minify the code by providing additional optimizations that can’t be done with classes.

Categories
Express JavaScript

Compress Express.js Responses with the Compression Middleware

Compressing our responses is a great way to speed up our Express app’s performance.

To do this, we can use the compression middleware.

In this article, we’ll look at the options available to us for compressing data and how to send a compressed response with it.

Adding the Middleware

We can install the package by running:

npm install compression

Then we can include it with:

const compression = require('compression');

Options

The compression middleware takes an options parameter, which is an object that can have the following properties:

chunkSize

The chunk size of the compressed output. Default is 16384 bytes or zlib.Z_DEFAULT_CHUNK , where zlib is the zlib Node package.

filter

A function that decides what kind of responses should be compressed. The function is called as filter(req, res) and should return true if the kind of response should be compressed and false if it shouldn’t.

The default function uses the compressible module to check if the res.getHeader('Content-Type') is compressible.

level

The compression level to apply The higher the level of compression, the longer it’ll take to complete.

The values range from 0 (no compression) to 9 (highest level of compression). -1 can be used to mean the default compression level, which is equivalent to level 6.

memLevel

This sets how much memory should be allocated for compression and is an integer ranging from 1 for the minimum level to 9 for the maximum.

Default is zlib.Z_DEFAULT_MEMLEVEL or 8.

strategy

This sets the compression algorithm. The value only differs in the compression ratio and doesn’t affect the content of the compressed output.

The following are available:

  • zlib.Z_DEFAULT_STRATEGY — used for normal data
  • zlib.Z_FILTERED — used for data produced by a filter. Filtered data consists mostly of small values with a random distribution. This algorithm is tuned to compressed these kinds of data better. This algorithm forces more Huffman coding.
  • zlib.Z_FIXED — use to prevent the use of dynamic Huffman codes
  • zlib.Z_HUFFMAN_ONLY — force Huffman encoding only
  • zlib.Z_RULE — limit match distances to one, This gives a compression ratio as good as Huffman only, but gives better compression for PNG data

threshold

The byte threshold for response body size before compression is considered for the response. The default 1kb . The value can be the number of bytes or any string applied by the bytes module.

windowBits

The default value is zlib.Z_DEFAULT_WINDOWBITS or 15.

.filter

The default filter function, which we can use to construct a custom filter function that extends the default action.

res.flush

A res.flush method is added to force partially compressed response to be flushed to the client.

Example

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const compression = require('compression');
const app = express();  
const shouldCompress = (req, res) => {  
  if (req.headers['x-no-compression']) {  
    return false  
  }  
  return compression.filter(req, res);  
}

app.use(bodyParser.json());  
app.use(compression({  
  filter: shouldCompress,  
  level: 7,  
}));

app.get('/', (req, res) => {  
  const foo = 'foo';  
  res.send(foo.repeat(3000));  
});

app.listen(3000);

In the code above, we add the compression middleware and specify some options.

We specified that we compress our responses when the x-no-compression header isn’t present.

Also, we changed the compression level.

With the x-no-compression header present, our response is 9KB. After compression is enabled by removing the x-no-compression header, the response is only 402 bytes.

As we can see, the difference is huge. This is because the text is repeated so it can just keep one part of it and then repeat it instead of storing the whole string.

Server-Sent Events

We can compress responses with server-sent events. To do this, we compress the content after a window of the output has been buffered.

Once we have that, then we can send the data to the client.

We can use the res.flush() method to send whatever is present to the client.

For example, we can write:

const express = require('express');  
const bodyParser = require('body-parser');  
const compression = require('compression');
const app = express();  
const shouldCompress = (req, res) => {  
  if (req.headers['x-no-compression']) {  
    return false  
  }  
  return compression.filter(req, res);  
}

app.use(bodyParser.json());  
app.use(compression({  
  filter: shouldCompress,  
  level: 7,  
}));

app.get('/', (req, res) => {  
  res.setHeader('Content-Type', 'text/event-stream');  
  res.setHeader('Cache-Control', 'no-cache');  
  const timer = setInterval(() => {  
    res.write('foo');  
    res.flush()  
  }, 2000) res.on('close', () => {  
    clearInterval(timer)  
  })  
});

app.listen(3000);

To send a text event stream to the client, then we should see foo on the screen added every 2 seconds.

Conclusion

The compression middleware is useful for compressing regular responses and server-sent event output.

We can set options like compression level, chunk size, etc.

Also, if we want to compress server-side events, we should call res.flush to send what’s what already buffered to the client compressed.

Categories
JavaScript React

Creating Accessible React Apps — Focus and Semantics

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at how to create accessible React apps.

Why Accessibility?

We should create accessible apps so that they can be used by everyone.

Standards and Guidelines

The Web Content Accessibility Guidelines provide guidelines for creating accessible web sites.

Also, we have the Web Accessibility Initiative — Accessible Rich Internet Applications document contains guidelines for building fully accessible JavaScript widgets.

aria-* HTML attributes are fully supported in JSX. These attributes are kept as kebab-case as they’re in HTML.

Semantic HTML

HTML tags are named for their meanings. This means that they make sense for screen readers and other accessibility programs that parse web content.

This means that instead of using div to group elements, we should use Fragments instead so that our app doesn’t have extra div elements getting in the way of screen readers.

For example, we can add fragments to a component as follows:

function ListItem({ item }) {  
  return (  
    <Fragment>  
      <dt>{item.term}</dt>  
      <dd>{item.meaning}</dd>  
    </Fragment>  
  );  
}

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      items: [  
        { term: "coffee", meaning: "black drink" },  
        { term: "milk", meaning: "white drink" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <dl>  
        {this.state.items.map(item => (  
          <ListItem item={item} key={item.id} />  
        ))}  
      </dl>  
    );  
  }  
}

Then we get the following HTML rendered:

<dl>  
  <dt>coffee</dt>  
  <dd>black drink</dd>  
  <dt>milk</dt>  
  <dd>white drink</dd>  
</dl>

As we can see, fragments do not produce any extra HTML but let us group elements together.

A shorthand or fragments are <> and </> . Therefore, we can rewrite the code above as follows:

function ListItem({ item }) {  
  return (  
    <>  
      <dt>{item.term}</dt>  
      <dd>{item.meaning}</dd>  
    </>  
  );  
}

We keep the rest of the code the same.

Then we get the same HTML rendered.

Accessible Forms

We should label forms to provide accessibility for all users.

To do this, we add a for attribute to label elements. In React, the for element represented by the htmlFor prop.

This applies to all form controls.

For example, we can do the following to add a htmlFor prop:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { name: "" };  
  } 

  render() {  
    return (  
      <>  
        <label htmlFor="name">Name:</label>  
        <input type="text" name="name" value={this.state.name} />  
      </>  
    );  
  }  
}

In the code above, we have:

htmlFor="name"

to relate the label to the form field. The htmlFor value should be the same as the name value of the form control element.

The full accessibility guidelines are at:

Notifying the user of errors

Errors need to understood by users. The following guides tells us how to expose error text to screen readers:

Focus Control

We should only change or remove outlines by using CSS so that users can get the focused element even without seeing the outline.

Ways to Skip to Desired Content

Also, we should provide ways for users to skip to what they want to see or use.

We can implement that with internal page anchors and some styling.

We can also put important content in elements like main and aside so that they can be differentiated from other content.

Programmatically Managing Focus

In React, we can access DOM elements by using refs. This means that we can control when an element is in focus by calling DOM methods to focus an element.

For example, if we want to focus an element when the component is mounted in the DOM tree, we can call focus as follows:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.textInput = React.createRef();  
  } 

  componentDidMount() {  
    this.textInput.current.focus();  
  } 

  render() {  
    return <input type="text" ref={this.textInput} />;  
  }  
}

In the code above, we created a ref to access the DOM element by writing:

this.textInput = React.createRef();

In the input element, we have:

ref={this.textInput}

to associate the input element with the ref we created.

Then in the componentDidMount hook, we have:

this.textInput.current.focus();

to focus the input when the component mounts. this.textInput.current returns the input element, so that we can call the native focus method on it.

Conclusion

When creating React apps, we should have accessibility in mind.

This means that we should use semantic HTML tags so that all users can understand what a page has.

Also, we should provide ways for users to skip to the content that they want to see.

Finally, we can focus elements programmatically so that users can use inputs right away when focus is lost by regaining focus.