Table definition has 'any' type

I'm defining all of my tables in an index.ts file; but on some tables like visitor_events I get this errors; 'visitor_events' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. On other tables however, I don't have the error and the PgTableWithColumns is correctly infered. I've restarted TS Server and VSCode but with no success.
6 Replies
sevenwestonroads
sevenwestonroads16mo ago
Ok so I've done a bit of research and here's some context. The error seems to be linked to a circular reference - telling me that something's wrong in my schema. I have 2 tables: visitorEvents and synchronisations - with circular reference that I defined in Prisma with specific names I had given for relations (which wasn't a problem in Prisma, I learned that naming relations explicitly does NOT results in a modified SQL schema). Here was my previous schemas
export const visitor_events = pgTable('visitor_events', {
// ... fields
});

export const synchronisations = pgTable('synchronisations', {
// ... fields
firstVisitorEventId: integer("first_visitor_event_id").references(() => visitor_events.id),
lastVisitorEventId: integer("last_visitor_event_id").references(() => visitor_events.id),
});
export const visitor_events = pgTable('visitor_events', {
// ... fields
});

export const synchronisations = pgTable('synchronisations', {
// ... fields
firstVisitorEventId: integer("first_visitor_event_id").references(() => visitor_events.id),
lastVisitorEventId: integer("last_visitor_event_id").references(() => visitor_events.id),
});
So I ended up doing another table to define this relationship like below.
export const visitor_events = pgTable('visitor_events', {
// ... fields
});

export const synchronisations = pgTable('synchronisations', {
// ... fields
});

export const synchronisation_batches = pgTable('synchronisation_batches', {
// ... fields
synchronisationId: integer('synchronisation_id')
.references(() => synchronisations.id)
.notNull(),
startEventId: integer('start_event_id')
.references(() => visitor_events.id)
.notNull(),
endEventId: integer('end_event_id')
.references(() => visitor_events.id)
.notNull(),
});
export const visitor_events = pgTable('visitor_events', {
// ... fields
});

export const synchronisations = pgTable('synchronisations', {
// ... fields
});

export const synchronisation_batches = pgTable('synchronisation_batches', {
// ... fields
synchronisationId: integer('synchronisation_id')
.references(() => synchronisations.id)
.notNull(),
startEventId: integer('start_event_id')
.references(() => visitor_events.id)
.notNull(),
endEventId: integer('end_event_id')
.references(() => visitor_events.id)
.notNull(),
});
The error disappeared. Here are my following up questions; 1. is typescript unable to infer type is expected behaviour ? 2. can I get more specific errors ? 3. more generally, if pgTable unallows circular references, why ? does it have to do with the order on which my tables are defined - circular references making it impossible to put one before the other ? Context: this is an analytics use case where I need to have a synchronisations table to keep track of a given batch of events to process Seems linked to https://discord.com/channels/1043890932593987624/1043890932593987627/1092514104201195521 Now when I go back to my previous implementation but by putting a AnyPgColumn like below - I still have circular reference but no errors
export const visitor_events = pgTable('visitor_events', {
// ... fields
});

export const synchronisations = pgTable('synchronisations', {
// ... fields
firstVisitorEventId: integer('first_event_id').references((): AnyPgColumn => visitor_events.id),
lastVisitorEventId: integer('last_event_id').references((): AnyPgColumn => visitor_events.id),
});
export const visitor_events = pgTable('visitor_events', {
// ... fields
});

export const synchronisations = pgTable('synchronisations', {
// ... fields
firstVisitorEventId: integer('first_event_id').references((): AnyPgColumn => visitor_events.id),
lastVisitorEventId: integer('last_event_id').references((): AnyPgColumn => visitor_events.id),
});
Why is that ? Thank you 🙏
tacomanator
tacomanator16mo ago
This is in the docs:
sisterCityId: integer('sister_city_id').references((): AnyPgColumn => cities.id), // self-referencing foreign key
sisterCityId: integer('sister_city_id').references((): AnyPgColumn => cities.id), // self-referencing foreign key
You need the AnyPgColumn to prevent the error
sevenwestonroads
sevenwestonroads16mo ago
But why ? Is it unsafe to do so ?
tacomanator
tacomanator16mo ago
I'm not familiar with the details of why. You could do it without AnyPgColumn but it would have to be separated out. This way is a lot cleaner. Unsafe is a relative word. It technically would work without it, but you're going to get a TypeScript error if you don't either separate it out or use AnyPgColumn but I would use AnyPgColumn so you have less manual work to do and your definitions are together.
sevenwestonroads
sevenwestonroads16mo ago
I see thank you. I think it's a TypeScript error and not a pgTable error - as it's possible to have a circular reference in PG but not in TypeScript sense making it impossible to do table definitions containing circular reference in TS without having the AnyPgColumn After reading more about it - I'm going to keep a separate table for my special business use case
bloberenober
bloberenober16mo ago
it's not unsafe, the function signature is the same even without the explicit type annotation it just helps TypeScript to understand there's no actual circular type dependency