clockworklabs / clockworklabs/SpacetimeDB
TypeScript: Type error when using .eq(...) on enum columns
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 25.2k
- Forks
- 1.1k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 46
Description
Short
I tried making a view in SpacetimeDB server side with TypeScript that returns all rows that have enum value "Lamp".
The issue I am having makes the TypeScript type checker error when using the .eq(...) function when trying to filter based on the enum type.
Code in question
The following snippet is part of my project and raises a type error on the label.label.eq({ tag: "Lamp" }) statement.
// Schema definition for context
tretakt_special_labels: table(
{ public: false },
{
tretakt_switch_id: t.string().unique().primaryKey(),
label: t.enum("Label", ["Lamp", "Switch"])
}
)
// View that raises issue
db_schema.anonymousView({ name: "binary_lamps", public: true },
t.array(binary_lamps),
(ctx) => {
return ctx.from.tretakt_special_labels
.where(label => label.label.eq({ tag: "Lamp" }))
.rightSemijoinSemijoin(ctx.from.tretakt_switch, ((label, sw) => sw.id.eq(label.tretakt_switch_id)))
}
)
Faulty behavior in detail
The .eq(...) function expects a value of type:
LiteralValue & RowType<TableDef>[ColumnName]
Where:
LiteralValueis a union of primitive types:
type LiteralValue =
| string
| number
| bigint
| boolean
| Identity
| Timestamp
| ConnectionId;
RowType<TableDef>[ColumnName]for thelabelenum column is an object of shape:
{ tag: "Lamp" | "Switch" }
The intersection LiteralValue & { tag: "Lamp" | "Switch" } requires the value to be both a primitive and an object, which is impossible.
As a result, the type checker produces errors like:
Type '{ tag: "Lamp"; }' is not assignable to type 'Timestamp & { tag: "Lamp" | "Switch"; }'
This is a typing issue rather than a runtime problem: the ORM defines enum columns as objects ({ tag: EnumValue }), but .eq is typed to accept only rimitive literals. TypeScript therefore sees a type mismatch and rejects { tag: "Lamp" }.
Full typing error
No overload matches this call.
Overload 1 of 2, '(literal: LiteralValue & { tag: "Lamp" | "Switch"; }): BooleanExpr<TableToSchema<"tretakt_special_labels", TableSchema<CoerceRow<{ tretakt_switch_id: StringColumnBuilder<{ isUnique: true; isPrimaryKey: true; }>; label: SimpleSumBuilderImpl<...>; }>, []>>>', gave the following error.
Argument of type '{ tag: "Lamp"; }' is not assignable to parameter of type 'LiteralValue & { tag: "Lamp" | "Switch"; }'.
Type '{ tag: "Lamp"; }' is not assignable to type 'Timestamp & { tag: "Lamp" | "Switch"; }'.
Type '{ tag: "Lamp"; }' is missing the following properties from type 'Timestamp': __timestamp_micros_since_unix_epoch__, microsSinceUnixEpoch, toMillis, toDate, and 2 more.
Overload 2 of 2, '(value: never): BooleanExpr<any>', gave the following error.
Argument of type '{ tag: string; }' is not assignable to parameter of type 'never'.ts(2769)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the TypeScript definitions for enum columns, LiteralValue, RowType, and the .eq(...) overload described in the issue. Reproduce the error with the provided schema and view, then verify that comparing an enum value such as { tag: "Lamp" } type-checks correctly and is covered by a regression test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100