Skip to content

Commit 9259bc4

Browse files
committed
[union] Type-check schema defaults
1 parent e3a8be2 commit 9259bc4

7 files changed

Lines changed: 244 additions & 51 deletions

File tree

src/@types/_internal/store/with-schemas/index.d.ts

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import type {
55
OptionalTablesSchema,
66
OptionalValuesSchema,
77
Store,
8+
TablesSchema,
89
Value,
10+
ValuesSchema,
911
} from '../../../store/with-schemas/index.d.ts';
1012

1113
export type TableIdFromSchema<Schema extends OptionalTablesSchema> = AsId<
@@ -94,10 +96,10 @@ export type CellIsDefaultedFromSchema<
9496
CellId extends CellIdFromSchema<Schema, TableId>,
9597
Then,
9698
Else,
97-
> = Schema[TableId][CellId] extends {
98-
default: infer _;
99-
}
100-
? Then
99+
> = Schema[TableId][CellId] extends {default: infer Default}
100+
? [Default] extends [Cell<Schema, TableId, CellId>]
101+
? Then
102+
: Else
101103
: Else;
102104

103105
export type CellIsRequiredFromSchema<
@@ -190,12 +192,45 @@ export type ValueIsDefaultedFromSchema<
190192
ValueId extends ValueIdFromSchema<Schema>,
191193
Then,
192194
Else,
193-
> = Schema[ValueId] extends {
194-
default: infer _;
195-
}
196-
? Then
195+
> = Schema[ValueId] extends {default: infer Default}
196+
? [Default] extends [Value<Schema, ValueId>]
197+
? Then
198+
: Else
197199
: Else;
198200

201+
type ValidCellDefault<
202+
Schema extends TablesSchema,
203+
TableId extends TableIdFromSchema<Schema>,
204+
CellId extends CellIdFromSchema<Schema, TableId>,
205+
> = Schema[TableId][CellId] extends {default: infer Default}
206+
? [Default] extends [Cell<Schema, TableId, CellId>]
207+
? unknown
208+
: never
209+
: unknown;
210+
211+
export type ValidTablesSchema<Schema extends TablesSchema> = {
212+
[TableId in TableIdFromSchema<Schema>]: {
213+
[CellId in CellIdFromSchema<Schema, TableId>]: ValidCellDefault<
214+
Schema,
215+
TableId,
216+
CellId
217+
>;
218+
};
219+
};
220+
221+
type ValidValueDefault<
222+
Schema extends ValuesSchema,
223+
ValueId extends ValueIdFromSchema<Schema>,
224+
> = Schema[ValueId] extends {default: infer Default}
225+
? [Default] extends [Value<Schema, ValueId>]
226+
? unknown
227+
: never
228+
: unknown;
229+
230+
export type ValidValuesSchema<Schema extends ValuesSchema> = {
231+
[ValueId in ValueIdFromSchema<Schema>]: ValidValueDefault<Schema, ValueId>;
232+
};
233+
199234
export type ValueIsRequiredFromSchema<
200235
Schema extends OptionalValuesSchema,
201236
ValueId extends ValueIdFromSchema<Schema>,

src/@types/mergeable-store/with-schemas/index.d.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import type {
33
CellIdFromSchema,
44
TableIdFromSchema,
5+
ValidTablesSchema,
6+
ValidValuesSchema,
57
ValueIdFromSchema,
68
} from '../../_internal/store/with-schemas/index.d.ts';
79
import type {GetNow, Hash, Hlc, Id} from '../../common/with-schemas/index.d.ts';
@@ -239,25 +241,25 @@ export interface MergeableStore<
239241
isMergeable(): boolean;
240242

241243
/// Store.setTablesSchema
242-
setTablesSchema<TS extends TablesSchema>(
243-
tablesSchema: TS,
244-
): MergeableStore<[typeof tablesSchema, Schemas[1]]>;
244+
setTablesSchema<const TS extends TablesSchema>(
245+
tablesSchema: TS & ValidTablesSchema<TS>,
246+
): MergeableStore<[TS, Schemas[1]]>;
245247

