Skip to content

Commit 61ba089

Browse files
committed
fix(zero-schema): Fix an issue with TS2589
TS2589: Type instantiation is excessively deep and possibly infinite The hint to solve this was here: microsoft/TypeScript#30188 (comment) The solution is to compute the types that cause problems step by step. By using `T extends infer U`, we can force the computation of `T` instead of deferring it. This way the instantiation does not get deeper. instantiation is excessively deep and possibly infinite
1 parent c5d7dd4 commit 61ba089

File tree

2 files changed

+247
-26
lines changed

2 files changed

+247
-26
lines changed

packages/zero-schema/src/builder/schema-builder.test.ts

+235-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
/**
2-
* Relationships as secondary.
3-
*/
4-
51
import {expectTypeOf, test} from 'vitest';
6-
import {table, number, string} from './table-builder.js';
7-
import {relationships} from './relationship-builder.js';
82
import type {Query} from '../../../zql/src/query/query.js';
3+
import {relationships} from './relationship-builder.js';
94
import {createSchema} from './schema-builder.js';
5+
import {number, string, table} from './table-builder.js';
106

117
const mockQuery = {
128
select() {
@@ -235,3 +231,236 @@ test('building a schema', () => {
235231
}[]
236232
>();
237233
});
234+
235+
test('too many relationships', () => {
236+
function makeTable<const N extends string>(name: N) {
237+
return table(name)
238+
.columns({
239+
id: string(),
240+
next: string(),
241+
})
242+
.primaryKey('id');
243+
}
244+
245+
const a = makeTable('a');
246+
const b = makeTable('b');
247+
const c = makeTable('c');
248+
const d = makeTable('d');
249+
const e = makeTable('e');
250+
const f = makeTable('f');
251+
const g = makeTable('g');
252+
const h = makeTable('h');
253+
const i = makeTable('i');
254+
const j = makeTable('j');
255+
const k = makeTable('k');
256+
const l = makeTable('l');
257+
const m = makeTable('m');
258+
const n = makeTable('n');
259+
const o = makeTable('o');
260+
const p = makeTable('p');
261+
const qt = makeTable('q');
262+
const r = makeTable('r');
263+
const s = makeTable('s');
264+
const t = makeTable('t');
265+
const u = makeTable('u');
266+
const v = makeTable('v');
267+
const w = makeTable('w');
268+
const x = makeTable('x');
269+
const y = makeTable('y');
270+
const z = makeTable('z');
271+
272+
const schema = createSchema(1, {
273+
tables: [
274+
a,
275+
b,
276+
c,
277+
d,
278+
e,
279+
f,
280+
g,
281+
h,
282+
i,
283+
j,
284+
k,
285+
l,
286+
m,
287+
n,
288+
o,
289+
p,
290+
qt,
291+
r,
292+
s,
293+
t,
294+
u,
295+
v,
296+
w,
297+
x,
298+
y,
299+
z,
300+
],
301+
relationships: [
302+
relationships(a, ({one}) => ({
303+
toB: one({
304+
sourceField: ['id'],
305+
destField: ['next'],
306+
destSchema: b,
307+
}),
308+
toC: one({
309+
sourceField: ['id'],
310+
destField: ['next'],
311+
destSchema: c,
312+
}),
313+
toD: one({
314+
sourceField: ['id'],
315+
destField: ['next'],
316+
destSchema: d,
317+
}),
318+
toE: one({
319+
sourceField: ['id'],
320+
destField: ['next'],
321+
destSchema: e,
322+
}),
323+
toF: one({
324+
sourceField: ['id'],
325+
destField: ['next'],
326+
destSchema: f,
327+
}),
328+
toG: one({
329+
sourceField: ['id'],
330+
destField: ['next'],
331+
destSchema: g,
332+
}),
333+
toH: one({
334+
sourceField: ['id'],
335+
destField: ['next'],
336+
destSchema: h,
337+
}),
338+
toI: one({
339+
sourceField: ['id'],
340+
destField: ['next'],
341+
destSchema: i,
342+
}),
343+
toJ: one({
344+
sourceField: ['id'],
345+
destField: ['next'],
346+
destSchema: j,
347+
}),
348+
toK: one({
349+
sourceField: ['id'],
350+
destField: ['next'],
351+
destSchema: k,
352+
}),
353+
toL: one({
354+
sourceField: ['id'],
355+
destField: ['next'],
356+
destSchema: l,
357+
}),
358+
toM: one({
359+
sourceField: ['id'],
360+
destField: ['next'],
361+
destSchema: m,
362+
}),
363+
toN: one({
364+
sourceField: ['id'],
365+
destField: ['next'],
366+
destSchema: n,
367+
}),
368+
toO: one({
369+
sourceField: ['id'],
370+
destField: ['next'],
371+
destSchema: o,
372+
}),
373+
toP: one({
374+
sourceField: ['id'],
375+
destField: ['next'],
376+
destSchema: p,
377+
}),
378+
toQ: one({
379+
sourceField: ['id'],
380+
destField: ['next'],
381+
destSchema: qt,
382+
}),
383+
toR: one({
384+
sourceField: ['id'],
385+
destField: ['next'],
386+
destSchema: r,
387+
}),
388+
toS: one({
389+
sourceField: ['id'],
390+
destField: ['next'],
391+
destSchema: s,
392+
}),
393+
toT: one({
394+
sourceField: ['id'],
395+
destField: ['next'],
396+
destSchema: t,
397+
}),
398+
toU: one({
399+
sourceField: ['id'],
400+
destField: ['next'],
401+
destSchema: u,
402+
}),
403+
toV: one({
404+
sourceField: ['id'],
405+
destField: ['next'],
406+
destSchema: v,
407+
}),
408+
toW: one({
409+
sourceField: ['id'],
410+
destField: ['next'],
411+
destSchema: w,
412+
}),
413+
toX: one({
414+
sourceField: ['id'],
415+
destField: ['next'],
416+
destSchema: x,
417+
}),
418+
toY: one({
419+
sourceField: ['id'],
420+
destField: ['next'],
421+
destSchema: y,
422+
}),
423+
toZ: one({
424+
sourceField: ['id'],
425+
destField: ['next'],
426+
destSchema: z,
427+
}),
428+
})),
429+
],
430+
});
431+
432+
const q = mockQuery as unknown as Query<typeof schema, 'a'>;
433+
const q2 = q
434+
.related('toB')
435+
.related('toC')
436+
.related('toD')
437+
.related('toE')
438+
.related('toF')
439+
.related('toG')
440+
.related('toH')
441+
.related('toI')
442+
.related('toJ')
443+
.related('toK')
444+
.related('toL')
445+
.related('toM')
446+
.related('toN')
447+
.related('toO')
448+
.related('toP')
449+
.related('toQ')
450+
.related('toR')
451+
.related('toS')
452+
.related('toT')
453+
.related('toU')
454+
.related('toV')
455+
.related('toW')
456+
.related('toX')
457+
.related('toY')
458+
.related('toZ');
459+
460+
// Before this commit the below line would generate 2 TS errors. One for the type number
461+
// but more importantly it used to raise:
462+
// TS2589: Type instantiation is excessively deep and possibly infinite
463+
464+
// @ts-expect-error type 'number' does not satisfy the constraint
465+
expectTypeOf(q2).toEqualTypeOf<123>();
466+
});

packages/zql/src/query/query.ts

+12-20
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import type {Expand, ExpandRecursive} from '../../../shared/src/expand.js';
3+
import type {Schema as ZeroSchema} from '../../../zero-schema/src/builder/schema-builder.js';
24
import type {
35
LastInTuple,
6+
SchemaValueToTSType,
47
TableSchema,
58
} from '../../../zero-schema/src/table-schema.js';
6-
import type {SchemaValueToTSType} from '../../../zero-schema/src/table-schema.js';
79
import type {ExpressionFactory, ParameterReference} from './expression.js';
810
import type {TypedView} from './typed-view.js';
9-
import type {Expand, ExpandRecursive} from '../../../shared/src/expand.js';
10-
import type {Schema as ZeroSchema} from '../../../zero-schema/src/builder/schema-builder.js';
1111

1212
type Selector<E extends TableSchema> = keyof E['columns'];
1313
export type NoJsonSelector<T extends TableSchema> = Exclude<
@@ -67,23 +67,15 @@ type DestRow<
6767
? PullRow<DestTableName<TTable, TSchema, TRelationship>, TSchema>
6868
: PullRow<DestTableName<TTable, TSchema, TRelationship>, TSchema> | undefined;
6969

70-
type AddSubreturn<
71-
TExistingReturn,
72-
TSubselectReturn,
73-
TAs extends string,
74-
> = undefined extends TExistingReturn
75-
?
76-
| (Exclude<TExistingReturn, undefined> & {
77-
readonly [K in TAs]: undefined extends TSubselectReturn
78-
? TSubselectReturn
79-
: readonly TSubselectReturn[];
80-
})
81-
| undefined
82-
: TExistingReturn & {
83-
readonly [K in TAs]: undefined extends TSubselectReturn
84-
? TSubselectReturn
85-
: readonly TSubselectReturn[];
86-
};
70+
type AddSubreturn<TExistingReturn, TSubselectReturn, TAs extends string> = {
71+
readonly [K in TAs]: undefined extends TSubselectReturn
72+
? TSubselectReturn
73+
: readonly TSubselectReturn[];
74+
} extends infer TNewRelationship
75+
? undefined extends TExistingReturn
76+
? (Exclude<TExistingReturn, undefined> & TNewRelationship) | undefined
77+
: TExistingReturn & TNewRelationship
78+
: never;
8779

8880
export type PullTableSchema<
8981
TTable extends string,

0 commit comments

Comments
 (0)