til

How to pop a file from stash

git

You can use the following command to pop just one file from it. Replace stash@{n} with the actual stash reference you want to use, and replace file/path with the path to the specific file you want to pop:

git checkout stash@{n} -- file/path

For example, if you want to pop a file named "example.txt" from the most recent stash (stash@{0}), you can do:

git checkout stash@{0} -- example.txt

It's possible to reference a second arg

typescript

In JavaScript you can reference a previous argument from a function but on TypeScript the first argument can reference the second argument!

type Indices = 1 | 2 | 3;

type GroupedKeys<T> = T extends `${infer U}${Indices}` ? U : never;

function add<
    Obj extends Record<`${BaseKey}${Indices}`, any>,
    BaseKey extends GroupedKeys<keyof Obj>
>(_obj: Obj, _baseKey: BaseKey) {
    return null as any;
}

const order = {
    price1: 10,
    price2: 20,
    price3: 30,
};

add(order, "price");

The code above is avaiablable in this playground.

You can read the full article from Maxime

I learnt this from @maxime1992

How to write overloads for arrow functions

typescript

The third argument seems to be needed to correlate return/input types with the function body.

const greet: {
    (name: string): string
    (hellos: number): string
    (arg: string | number): string
} = (arg) => {
    if (typeof arg === "string") {
        return `Hello ${arg}!`;
    }
    return Array.from(Array(arg)).map(() => "Hello").join(' ');
}

greet("John");
greet(3);

// Outputs:
// Hello John!
// Hello Hello Hello

Check this TypeScript playground

I learnt this from @steveruizok

How to sort of extend enums

typescript

Not sure what you'd need this but...

enum Status {
    RUNNING = "RUNNING",
    FINISHED = "FINISHED",
    FAILURE = "FAILURE"
}

const StatusValues = {
    ...Status,
    PENDING: "PENDING" as const
}

const st = StatusValues.RUNNING;

Check this TypeScript playground

I learnt this from @steveruizok

How to check if the inferred type is `any`

typescript

You can check if a type is any using this utility:

type IsAny<T> = 0 extends (1 & T) ? true : false;

Some checks:

// Returns true
type R = IsAny<any>;
type J = IsAny<ReturnType<typeof JSON.parse>>;

// Returns fale
type A = IsAny<"A">;
type B = IsAny<{}>;
type C = IsAny<unknown>;

Check this TypeScript playground

I learnt this from @WrocTypeScript

How to handle multiple submit buttons in a form

typescriptjavascriptbrowsers

Normally, we use forms with only one submit button, but because they are just inputs, you can define multiple of them.

The key to knowing which button was clicked or submitted when you hit enter is to give them all the same name.

interface AcceptRejectSubmitEvent extends SubmitEvent {
  readonly submitter: HTMLButtonElement;
}

export default function App() {
  const [chosenButton, setChosenButton] = React.useState<string>(null);

  const onSubmit = (
    e: React.SyntheticEvent<HTMLFormElement, AcceptRejectSubmitEvent>
  ) => {
    e.preventDefault();

    const submitter = e.nativeEvent.submitter;
    setChosenButton(submitter.value);
  };

  return (
    <div>
      <form onSubmit={onSubmit}>
        <p>I agree with the terms ...</p>

        <div>
          <label htmlFor="name">Email: </label>

          <input type="email" name="email" id="email" required />
        </div>

        <div className="buttons" style={{ display: "flex" }}>
          <button
            type="submit"
            name="commit"
            value="reject"
            style={{ order: 1 }}
          >
            Reject
          </button>

          <button type="submit" name="commit" value="accept">
            Accept
          </button>
        </div>

        {chosenButton && <output>You choose {chosenButton}</output>}
      </form>
    </div>
  );
}

Examine the following lines of code:

  1. When you press enter, the first button in the DOM is the one specified by e.nativeEvent.submitter. I used order to change the order of appearance, but it wasn't taken into account.
  2. You must use the SubmitEvent method. Because submitter is of type HTMLElement by default, we extend the SubmitEvent to override the submitter type to avoid casting.

