drago.cc

A utility for null and undefined array filtering in TypeScript

The solution

export function notNullOrUndefined<TType>( item: TType | null | undefined, ): item is TType { return item !== null && item !== undefined; }

Example usage

const users: User[] = [ { name: "Anthony", website: "https://anthonysgoods.com" }, { name: "Pam" }, // Pam doesn't have a website ]; // ❌ The `Boolean` filter removes undefined values, but TypeScript doesn't // understand that const userWebsites: (string | undefined)[] = users .map((user) => user.website) .filter(Boolean); // ✅ The `notNullOrUndefined` filter achieves the same thing, but provides an // extra hint to TypeScript that no `undefined` will exist in the array const userWebsites: string[] = users .map((user) => user.website) .filter(notNullOrUndefined);

The problem

In TypeScript, it's common to transform an array of objects into an array containing a specific property from those objects, which may potentially be null or undefined. For instance, let's say we want to compile a list of our users' websites, but some users might not have a website.

We can start with an interface and an array of user objects:

interface User { name: string; website?: string; } const users: User[] = [ { name: "Anthony", website: "https://anthonysgoods.com" }, { name: "Pam" }, // Pam doesn't have a website ];

To create an array of their websites, we could initially attempt this:

const websites = users.map((user) => user.website);

However, this leads to the websites variable having the type (string | undefined)[], which isn't ideal.

Subsequently, you might try filtering out the undefined values:

const websites = users.map((user) => user.website).filter(Boolean);

Despite this, websites still remains of type (string | undefined)[].

This is where the notNullOrUndefined function proves useful:

export function notNullOrUndefined<TType>( item: TType | null | undefined, ): item is TType { return item !== null && item !== undefined; }

It checks whether the provided item is either null or undefined and provides TypeScript with a type hint, resulting in a cleaner and more precise string[]:

const websites = users.map((user) => user.website).filter(notNullOrUndefined);

In summary, the notNullOrUndefined function assists in filtering out null or undefined values when working with arrays of potentially nullable properties, leading to a more refined and expected data type.

Published: September 14, 2023 at 1:56 AM

Edited: September 16, 2023 at 1:51 PM

WCAG guidelines for line-height

If you're struggling to figure out typography, here are some basic rules provided by the WCAG:

  • line-height should be at least 1.5 times the font-size
  • The spacing that follows paragraphs should be at least 2 times the font-size
  • letter-spacing should be at least 0.12 times the font-size
  • word-spacing should be at least 0.16 times the font-size

https://www.w3.org/WAI/WCAG21/Understanding/text-spacing.html

Published: December 7, 2021 at 2:15 PM

Web Accessibility Chrome Extension

Automated accessibility testing will probably never be able to catch all the issues that a real human could, but it doesn't hurt to have one in your tool belt anyway.

The "axe DevTools" Chrome extension, by Deque Labs, can be very helpful in finding many critical and easy-to-miss accessibility issues.

Published: December 6, 2021 at 5:31 PM

The play function on audio and video elements is a promise

audio and video elements in HTML expose a play() function. This function returns a Promise<void>, so if you need to update some piece of UI in response to playing a piece of media and even show when it is loading, especially if you're not preloading the media, you can await play():

const handlePlayClick = async () => { const nextIsPaused = !isPaused; if (audioRef.current) { if (nextIsPaused) { audioRef.current.pause(); } else { try { setIsLoading(true); await audioRef.current.play(); setIsPaused(!isPaused); } catch { // Stay paused } setIsLoading(false); } } };

Doing this can also fix some cases where .play() and .pause() are inadvertently called in lock-step.

Published: November 21, 2021 at 5:30 PM

CSS grid-area shorthand

Using CSS grid with grid-area can be useful in certain circumstances, and especially for stacking elements without using position: absolute. For example, there's a particularly clever trick that can be used to make textarea and input elements automatically resize based on their contents.

Here's what the different versions of the shorthand translate to:

/* 4 */ grid-area: 0 / 0 / 1 / 1; grid-area: 0 / /* grid-row-start / */ 0 / /* grid-column-start / */ 1 / /* grid-row-end / */ 1; /* grid-column-end; */ /* 3 */ grid-area: 0 / 0 / 1; grid-area: 0 / /* grid-row-start / */ 0 / /* grid-column-start / */ 1; /* grid-row-end / */ /* <grid-column-start's custom-ident or auto>; */ /* 2 */ grid-area: 0 / 0; grid-area: 0 / /* grid-row-start / */ 0; /* grid-column-start / */ /* <grid-row-start's custom-ident or auto> / */ /* <grid-column-start's custom-ident or auto>; */ /* 1 */ grid-area: 0; grid-area: 0; /* grid-row-start / */ /* <grid-row-start's custom-ident or auto> / */ /* <grid-row-start's custom-ident or auto> / */ /* <grid-row-start's custom-ident or auto>; */

Published: September 11, 2021 at 5:12 PM