246248
/// Store.setValuesSchema
247-
setValuesSchema<VS extends ValuesSchema>(
248-
valuesSchema: VS,
249-
): MergeableStore<[Schemas[0], typeof valuesSchema]>;
249+
setValuesSchema<const VS extends ValuesSchema>(
250+
valuesSchema: VS & ValidValuesSchema<VS>,
251+
): MergeableStore<[Schemas[0], VS]>;
250252

251253
/// Store.setSchema
252-
setSchema<TS extends TablesSchema, VS extends ValuesSchema>(
253-
tablesSchema: TS,
254-
valuesSchema?: VS,
254+
setSchema<const TS extends TablesSchema, const VS extends ValuesSchema>(
255+
tablesSchema: TS & ValidTablesSchema<TS>,
256+
valuesSchema?: VS & ValidValuesSchema<VS>,
255257
): MergeableStore<
256258
[
257-
typeof tablesSchema,
259+
TS,
258260
Exclude<ValuesSchema, typeof valuesSchema> extends never
259261
? NoValuesSchema
260-
: NonNullable<typeof valuesSchema>,
262+
: VS,
261263
]
262264
>;
263265

src/@types/store/docs.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,11 @@
5757
* Set `allowNull` to `true` to also allow `null`, whether the schema uses
5858
* `type` or `enum`. A default value is used only when it has the correct type,
5959
* matches any member of a type union, is an enum member when applicable, or is
60-
* `null` when allowed. A valid default means that the Cell will always be
61-
* present in a Row. You can also set `required` to `true` to indicate to
62-
* schema-based typing that the Cell should be present even if it does not have
63-
* a default.
60+
* `null` when allowed. Literal schemas passed to Store schema setters are
61+
* checked against these default rules by TypeScript. A valid default means
62+
* that the Cell will always be present in a Row. You can also set `required`
63+
* to `true` to indicate to schema-based typing that the Cell should be present
64+
* even if it does not have a default.
6465
*
6566
* If neither a default value nor `required: true` is provided, the Cell may be
6667
* missing from the Row, but when present you can be guaranteed it is of the
@@ -170,10 +171,11 @@
170171
* Set `allowNull` to `true` to also allow `null`, whether the schema uses
171172
* `type` or `enum`. A default value is used only when it has the correct type,
172173
* matches any member of a type union, is an enum member when applicable, or is
173-
* `null` when allowed. A valid default means that the Value will always be
174-
* present in a Store. You can also set `required` to `true` to indicate to
175-
* schema-based typing that the Value should be present even if it does not have
176-
* a default.
174+
* `null` when allowed. Literal schemas passed to Store schema setters are
175+
* checked against these default rules by TypeScript. A valid default means
176+
* that the Value will always be present in a Store. You can also set `required`
177+
* to `true` to indicate to schema-based typing that the Value should be present
178+
* even if it does not have a default.
177179
*
178180
* If neither a default value nor `required: true` is provided, the Value may
179181
* not be present in the Store, but when present you can be guaranteed it is of

src/@types/store/index.d.ts

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,46 @@ type SchemaType = 'string' | 'number' | 'boolean' | 'object' | 'array';
1414

1515
type SchemaTypeArray = readonly [SchemaType, ...SchemaType[]];
1616

17+
type CellOrValueFromSchemaType<Type> = Type extends readonly (infer Type)[]
18+
? CellOrValueFromSchemaType<Type>
19+
: Type extends 'string'
20+
? string
21+
: Type extends 'number'
22+
? number
23+
: Type extends 'boolean'
24+
? boolean
25+
: Type extends 'object'
26+
? AnyObject
27+
: Type extends 'array'
28+
? AnyArray
29+
: never;
30+
31+
type CellOrValueFromSchema<Schema> = Schema extends {
32+
enum: readonly (infer Enum)[];
33+
}
34+
? Enum
35+
: Schema extends {type: infer Type}
36+
? CellOrValueFromSchemaType<Type>
37+
: never;
38+
39+
type NullFromSchema<Schema> = Schema extends {allowNull: true} ? null : never;
40+
41+
type ValidDefault<Schema> = Schema extends {default: infer Default}
42+
? [Default] extends [CellOrValueFromSchema<Schema> | NullFromSchema<Schema>]
43+
? unknown
44+
: never
45+
: unknown;
46+
47+
type ValidTablesSchema<Schema extends TablesSchema> = {
48+
[TableId in keyof Schema]: {
49+
[CellId in keyof Schema[TableId]]: ValidDefault<Schema[TableId][CellId]>;
50+
};
51+
};
52+
53+
type ValidValuesSchema<Schema extends ValuesSchema> = {
54+
[ValueId in keyof Schema]: ValidDefault<Schema[ValueId]>;
55+
};
56+
1757
/// TablesSchema
1858
export type TablesSchema = {[tableId: Id]: {[cellId: Id]: CellSchema}};
1959

@@ -679,13 +719,20 @@ export interface Store {
679719
setJson(tablesAndValuesJson: Json): this;
680720

681721
/// Store.setTablesSchema
682-
setTablesSchema(tablesSchema: TablesSchema): this;
722+
setTablesSchema<const TS extends TablesSchema>(
723+
tablesSchema: TS & ValidTablesSchema<TS>,
724+
): this;
683725

684726
/// Store.setValuesSchema
685-
setValuesSchema(valuesSchema: ValuesSchema): this;
727+
setValuesSchema<const VS extends ValuesSchema>(
728+
valuesSchema: VS & ValidValuesSchema<VS>,
729+
): this;
686730

687731
/// Store.setSchema
688-
setSchema(tablesSchema: TablesSchema, valuesSchema?: ValuesSchema): this;
732+
setSchema<const TS extends TablesSchema, const VS extends ValuesSchema>(
733+
tablesSchema: TS & ValidTablesSchema<TS>,
734+
valuesSchema?: VS & ValidValuesSchema<VS>,
735+
): this;
689736

690737
/// Store.delTables
691738
delTables(): this;

src/@types/store/with-schemas/index.d.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import type {
1111
StoreAlias,
1212
TableIdFromSchema,
1313
Truncate,
14+
ValidTablesSchema,
15+
ValidValuesSchema,
1416
ValueIdFromSchema,
1517
} from '../../_internal/store/with-schemas/index.d.ts';
1618
import type {
@@ -1258,25 +1260,25 @@ export interface Store<in out Schemas extends OptionalSchemas> {
12581260
setJson(tablesAndValuesJson: Json): this;
12591261

12601262
/// Store.setTablesSchema
1261-
setTablesSchema<TS extends TablesSchema>(
1262-
tablesSchema: TS,
1263-
): Store<[typeof tablesSchema, Schemas[1]]>;
1263+
setTablesSchema<const TS extends TablesSchema>(
1264+
tablesSchema: TS & ValidTablesSchema<TS>,
1265+
): Store<[TS, Schemas[1]]>;
12641266

12651267
/// Store.setValuesSchema
1266-
setValuesSchema<VS extends ValuesSchema>(
1267-
valuesSchema: VS,
1268-
): Store<[Schemas[0], typeof valuesSchema]>;
1268+
setValuesSchema<const VS extends ValuesSchema>(
1269+
valuesSchema: VS & ValidValuesSchema<VS>,
1270+
): Store<[Schemas[0], VS]>;
12691271

12701272
/// Store.setSchema
1271-
setSchema<TS extends TablesSchema, VS extends ValuesSchema>(
1272-
tablesSchema: TS,
1273-
valuesSchema?: VS,
1273+
setSchema<const TS extends TablesSchema, const VS extends ValuesSchema>(
1274+
tablesSchema: TS & ValidTablesSchema<TS>,
1275+
valuesSchema?: VS & ValidValuesSchema<VS>,
12741276
): Store<
12751277
[
1276-
typeof tablesSchema,
1278+
TS,
12771279
Exclude<ValuesSchema, typeof valuesSchema> extends never
12781280
? NoValuesSchema
1279-
: NonNullable<typeof valuesSchema>,
1281+
: VS,
12801282
]
12811283
>;
12821284

0 commit comments

Comments
 (0)