If you use action and method to handle the submit action on the server, you will get the attribute commit with the value accept or reject.

You can play with it here

How to unwrap promises from an array of promises

typescriptjavascript

There's a new method released in Safari 16.4 that allows to unwrap all promises from an array: Array.fromAsync.

I found and example from @mgechev:

async function* generate(total, throttle) {
  for (let i = 0; i < total; i++) {
    await new Promise((resolve) => setTimeout(resolve, throttle));
      yield i + 1;
  }
}

// [1, 2, 3, 4, 5]
console.log(await Array.fromAsync(generate(5, 200)));

As you can see it returns a Promise, so what happens when a promise is rejected? Yes, you have to handle it. In the next example, the error is caught and the expression of Array.fromAsync will return undefined. We could use ?? to return a fallback array:

async function withErrorExample() {
  const err = new Error();
  const badIterable = {
    [Symbol.iterator]() {
      throw err;
    }
  };

  // This returns a promise that will reject with `err`.
  const withErrorResult = await Array.fromAsync(badIterable)
    .catch((error) => {
      console.log("This is executed when there's an error.", error);
    }) ?? ["falback"];

  console.log("Result", withErrorResult);
}

withErrorExample();

As with Array.from there's also a second argument which is a map function:

class Array {
  static fromAsync(
    asyncItems: AsyncIterable | Iterable | ArrayLike,
    mapfn?: (value: any, index: number) => any,
    thisArg?: any
  ): Array;
}

I've made a CodeSandbox to play with it

I learnt this from @mgechev

How to group an array into a Map

typescriptjavascript

While reviewing the Safari 16.4 release notes I noticed a new method for array and array like objects.

Basically it iterates throught an array and returns a Map object indexed by the returned value of the groupToMap callback.

const posts = [
  { slug: "something-new", favorites: 3 },
  { slug: "weird-bug-thingy", favorites: 2 },
  { slug: "some-cash-please", favorites: 2 },
  { slug: "unpopular-opinion", favorites: 1 },
  { slug: "how-to-make-money", favorites: 3 }
];

posts.groupToMap(({ favorites }) => favorites);

That will return a Map object like this:

[
  [
    3,
    [
      { slug: "something-new", favorites: 3 },
      { slug: "how-to-make-money", favorites: 3 }
    ]
  ],
  [
    2,
    [
      { slug: "weird-bug-thingy", favorites: 2 },
      { slug: "some-cash-please", favorites: 2 }
    ]
  ],
  [1, [{ slug: "unpopular-opinion", favorites: 1 }]]
]

Until it's officially polyfilled, here's an ambient declaration that you could add to your global.d.ts file to make it work with TypeScript:

declare global {
  interface Array<T> {
    groupToMap<GroupName>(
      cb: (value: T) => GroupName,
      index?: number,
      origArray?: T[]
    ): Map<GroupName, T>;
  }
}

Note: On sparse arrays empty values are treated as undefined.

I've made a CodeSandbox to play with it

What's the difference between DetailedHTMLProps and HTMLAttributes

typescript

I came across a tweet of cpojer where he claimed he liked the native browser form validation and in the snippet I found a TypeScript utility I haven't seen before: React.DetailedHTMLProps. It seems it's like React.HTMLAttributes but it also adds key and ref as optional props.

function App() {
  return (
    <div className="App">
      <Form>
        <label htmlFor="name">Name:</label>
        <input name="name" placeholder="Type here your name" required />
      </Form>
    </div>
  );
}

type FormProps = React.DetailedHTMLProps<
  React.FormHTMLAttributes<HTMLFormElement>,
  HTMLFormElement
>;

function Form({ onBlur: onBlurBase, ...rest }: FormProps) {
  const onBlur: React.FocusEventHandler<HTMLFormElement> = (e) => {
    e.target.classList.add("validate");
    onBlurBase?.(e);
  };

  return <form {...rest} onBlur={onBlur} />;
}

If you want to play with the code above you can do it here.

