Filtered by JavaScript, Python

Reset

get in JavaScript is the same as property in Python

February 13, 2025
0 comments Python, JavaScript

Almost embarrassing that I didn't realize that it's the same thing!


class MyClass {
  get something() {
  }
}

is the same as Python's property decorator:


class MyClass
    @property
    def something:

They both make an attribute on a class automatically "callable".
These two are doing the same functionality:


class Foo {
  get greeting() {
    return "hello";
  }
  place() {
    return "world";
  }
}

const f = new Foo();
console.log(f.greeting, f.place());
// prints 'hello world'

and


class Foo:
    @property
    def greeting(self):
        return "hello"

    def place(self):
        return "world"

f = Foo()
print(f.greeting, f.place())
# prints 'hello word'

How to send custom headers in a loader in react-router v7

February 7, 2025
0 comments React, JavaScript

tl;dr; Use data() in your loader function and make your headers function pass it on to get headers be dependent on what's happening in the loader function.

I recently rewrote the front end of this website from Remix to react-router v7. A route is a page, which can be something like /about or have a parameter in it like /blog/:slug.

The way react-router v7 (the "framework mode") works is that your route looks like this:


import type { Route } from "./+types/post"

export async function loader({ params }: Route.LoaderArgs) {
  const post = await fetchPost(params.slug)
  return { post }
}

export default function Component({loaderData}: Route.ComponentProps) {
  return <h1>{loaderData.post.title}</h1>
}

So good for so far. But suppose you want this page to have a certain header, depending on the value of the post object. To set headers, you have to add an exported function called, surprise surprise; headers. For example:

Truncated! Read the rest by clicking the link below.

TypeScript enums without enums

January 29, 2025
0 comments JavaScript, TypeScript

My colleague @mattcosta7 demonstrated something that feels obvious in hindsight.

Instead of enums, use a regular object. So instead of


enum State {
  SOLID,
  LIQUID,
  GAS,
}

(playground here - note how "complex" the transpiled JavaScript becomes)

...use an object. Objects have the advantage that when the TypeScript is converted to JavaScript, it looks pretty much identical. TypeScript 5.8 makes it possible to disallow "non-erasable syntax" which means you can set up your tsconfig.json to avoid enum.

The alternative is an object. It's a bit more verbose but it has advantages:


const State = {
  SOLID: "solid",
  LIQUID: "liquid",
  GAS: "gas"
} as const

type State = typeof State[keyof typeof State]

(playground here - note how simple the transpiled JavaScript is)

In the above code, if you hover the mouse over State it'll say

'solid' | 'liquid' | 'gas'

Truncated! Read the rest by clicking the link below.

How I run standalone Python in 2025

January 14, 2025
1 comment Python

I don't do as much Python as I used to do. The few projects I still maintain, in Python, have a pyproject.toml and uv.lock. I.e. I'm using uv for getting the right executable version of Python and for installing dependencies. No more pip install ... and no more requirements.(in|txt). And definitely no poetry.lock.

And pyenv stopped working entirely when Python 3.12 came out. I used to use pyenv instead of Homebrew to get different versions of Python for different projects. uv is just that much better. I still use virtual envs, in the form of uv sync && source .venv/bin/activate when working inside a project and want to be able to type python ... and that referring to the exact version of Python with the relevant dependencies (from the pyproject.toml) installed.

However, there's a problem how: Outside of projects (that have a pyproject.toml and uv.lock) I no longer have a valid python executable. There's still a python3 executable that comes from /opt/homebrew/bin/python3 but that one I can't add dependencies to.
And many times I just want to whip up a quick script or start a repl, but with some certain dependencies installed. For example, to run...


import requests
print(requests.get('https://www.peterbe.com').headers['content-type'])
# prints 'text/html; charset=utf-8'

Again, uv to the rescue! I created ~/bin/python (plus chmod +x ~/bin/python) which now looks like this:


#!/bin/bash
set -x
uv run --python 3.12 --with requests python $@

Now I can quickly start a repl. Or if I create a /tmp/test-something.py I can just run that with


python /tmp/test-something.py

Truncated! Read the rest by clicking the link below.

Run TypeScript in Node without extensions

December 10, 2024
0 comments Node, JavaScript

