Skip to content
tinytip

Latest tips

Backreference in RegEx allows matching the same text as a previous capturing group

December 19, 2024
#javascript #regex

A capturing group (...) groups a subpattern. For example, ([A-Z]\d) matches a letter followed by a digit, like "A1". A backreference, denoted by \1, \2, etc., refers to a previous capturing group and matches the same text as that group.

For instance, in the pattern ([A-Z]\d)\1, \1 refers to the first capturing group ([A-Z]\d), ensuring that the same letter-digit combination is repeated.

const pattern = /([A-Z]\d)\1/;

pattern.test("A1A1"); // true
pattern.test("A1B1"); // false

You can also use a backreference with quantifiers:

const pattern = /(\d)\1{2}/;

pattern.test("111"); // true
pattern.test("122"); // false

Inspect your ESLint Flat Config

December 18, 2024
#eslint

The ESLint Config Inspector allows you to examine your flat configuration. It displays the rules you have set up and the files to which they apply. Use the following command to inspect your configuration:

eslint --inspect-config

Naming your config objects will help you easily identify them when using the inspector:

// eslint.config.js
export default [
{
name: "common", // <-- Define a name
rules: {
"no-console": "error",
},
},
{
name: "react", // <-- Define a name
plugin: { react },
rules: {
"react/jsx-boolean-value": "error",
},
},
];

Get translated display names with Intl.DisplayNames

April 23, 2024
#javascript

When developing features such as a country selector, a currency picker, or a language switcher, you often need to display the names of countries, currencies, and languages translated into the user's language. JavaScript's Intl.DisplayNames object is a handy tool for this purpose.

To use Intl.DisplayNames, create a new instance by specifying the user's current language and the type of display names you need. Then, retrieve the translated display name using the of() method. In the following example, we generate the display name for the US region in both English and German.

const regionEnglish = new Intl.DisplayNames("en", { type: "region" });
regionEnglish.of("US"); // United States

const regionGerman = new Intl.DisplayNames("de", { type: "region" });
regionGerman.of("US"); // Vereinigte Staaten

By altering the type parameter in the Intl.DisplayNames constructor, you can retrieve display names for different categories such as languages or currencies.

const lang = new Intl.DisplayNames("en", { type: "language" });
lang.of("en-US"); // American English
lang.of("fr"); // French

const currency = new Intl.DisplayNames("en", { type: "currency" });
currency.of("USD"); // US Dollar

React Context without default value

April 18, 2024
#react

Creating a React Context using createContext() requires a default value. If you cannot provide a useful default value, you have to make the context nullable and then, when using the context value, verify that it is not null.

const context = createContext<User | null>(null);

export function useUser() {
const value = useContext(context);
if (value === null) throw new Error("UserContext not provided");
return value;
}

Instead of repeating this boilerplate code every time, you can move this logic into a small utility function:

// Represents our empty value
const EMPTY = Symbol();

export function createRequiredContext<T>(): [Provider<T>, () => T] {
// Context, initialized with EMPTY
const context = createContext<T | typeof EMPTY>(EMPTY);

// Provider with EMPTY excluded (only T values are allowed)
const Provider = context.Provider as Provider<T>;

// Hook that throws an error if the value is EMPTY
const useStrictContext = () => {
const value = useContext(context);
if (value !== EMPTY) return value;
throw new Error("Missing context provider");
};

return [Provider, useStrictContext];
}

In our approach, we utilize a unique symbol, denoted as EMPTY, to differentiate between a default value and an actual value. This strategy provides the flexibility to create nullable contexts when necessary. You can then call the createRequiredContext function to create a new context:

const [UserProvider, useUser] = createRequiredContext<User>();

Replace any with generics, not with unknown (in many cases)

February 25, 2024
#typescript

You sure know that any in TypeScript is bad and should be avoided. But what should you replace it with?

When the type is unknown throughout the application: If the type is unknown in the entire application, such as when receiving data from an untrusted third-party API, the unknown type is your best choice. It's the type-safe counterpart of any and informs TypeScript that the type is unknown until you validate it at runtime. You can validate the type using methods like Array.isArray() or the typeof operator:

function foo(value: unknown) {
if (Array.isArray(value)) {
// We know it's an array
console.log("Number of items: " + value.length);
} else if (typeof value === "string") {
// We know it's a string
console.log(value.toLowerCase());
}
}

When the type is unknown in a specific context: Sometimes, your type might be unknown in one part of the application (where you don't care about the type) but known in another part. If you try to replace any with unknown in this case, you will likely encounter errors.

const addValidationFn = (fn: ((value: unknown) => boolean)) => { /* ... */ };

// => Doesn't work, you will get: Type 'unknown' is not assignable to type 'number'
addValidationFn((value: number) => { /* ... */ });

In this case, TypeScript is correct. Inside addValidationFn, you could call the provided function with any value because you've specified that the type is unknown, and any value is assignable to unknown. Therefore, providing a function that expects a number is not valid.

In such scenarios, you should use generics:

const addValidationFn = <V,>(fn: ((value: V) => boolean)) => { /* ... */ };

// => This works
addValidationFn((value: number) => { /* ... */ });

Generics allow you to capture the type information while maintaining type safety. In the above example, V is a placeholder for any type, and it will be determined when addValidationFn is called.