I found the answer to my question in Stackoverflow thanks to Marcin. I copy here the response because it's worthwile knowing it.

interface ComponentProps1
  extends React.DetailedHTMLProps<
    React.HTMLAttributes<HTMLDivElement>,
    HTMLDivElement
  > {}

interface ComponentProps2 extends React.HTMLAttributes<HTMLDivElement> {}
type Dif = Omit<ComponentProps1, keyof ComponentProps2>;
type Dif = {
  ref?: LegacyRef<HTMLDivElement>;
  key?: string | number;
};

I learnt this from @cpojer

How to create .d.ts files from .js files

typescript

You can set up a JavaScript project to emit .d.ts files automatically from JSDoc tags, without having to maintain them manually.

To do so, you have to follow these steps:

  1. Add TypeScript to your devDependencies
  2. Add a tsconfig.json file with this content:
{
  // Change this to match your project
  "include": ["src/**/*"],
  "compilerOptions": {
    // Tells TypeScript to read JS files, as
    // normally they are ignored as source files
    "allowJs": true,
    // Generate d.ts files
    "declaration": true,
    // This compiler run should
    // only output d.ts files
    "emitDeclarationOnly": true,
    // Types should go into this directory.
    // Removing this would place the .d.ts files
    // next to the .js files
    "outDir": "dist",
    // go to js file when using IDE functions like
    // "Go to Definition" in VSCode
    "declarationMap": true
  }
}
  1. Run the TypeScript compiler to generate the corresponding .d.ts files for JavaScript files.
  2. (optional) Edit package.json to reference the types.

Check here the original article.

I learnt this from @orta

How to know if a CPU is x86

javascript

It's possible to see whether a CPU is x86 based using the following snippet.

function isX86() {
  const f = new Float32Array(1);
  const u8 = new Uint8Array(f.buffer);
  f[0] = Infinity;
  f[0] = f[0] - f[0];
  return u8[3] == 255;
}

The exaplanation of this is commented in the Tensorflow codebase and is worthwhile to read:

Unlike most other architectures, on x86/x86-64 when floating-point instructions have no NaN arguments, but produce NaN output, the output NaN has sign bit set. We use it to distinguish x86/x86-64 from other architectures, by doing subtraction of two infinites (must produce NaN per IEEE 754 standard).

I learnt this from @robknight\_

How to avoid casting [[form]].elements

typescript

When you do an uncontrolled form in React and you want to access a field inside of the elements attribute, for instance username, you'll get an error like this:

Property 'username' does not exist on type 'FormElements'

You can extend HTMLFormControlsCollection and HTMLFormElement to add all the input elements like this:

interface FormElements extends HTMLFormControlsCollection {
  username: HTMLInputElement;
}

interface UsernameFormElement extends HTMLFormElement {
  readonly elements: FormElements;
}

function UsernameForm({
  onSubmitUsername,
}: {
  onSubmitUsername: (value: string) => void;
}) {
  const [error, setError] = React.useState<string | null>(null);

  function onSubmit(evt: React.FormEvent<UsernameFormElement>) {
    evt.preventDefault();
    onSubmitUsername(evt.currentTarget.elements.username.value);
  }

  function onChange({
    currentTarget: { value },
  }: React.ChangeEvent<HTMLInputElement>) {
    const isLowerCase = value === value.toLowerCase();
    setError(isLowerCase ? null : "Username must be lower case");
  }

  return (
    <form onSubmit={onSubmit}>
      <div>
        <label htmlFor="username">Username:</label>

        <input id="username" onChange={onChange} />
      </div>

      <div role="alert" style={{ color: "red" }}>
        {error}
      </div>

      <button type="submit" disabled={Boolean(error)}>
        Submit
      </button>
    </form>
  );
}

That way you avoid casting the elements object.

You can play with a working example here

I learnt this from @kentcdodds

Valid CSS nested selectors

css
/* 🛑 Invalid selectors */
.char {
  p {
    ...;
  }
}

