60 mappings

Rosetta cheatsheet

From the JavaScript you already write to Python 3.14+. Anything tagged footgun looks equivalent but behaves differently.

60 of 60

Transform every element
TypeScript
xs.map(x => x * 2)
Python 3.14+
[x * 2 for x in xs]
Keep elements matching a predicate
TypeScript
xs.filter(x => x > 2)
Python 3.14+
[x for x in xs if x > 2]
Filter then transform in one pass
TypeScript
xs.filter(x => x > 2).map(x => x * 2)
Python 3.14+
[x * 2 for x in xs if x > 2]
Fold to a single value
TypeScript
xs.reduce((a, b) => a + b, 0)
Python 3.14+
sum(xs) # or functools.reduce(op.add, xs, 0)
First element matching a predicate
TypeScript
xs.find(x => x > 2)
Python 3.14+
next((x for x in xs if x > 2), None)
Any / all match
TypeScript
xs.some(f) / xs.every(f)
Python 3.14+
any(f(x) for x in xs) / all(f(x) for x in xs)
Membership test
TypeScript
xs.includes(3)
Python 3.14+
3 in xs
Last element
footgun
TypeScript
xs.at(-1)
Python 3.14+
xs[-1]
JS xs[-1] is a property lookup returning undefined; Python indexes from the end and raises IndexError when empty.
Sub-sequence
TypeScript
xs.slice(1, 3)
Python 3.14+
xs[1:3]
Reversed copy
footgun
TypeScript
[...xs].reverse()
Python 3.14+
xs[::-1]
JS .reverse() mutates in place; the spread is what makes it a copy.
Sort by a key
footgun
TypeScript
[...xs].sort((a, b) => a.age - b.age)
Python 3.14+
sorted(xs, key=lambda x: x.age)
Python xs.sort() mutates and returns None; sorted() returns a new list. JS .sort() does both at once, and sorts lexicographically without a comparator.
Concatenate
TypeScript
[...a, ...b]
Python 3.14+
[*a, *b] # or a + b
Head and tail
TypeScript
const [first, ...rest] = xs
Python 3.14+
first, *rest = xs
Index with each element
TypeScript
xs.forEach((x, i) => ...)
Python 3.14+
for i, x in enumerate(xs): ...
Iterate two sequences together
footgun
TypeScript
a.map((x, i) => [x, b[i]])
Python 3.14+
list(zip(a, b))
zip stops at the shorter input; pass strict=True (3.10+) to raise instead.
Flatten one level
TypeScript
xs.flat()
Python 3.14+
[y for x in xs for y in x]
Deduplicate
footgun
TypeScript
[...new Set(xs)]
Python 3.14+
list(dict.fromkeys(xs)) # order-preserving
Python set(xs) deduplicates but loses order; dict.fromkeys keeps it.
Numeric range
TypeScript
Array.from({ length: 5 }, (_, i) => i)
Python 3.14+
list(range(5))
Read with a fallback
footgun
TypeScript
obj.key ?? "default"
Python 3.14+
d.get("key", "default")
d["key"] raises KeyError; there is no silent undefined.
Merge / override
TypeScript
{ ...a, k: v }
Python 3.14+
{**a, "k": v} # or a | {"k": v} (3.9+)
Iterate key/value pairs
TypeScript
Object.entries(obj)
Python 3.14+
d.items()
Keys / values
TypeScript
Object.keys(o) / Object.values(o)
Python 3.14+
d.keys() / d.values()
Build a mapping from a list
TypeScript
Object.fromEntries(xs.map(x => [x.id, x]))
Python 3.14+
{x.id: x for x in xs}
Key exists
TypeScript
"k" in obj
Python 3.14+
"k" in d
Remove a key
TypeScript
delete obj.k
Python 3.14+
del d["k"] # or d.pop("k", None)
Set algebra
TypeScript
no built-in, filter over a Set
Python 3.14+
a | b, a & b, a - b, a ^ b
Safe nested access
footgun
TypeScript
a?.b?.c
Python 3.14+
a.get("b", {}).get("c") # or try/except
Python has no ?.. The idiom is EAFP. Attempt the access and catch it, rather than testing first.
Typed record
TypeScript
interface User { id: string }
Python 3.14+
@dataclass
class User:
id: str
Anonymous function
footgun
TypeScript
(a, b) => a + b
Python 3.14+
lambda a, b: a + b
A lambda body is a single expression. No statements, no multi-line blocks.
Default parameter
footgun
TypeScript
function f(xs = []) {}
Python 3.14+
def f(xs=None):
xs = [] if xs is None else xs
Python evaluates defaults once at definition time, so a mutable default is shared across every call. JS evaluates them per call.
Variadic arguments
TypeScript
function f(...args) {}
Python 3.14+
def f(*args, **kwargs): ...
Force named arguments
TypeScript
function f({ apiKey, timeout = 30 }) {}
Python 3.14+
def f(*, api_key: str, timeout: int = 30): ...
Write to an enclosing variable
footgun
TypeScript
let n = 0; const inc = () => { n += 1 }
Python 3.14+
n = 0
def inc():
nonlocal n # or global at module level
n += 1
Assigning to a name makes it local for the whole function unless declared nonlocal/global. Reading alone needs no declaration.
Lazy sequence
TypeScript
function* gen() { yield 1 }
Python 3.14+
def gen():
yield 1
Bind leading arguments
TypeScript
f.bind(null, 1)
Python 3.14+
functools.partial(f, 1)
Wrap a function
TypeScript
const wrapped = withLog(f)
Python 3.14+
@with_log
def f(): ...
Start the async world
footgun
TypeScript
await main() // top-level await
Python 3.14+
asyncio.run(main())
Node keeps an event loop running always. Python has no loop until you start one. An un-awaited coroutine simply never executes.
Run concurrently, fail fast
TypeScript
await Promise.all([p1, p2])
Python 3.14+
await asyncio.gather(t1, t2)
Run concurrently, collect errors
TypeScript
await Promise.allSettled([p1, p2])
Python 3.14+
await asyncio.gather(t1, t2, return_exceptions=True)
First to settle wins
TypeScript
await Promise.race([p1, p2])
Python 3.14+
await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
Start work without awaiting it yet
footgun
TypeScript
const p = fetchUser() // already running
Python 3.14+
task = asyncio.create_task(fetch_user())
A Promise starts on creation; a coroutine object does nothing until awaited or wrapped in a task. Calling an async def and dropping the result is a silent no-op.
Run tasks that all share one lifetime, cancel siblings on failure
footgun
TypeScript
await Promise.all([p1, p2]) // siblings keep running on rejection
Python 3.14+
async with asyncio.TaskGroup() as tg:
tg.create_task(coro1())
tg.create_task(coro2())
# except* ExceptionGroup to catch failures
A TaskGroup failure raises an ExceptionGroup caught only by except*, and no task survives the block, unlike Promise.all where abandoned siblings finish in the background.
Delay
TypeScript
await new Promise(r => setTimeout(r, 1000))
Python 3.14+
await asyncio.sleep(1)
Abort slow work
TypeScript
AbortSignal.timeout(5000)
Python 3.14+
async with asyncio.timeout(5): ...
Limit concurrency
TypeScript
p-limit / a manual queue
Python 3.14+
sem = asyncio.Semaphore(3)
async with sem: ...
Iterate an async stream
TypeScript
for await (const x of stream)
Python 3.14+
async for x in stream:
Catch a specific failure
footgun
TypeScript
try { ... } catch (e) { if (!(e instanceof T)) throw e }
Python 3.14+
try:
...
except ValueError as e:
...
JS catches everything and re-throws; Python filters by exception type in the clause.
Always run / run only on success
TypeScript
try { ... } finally { ... }
Python 3.14+
try:
...
except E:
...
else:
# only if no exception
finally:
...
Raise
TypeScript
throw new Error("boom")
Python 3.14+
raise ValueError("boom")
Wrap and preserve the cause
TypeScript
throw new Error("ctx", { cause: e })
Python 3.14+
raise RuntimeError("ctx") from e
Domain-specific error type
TypeScript
class NotFound extends Error {}
Python 3.14+
class NotFound(Exception): ...
Guard vs attempt
footgun
TypeScript
if (obj?.key) use(obj.key) // LBYL
Python 3.14+
try:
use(d["key"])
except KeyError:
... # EAFP
Idiomatic Python attempts and catches rather than checking first. try costs nothing when no exception is raised.
Read a whole text file
TypeScript
await readFile("a.txt", "utf8")
Python 3.14+
Path("a.txt").read_text()
Write a text file
TypeScript
await writeFile("a.txt", data)
Python 3.14+
Path("a.txt").write_text(data)
Scoped handle
TypeScript
const fh = await open(p); try { ... } finally { await fh.close() }
Python 3.14+
with open(p) as fh:
...
Stream lines without loading the file
TypeScript
createInterface({ input: createReadStream(p) })
Python 3.14+
with open(p) as fh:
for line in fh: ...
Parse / serialise JSON
footgun
TypeScript
JSON.parse(s) / JSON.stringify(o)
Python 3.14+
json.loads(s) / json.dumps(o)
json.dumps writes Python None/True as JSON null/true, but tuples become arrays and dict keys are coerced to strings.
Build a path
TypeScript
path.join(a, b)
Python 3.14+
Path(a) / b
Environment variable with a default
TypeScript
process.env.KEY ?? "x"
Python 3.14+
os.environ.get("KEY", "x")
Find files by pattern
TypeScript
await glob("**/*.ts")
Python 3.14+
Path(".").rglob("*.py")