A couple of months ago I wrote about "Node watch mode and TypeScript" which suggests using the @swc-node/register package to be able to run node on .ts file without first converting it to .js using tsc.

In Node 22, you don't even need @swc-node/register. You can use --experimental-strip-types instead. (Note the prefix "experimental"). See release notes here.

Imagine a script like this:


// example.ts

function c2f(c: number) {
  return (c * 9) / 5 + 32;
}
console.log(c2f(123));

you can execute it directly in Node v22 using:


❯ node --experimental-strip-types --no-warnings example.ts
253.4

Truncated! Read the rest by clicking the link below.

An ideal pattern to combine React Router with TanStack Query

November 18, 2024
1 comment React, JavaScript

I'm writing this blog post from an admin interface I built, which is a web app frontend for the backend behind peterbe.com. It's built as a single-page app in Vite, with React.
Vite, unlike frameworks like Remix or Next, doesn't come with its own routing. You have to add that yourself. I added React Router. Another thing you have to do yourself is a way to load remote data into the app for display and for manipulation. This is done as XHR requests happen on the client side. For that, I chose TanStack Query. If you haven't used it but used React, it's sugar for this type of code:


// DON'T DO THIS. USE TANSTACK QUERY

const [stuff, setStuff] = useState(null)
const [error, setError] = useState(null)
useEffect(() => {
  fetch('/api/some/thing')
    .then(r => r.json())
    .then(data => setStuff(data)
    .catch(err => setError(err))
}, [])

Truncated! Read the rest by clicking the link below.

Object.keys to return the known strings of an object in TypeScript

October 25, 2024
0 comments JavaScript

This one always confused me but by blogging about it, hopefully, it will stick.

This does NOT work in TypeScript:


const person = {
  firstName: "peter",
  lastName: "bengtsson",
  state: "happy"
}

const keys = Object.keys(person)
const randomKey = keys[Math.floor(Math.random() * keys.length)];
const value = person[randomKey]

It works in JavaScript, but in TypeScript you get an error on the last line (from the person[randomKey]):

Truncated! Read the rest by clicking the link below.

How I make my Vite dev server experience faster

October 22, 2024
0 comments React, Node, JavaScript

I have a web app that operates as a SPA (Single Page App). It's built on regular Vite + React + TypeScript. In production you just host the built static assets, but in development (for hot module reloading and stuff) I use the built-in dev server in Vite. This is what you get when you type vite without any other command line arguments.

But here's what happens, you're in the terminal and you type npm run dev and hit Enter. Then, using your trackpad or keyboard shortcuts you switch over to a browser tab and go to http://localhost:5173/. When you get there to the first request, Vite starts at the entry point, which is src/main.tsx and from there, it looks at its imports and starts transpiling the files needed. You can see what happens with vite --debug transform.

With debug:

Truncated! Read the rest by clicking the link below.

How to extend a function in TypeScript without repeating the signature types

October 16, 2024
0 comments JavaScript

Suppose you have a function, written in TypeScript, that is fine and complete. Now you want to write a function that works like that one but with just some slightly more parameters and other differences. It's not too different from a decorator function.

Extending the list of parameters

Let's imagine that you already have this function:


type Operation = "sum" | "sub" | "mul" | "div"

function calculator(a: number, b: number, op: Operation) {
  if (op === "sum") return a + b
  if (op === "sub") return a - b
  if (op === "mul") return a * b
  if (op === "div") return a / b
  throw new Error(op)
}

And this could, for the sake of argument, be in a different file and/or possibly outside your control. What you now want to do is write a new function that takes those same arguments, plus one more. And importantly, you don't want to have to spell out all the arguments one more time.

First, the WRONG way to solve this:


import { calculator } from './calculator' // The code in the snippet above

type Operation = "sum" | "sub" | "mul" | "div"

function doubleCalculator(a: number, b: number, op: Operation, c: number) {
  return calculator(calculator(a, b, op), c, op)
}

console.log(calculator(1, 2, "sum")) // 3
console.log(doubleCalculator(1, 2, "sum", 10)) // 13

Technically, it works, but you had to repeat the calculator function's signature.

Truncated! Read the rest by clicking the link below.

Previous page
Next page