/* ✅ Valid selectors */
.chart {
  & p {
    ...;
  }
}
.chart {
  > p {
    ...;
  }
}
.chart {
  :is(p) {
    ...;
  }
}
.chart {
  .message {
    ...;
  }
}
.chart {
  .message & {
    ...;
  }
}

Parsing rules from nesting spec

I learnt this from @argyleink

How to have a parallel `gitignore` file

git

You can have a local .gitignore file to avoid files getting checked into a repo. Just add the files you want to ignore in .git/info/exclude.

There's also a global gitignore at ~/.config/git/ignore.

I learnt this from @mgattozzi

How to force VSCode to show expanded types

typescriptvscode

I always forget this gem piece of TypeScript that allows you to force VSCode to show properties inside of a type. So instead of seeing a reference to the type name you get the full properties inside of the type

type Prettify<Obj> = { [k in keyof Obj]: Obj[k] } & {};

So, instead of seeing this:

Collapsed properties

You see this:

Expanded properties

Also when you have intersections like this:

type Intersected = { a: number } & { b: number };

Instead of seeing this:

Intersection before

You see this:

Intersection after

I learnt this from @mattpocockuk

How to configure VSCode with untrusted certificate

sonarqubevscode

I always forget the formula so here are the steps:

First, download the certificate from the domain using Chrome or Firefox.

Next, import the certificate in the Java VM Keytool:

sudo keytool -import -alias whatever_alias -keystore /Library/Java/JavaVirtualMachines/jdk-17.0.2.jdk/Contents/Home/lib/security/cacerts -file path/to/certificate.cer

In VSCode I also had to add the path to my JVM installation In VSCode Settings > Sonarlint › Ls: Java Home. At the time or writing the value is /Library/Java/JavaVirtualMachines/jdk-17.0.2.jdk/Contents/Home

To use the connected mode I add this piece of JSON to .vscode/settings.json

"sonarlint.connectedMode.project": {
  "projectKey": "CODE_PROJECT_HERE"
}

After restarting VSCode it should be in connected mode.

Lazy loading images needs JS enabled

javascriptbrowser

I have read another TIL from Stefan Judis that explains this way better.

It seems it's to prevent tracking the user scroll position becaue a server could place images strategically and know how much of them were downloaded and at which time.

I learnt this from @stefanjudis

How to clear browsing data on a website

httpbrowser

The Clear-Site-Data header allows to clear the browser data of a website. You can specify which data you want to clear:

  • cookies
  • storage: localStorage, sessionStorage, IndexedDB, Service worker registrations, FS API Data, and Plugin Data
  • executionContexts
  • cache: locally cached data like script caches, pre-rendered pages, shaders, address bar suggestions...
  • everithing: using the wildcard *.

See MDN Clear-Site-Data docs for more info.

I learnt this from @stefanjudis

How to style using data attributes

tailwindcssjavascript

Suppose you are using a Callout component like this:

<>
  <Callout data-status="success">Some success message</Callout>

  <Callout data-status="warning">Some warning message</Callout>

  <Callout data-status="error">Some error message</Callout>
</>

You can style your Callout component doing this:

function Callout({children}) {
    return (
        <div className={clsx(
            "p-4",
            "font-medium",
            "rounded-lg",
            "data-[status=success]:bg-green-200"
            "data-[status=warning]:bg-yellow-200"
            "data-[status=error]:bg-red-200"

        )}>
            <p className="text-green-800">
                {children}
            </p>
        </div>
    );
}

You can combine this with the group class to also styling nested elements based on the container.

Then, the resulting code will look like this:

function Callout({children}) {
    return (
        <div className={clsx(
            "group", // Add the group class
            "p-4",
            "font-medium",
            "rounded-lg",
            "data-[status=success]:bg-green-200"
            "data-[status=warning]:bg-yellow-200"
            "data-[status=error]:bg-red-200"

        )}>
            <p className={clsx(
                "group-data-[status=success]:text-green-800",
                "group-data-[status=warning]:text-yellow-800",
                "group-data-[status=error]:text-red-800",
            )}>
                {children}
            </p>
        </div>
    );
}

