/r/typescript
TypeScript is a language for application-scale JavaScript development.
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
Resources
Language
Discussion
/r/typescript
I've never written unit tests in a language like typescript before where the consumer of my code may themselves not be types, or may have a different strictness level of types, or may be wildly casting types as 'any'. Do you ever consider these cases in testing?
It seems almost ridiculous to ask, because if the answer is yes, then why not consider it in the function itself? Why not wrap every parameter to every function in type guards for safety, and at that point why even write in typescript? Let's not go down that road...
But that leaves the behavior undefined. For reference, I'm writing a library, and I have two identical functions. One is fast and dangerous, relying entirely on my type system to validate parameters and a bunch of casting happening inside. The other is slower but is littered with type guards. They each pass all the same test cases but the faster one is unpredictable if typescript is circumvented and bad parameters are passed; sometimes it will throw, sometimes it will return undefined, sometimes it will do the unexpected. Should I even care?
The monthly thread for people to post openings at their companies.
* Please state the job location and include the keywords REMOTE, INTERNS and/or VISA when the corresponding sort of candidate is welcome. When remote work is not an option, include ONSITE.
* Please only post if you personally are part of the hiring company—no recruiting firms or job boards **Please report recruiters or job boards**.
* Only one post per company.
* If it isn't a household name, explain what your company does. Sell it.
* Please add the company email that applications should be sent to, or the companies application web form/job posting (needless to say this should be on the company website, not a third party site).
Commenters: please don't reply to job posts to complain about something. It's off topic here.
Readers: please only email if you are personally interested in the job.
Posting top level comments that aren't job postings, [that's a paddlin](https://i.imgur.com/FxMKfnY.jpg)
I need to process key value pair objects from an api but I have no idea about their structure or how deep they are.
For example:
function processApiObject(x: object) {
if ( x.domain === "example" ) {
// Do something ...
}
}
I want to avoid using just object.
I think it’s pretty common to have an array of a string union type. Like:
const a = [‘a’, ‘b’] as const;
Type U = (typeof a)[number];
Now, if I want to use this to check if some value is a U I’d like to do:
a.includes(someString);
Of course, this gives an error because string isn’t assignable to the type of the array - but that’s exactly what I need it for. So far, I use this:
(a as string[]).includes(someString)
Which… meh, it’s ok, but it is really lying to the compiler. I know that a is of type U[], not string[].
Is there a good way to do this?
Such that, for instance, an argument could be constrained to between zero and one, and if you tried to pass in a value that was outside of that range, you’d get a type error. There are some workarounds for similar behavior, but first class support would be neat
I can do the following:
type Kid = [ string, string, number ]; type ReadonlyKid = readonly [ string, string, number ]; type KidTuple = { readonly [ K in keyof Kid ]: Kid[K] }; type KidTuple2 = { readonly [ K in keyof ReadonlyKid ]: ReadonlyKid[K] }; const testKid1: KidTuple = [ 'Noah', 'Ortiz', 7 ]; testKid1.pop(); const testKid2: KidTuple2 = [ 'Noah', 'Ortiz', 7 ]; testKid2.pop(); // <-- doesn't work as expected
The ReadonlyKid type makes it so that you're unable to pop or push elements in the tuple. However, I needed to create this ReadonlyKid type to make this work. If we only had access to the Kid type which is from some third party library, how would I create a similarly readonly tuple based on it?
I can't do the following instead:
type ReadonlyKid = readonly Kid;
because that gets flagged by typescript as only being allowed on array or literal tuple types.
Is there any way to accomplish this using the readonly keyword, not Readonly<T>?
p.s. I don't know why carriage returns are not working in the code-block.
Hi, i have a monorepo:
web (vite react app)
api (expressJs backend)
schema (shared local package, which is used by web and api)
The idea is: when builded, web
and api
must resolve import from @my-monorepo/schema
to schema's dist/index.js
, while during development i need it to point to src/
.ts file.
To achieve this i am trying to use project references
https://www.typescriptlang.org/docs/handbook/project-references.html
The problem is:
During development web
package resolves @my-monorepo/schema
to /schema/DIST/types/index
. And does not provide autocompletion. To make it work as i want i need to manually type @my-monorepo/schema/SRC
But api
works as expected @my-monorepo/schema
resolved to /schema/src/index
and autompletion works fine.
What tsconfig settings can affect this?
schema package.json
has entry point to builded dist
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/types/index.d.ts",
schema tsconfig.json
:
"composite": true, // enabled for references
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"rootDir": "src",
"baseUrl": "./src",
"outDir": "dist",
"declarationDir": "dist/types",
...
"include": ["src/**/*"],
"exclude": ["dist"],
...
web
and api
tsconfigs both have references specified:
"references": [{ "path": "../schema" }]
I've re-read it multiple times now and I know that it's a special config with a special use-case but I'm writing a full-fledged course and I would really love to include the explanation of this option.
I feel like my head is stuck on repeat, anybody able to explain it? https://www.typescriptlang.org/tsconfig/#customConditions
I'm looking for an official documentation on each error where you can search for something like TSxxxx and you find an entry with information about the error, how to debug it, common gotchas etc.
Does that exist? Obviously most of us use Stack Overflow, but do people first learn about an error and why it occurs?
Hey,
I want to use chatGPT as a sort of API that returns JSON and therefore want to tell it what type it should return as. It does that really well when using the UI. Something like: "Give me a list of 5 countries. Return JSON only in the format of { countries: string [] }.
For my implementation i want to pass that type from typescript into my prompt. Like so
"useGPT<{ countries: string[] }>('Give me a list of 5 countries')"
Is it possible to create a string from that Generic Type that I can pass into a string prompt?
Help is appreciated 🙏
Hey everyone, I am software engineer who usually works in other languages, but have decided to pick up TS for my latest project. I am looking for recommendation on what technologies could I utilize. I hate these kind of questions, but to be completely honest, the whole ecosystem is so vast, it's very difficult to get a hold of things.
We have an expo app, and would like to create a monorepo, we need basic CRUD functionalities with support for AI Agents and LLM prompting.
Current ideas are:
Priorities are dev experience and testability, I'd expect decent performance from any framework in 2025. Simplicity and low mental overhead is always a plus.
What do you think? Any technologies that would better fit my usecase, or any that I've missed?
I have a "working" script that connects to postgresql. This script works perfectly fine in another machine. However, I am trying to re-setup the project to another machine. Despite following almost the same step (some naming being different, but nothing major).
This is the db.ts
import { Pool } from 'pg';
import dotenv from 'dotenv';
// Load environment variables from the .env file in the src directory
const result = dotenv.config({ path: './src/.env' });
if (result.error) {
throw new Error('Failed to load .env file. Please ensure it exists in the src directory.');
}
console.log('Database credentials:');
console.log('User:', process.env.POSTGRES_USER);
console.log('Host:', process.env.POSTGRES_HOST);
console.log('Database:', process.env.POSTGRES_DATABASE);
console.log('Password:', process.env.POSTGRES_PASSWORD ? '****' : 'Not Set');
console.log('Port:', process.env.POSTGRES_PORT);
const pool = new Pool({
user: process.env.POSTGRES_USER,
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
password: process.env.POSTGRES_PASSWORD,
port: Number(process.env.POSTGRES_PORT),
});
// Function to fetch data for processing
export const databaseConnection = async () => {
let client;
try {
console.log('Attempting to connect to the database...');
client = await pool.connect();
console.log('Database connection successful.');
`const query = ``
SELECT
id AS "rowId",
contract_address AS "tokenAddress",
asset_id AS "assetId",
FROM public.custom_action_signal
ORDER BY RANDOM() -- Randomize the rows
LIMIT 50
\
;`
const result = await client.query(query);
console.log('Query Results:');
console.table(result.rows);
return result.rows; // Return the rows to be used in createOffer.ts
} catch (error: unknown) {
if (error instanceof Error) {
console.error('Database connection or query failed:', error.message);
} else {
console.error('Unknown error occurred during database connection or query.');
}
process.exit(1);
} finally {
if (client) {
client.release();
console.log('Database connection closed.');
}
}
};
// Function to update a row in the custom_action_signal table
export const updateCustomActionSignal = async (rowId: number, orderHash: string) => {
try {
`const query = ``
UPDATE public.custom_action_signal
SET
done_custom_bot_action = true,
some_var = $1,
modified_timestamp = NOW()
WHERE id = $2
\
;`
const values = [orderHash, rowId];
await pool.query(query, values);
console.log(\
Successfully updated row with ID ${rowId}`);`
} catch (error) {
console.error(\
Error updating row with ID ${rowId}:`, error);`
}
};
export default databaseConnection;
My set up is running the .ts build within WSL within VSCode. I got my IP address via "ipconfig", and then added that into the `pg_hba.conf`. As a check, I use the same credential and successfully log into the Postgresql db via the SQL shell (psql).
However, when I run my script, the same credential gives me this error: Database connection or query failed: connect ETIMEDOUT 192.168.1.875:5432
Again, I am not too familiar with this type of DB issues, and I can't figure out why I did the exact same step on another machine without any connection issue.
What can I try? How can I debug?
Sorry for the wordy title. It's always hard for me to explain typescript stuff concisely!
My problem is pretty simple. Say you have an object type that has two functions. It looks like this:
type invalidator<TArgs extends unknown[]> = {
fn: (...args: TArgs) => any;
genSetKey: (...args: TArgs) => string;
};
The point of this type is that the arguments supplied to genSetKey
must match the args supplied to fn
. This works fine.
The problem is when I try to make an object type, where each property is one of these "invalidator" objects.
This is what I've tried so far:
type invalidatorObj<TInvalidatorMap extends Record<string, unknown[]>> = {
[K in keyof TInvalidatorMap]: invalidator<TInvalidatorMap[K]>;
};
But TS doesn't care if I provide different argument types for each fn
and genSetKey
.
I'm guessing that the issue is that Record
is too... loose? Like TS isn't keeping track of the relationship between each key and each value?
Here's a TS playground link demonstrating the lack of type errors
Having an issue getting decorators to use the TS5 definition. Using React 18/Vite. I have TS 5.7.3 installed in my project Checked npm list and that is the only version being used (no conflicting dependencies),
I do not have experimental decorators set (event tried explicitly setting it to false)
all my configs are referencing ESNext
"target": "ESNext",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"module": "ESNext",
using plugins: [react({ tsDecorators: true })] in vite.config
but it's still using the 3 argument definition
(react-ts-swc template)
Storing custom claims (like role='admin') on your auth tokens seems to be the most common way of handling authorization, but it seems less than ideal for some use cases since as far as I can tell permissions can't be instantly revoked (since the claims are stored on the auth token until it expires).
So it seems that to avoid this, the best way of handling authorization is to use DB queries. Only problem is, how do you make it as efficient as possible?
Right now I'm using Postgres / Drizzle / TS for my backend. My initial approach was to create reusable queries that checked authorization, like this:
const isAdmin = (clubId: number) => {
const result = db.select... // Query for checking if user is admin of club with clubId
return !!result
}
And then you can call that from any given endpoint that requires admin status, and return error status if needed. But this adds an extra round-trip to the DB, which adds unnecessary latency, and sometimes more than one check is needed (e.g. isAdmin, isOwnerOfProperty, etc.)
How do you guys handle situations like these? I know I could just write the authorization logic into every individual query, but it seems like there'd be a better way to do that where you can reuse the logic.
Also, any thoughts on RLS? Seems like a pretty good solution but it doesn't appear to be super popular, and I'm wondering if there's a reason.
Thanks!
Recently I've played around with https://www.better-auth.com, and noticed 2 things:
The first was sad, the second frustrating.
Looking into this, I found https://github.com/better-auth/better-auth/issues/1252 which has some suspicions but no real concrete answers or explanations. I sort of just shrugged at this, and decided to try and fix up their typing issue so it's a bit more pleasant to use.
Disclaimer I haven't looked into LSP or how is implemented and my suspicions are based on educated guesses of how I'd expect it to work
Now, after a few hours of reworking and cleaning up their types, I noticed a reasonable number of repeated inline types, and allot of ReturnType<typeof (some func)>
, which got me wondering if the lack of explicit typing, and use of inline typing, would contribute to problems with LSP lookups due to difficulty indexing types?
As an additional, I'd appreciate if anyone could tell me if using the CPU profiling in tsc
would provide adequate information to confirm my suspicions, or would it be more appropriate to dig into the LSP server to figure out the problems
SOLVED: Although, it is weird behavior, it looks as though if you have an implementation similar to mine where the Generic Parameter (TEvents
per my example) is indirectly referenced in the class, then the inference of that generic parameter from child classes will fail.
e.g., per my example __listeners
was declared as a type of Partial<Record<keyof TEvents, Function[]>>
, so it was indirectly referencing the TEvents
generic parameter, meaning inference from a child class would fail. However, if you have a variable that directly references the generic parameter (I added a #__ignore
variable typed as TEvents
) then type inference from a child class will successfully yield what you're looking for.
Non-working example:
type InferParam<T extends MyClass<any>> = T extends MyClass<infer U> ? U : never;
class MyClass<T extends Record<string, any>> {
}
class MyChildClass extends MyClass<{ test: number }> {}
const x: InferParam<MyChildClass> = {}; // typescript will NOT yell at you for this.
Working example:
type InferParam<T extends MyClass<any>> = T extends MyClass<infer U> ? U : never;
class MyClass<T extends Record<string, any>> {
// notice this variable
#__ignore: T;
}
class MyChildClass extends MyClass<{ test: number }> {}
const x: InferParam<MyChildClass> = {}; // typescript will yell at you
// expecting that `x` should be a type of `{ test: number }`
ORIGINAL QUESTION:
I am trying to make a custom AsyncEventEmitter class to handle asynchronous events. I was able to successfully get a class to work functionally, but I wanted to make a specific type for getting the Listener type, so I can declare functions separately. Here is a short excerpt of what I am working with on TS playground
Essentially, what I want is this:
class AsyncEventEmitter<TEvents extends Record<string, any[]>> {}
class MyAsyncEventEmitter extends AsyncEventEmitter<{ test: [a: number, b: string]}> {}
type AsyncEvents<TEmitter extends AsyncEventEmitter<any>> = TEmitter extends AsyncEventEmitter<infer TEvents> ? TEvents : never;
type AsyncEventListener<TEmitter extends AsyncEventEmitter<any>, TEvent extends keyof AsyncEvents<TEmitter>> = (...args: AsyncEvents<TEmitter>[TEvent]) => void|Promise<void>;
// forgive me, I write all of my TypeScript in JSDOC,
// so I declare the function using JSDOC here since I don't remember off the top of my head on how to type a Function in TS
/** @type {AsyncEventListener<MyAsyncEventEmitter, "test">} */
function test(a,b) {
// intellisense should pick up that parameter [a] is a number and parameter [b] is a string.
}
The above example is essentially what I have in the TS playground, but you'll see that the function test(a,b)
does not properly infer the types a
and b
as number
and string
(respectively). Instead it is inferred as any
and any
.
If I explicitly use the AsyncEvents
custom type, as defined above, then I will only ever get a Record<string, any[]>
type.
e.g.,
const events: AsyncEvents<MyAsyncEventEmitter> = {
};
The above code, if AsyncEvents
worked as I expected, should throw an error, as events
should have the "test"
key inside its object and a value for that property being [{number}, {string}]
.
Instead, events
is typed as a Record<string, any[]>
.
I've never had an issue with inferring generic type parameters before, so I am wondering what I could be doing differently that is causing this behavior.
Thank you in advance.
Another side-note: I am aware there is an async-event-emitter
library, but this project requires us to have a little bit more control over the library, and it was simple enough to write one of our own.
After embarrassing myself at a job interview I want to learn react, already started learning TS. Need recommendations on resources to learn both these technologies together.
Preferably through doing a project. Im just going to small YT tutorials and then documentation on internet to learn TS.
Hi am a full stack noob here learning react from odin project. I thought practicing ts from now itself will improve myself. But when developing react project i kinda hit my nerve with using TS and start to use 'any' type and sometimes I just code in js in a ts file.
Any tips on how to rewrite legacy php code (code igniter) into NESTJS and REACT , and migrating from MySQL5 to MySQL8 plus adding new features for a delivery like web app. note: I haven't worked in this project and I haven't even seen the code base yet, I start next week.
The "satisfies" operator is one of my favorite newer TS features. I use it all the time. However, it seems arbitrarily limited to me to only be applied to expressions, but not to types themselves, and I was curious if anyone knows why this is?
For those wondering why I'd want it available at the type level, perhaps the most obvious use case is creating two types where you've guaranteed they at least share the same set of keys, even if their value types may differ. Of course, there are an infinite number of applications, but this is the most common. An example of what I wish we could write:
// I want to enforce, at the TYPE level, that the keys of RecordOne and RecordTwo are the same,
// so that a change in one spot to their keys forces both types to be updated.
type RecordOne = { key1: number, key2: number, key3: number };
type RecordTwo = { key1: string, key2: string, key3: string };
// So I declare a type with the keys:
type SharedKeys = 'key1' | 'key2' | 'key3';
// And then I use this type to enforce that the keys are the same, but I cannot because TS limits "satisfies" to only code expressions.
type RecordOneWithSatisfies = { key1: number, key2: number, key3: number } satisfies Record<SharedKeys, unknown>;
type RecordTwoWithSatisfies = { key1: string, key2: string, key3: string } satisfies Record<SharedKeys, unknown>;