I saw this from Simon Vrachliotis

I learnt this from @simonswiss

How to get the first day of week

javascript

Today I found a tweet from Erikras mentioning this.

Date.prototype.getDay() returns a value 0-6, with 0 being the 🇺🇸-centric first day of week: Sunday. But Intl.Locale.prototype.weekInfo.firstDay is from 1-7, with 1=Monday, 7=Sunday.

Code snippet showing difference between US and GB

So the thing is that a function to get the first day of week could look like this:

function isFirstDayOfWeek(date: Date): boolean {
  const locale = new Intl.Locale(navigator.language);
  const firstDayOfWeek = locale.weekInfo.firstDay;
  const dayOfWeek = date.getDay();
  return dayOfWeek === firstDayOfWeek % 7;
}

There not seems to be a way of getting the first day of week defined by the system:

MacOSX First day of week

I learnt this from @erikras

How to export CSV files preserving enconding in Excel

csvbrowser

The way you can preserve your encondig in an Excel file is to use a BOM_ORDER_MARK which is a character used by Excel to know the file encondig.

You can create a utility function to download a CSV file like this:

const BYTE_ORDER_MARK = "%EF%BB%BF";

export default function downloadCsv(csv: string, fileName: string) {
  const anchor = Object.assign(document.createElement("a"), {
    href: `data:text/csv;charset=utf-8,${BYTE_ORDER_MARK}` + encodeURI(csv),
    download: `${fileName}.csv`,
  });
  anchor.click();
}

To handle .csv files, Microsoft Excel uses the List separator defined in Windows Regional settings.

In North America and some other countries, the default list separator is a comma, so you get CSV comma delimited.

In European countries, a comma is reserved for the decimal symbol, and the list separator is generally set to semicolon. That is why the result is CSV semicolon delimited.

You can configure the separator used in an CSV file by adding this as the first line:

sep=,

I've noticed that adding the sep line will make enconding break, so it's better not to add.

Use fetch keepalive instead of sendBeacon

javascriptbrowser

One of the fetch API options is keepalive. This has the same behaviour as sendBeacon API to send analytics or simply calls to the server you don't want to be aborted when navigating though pages.

The reason to prefer keepalive: true instead of sendBeacon is that adBlocks seems to be blocking sendBeacon requests.

I learnt this from @stefanjudis

Reduce initial value is optional.

javascript

You don't need to provide an initial value to the reduce method. That way you're saving one iteration that you may not need.

[1,2,3,4].reduce((previousValue, currentValue) =>
  previousValue + currentValue;
);

The iteration starts assigning 1 to previousValue and 2 to currentValue.

I learnt this from @stefanjudis

Template for monorepos

javascriptmicrofrontend

This template was presented in React Alicante 2022. It tries to solve common monorepos problem like versioned dependencies, ci build times, ... It can work with Remix and with Next.js.

See the repo on Github here.

How to get proper screen dimensions

javascriptreact-native

Samsung devices have some sort of resolution selection that will make width and height returned from Dimensions.get("window") not to work as expected. To avoid it, we have to use this scaling factor:

const { width, height } = Dimensions.get("window");

const scaleFactor =
  Dimensions.get("screen").scale / Dimensions.get("window").scale;

export const screenWidth = width * scaleFactor;
export const screenHeight = height * scaleFactor;

Object.assign can be used to add attributes/properties to an element

javascriptbrowser

Instead of creating an element and calling setAttribute multiple times, you can just use Object.assign.

function downloadJson(json: string, fileName: string) {
  const blob = new Blob([json], { type: "application/json" as const });
  const href = URL.createObjectURL(blob);
  const anchor = Object.assign(document.createElement("a"), {
    href,
    download: `${fileName}.json`,
  });
  anchor.click();
}

I learnt this from @jh3yy

Avoid waitFor using findBy* queries

javascriptreact-testing-library

Whenever you have to do a getBy* query to look for an element that was added to the DOM in response to an async operation like a fetch request, you can directly use findBy* queries.