Reputation: 3471
I'm looking for a way to type default and virtual (aka. auto generated from other values) values for a database schema. The idea is to use an utility type to automatically convert a schema for insertion (props with defaults or generated by virtuals aren't required) and on the other side as a query result (eg. we are sure that these fields will be populated by defaults or other "virtual"-like settings so they can be flagged as NonNullable
).
So something like that if we simplify typings to a single prop:
type WithDefault<T> = T;
// Mark prop as optional
type Input<T> = T extends WithDefault<infer T> ? T | undefined : T;
The obvious issue with that is that there is no difference between Input<WithDefault> and Input. Any idea of something that could help achieve a pattern like that? Ending up with a schema like:
type User = {
firstName: string
lastName: string
fullName: WithDefault<string>
}
And being able to switch back and forth to an insert-able schema to a read-able schema.
Upvotes: 0
Views: 48
Reputation: 4010
The problem - as you say - is that the types are structurally equivalent, so TS treats them the same.
You can tag it with some property with type never to distinguish between the two. The downside is that you're adding a property that needs to not exist, but you can mitigate this by using a Symbol as it is guaranteed to be unique.
Code below (TS playground link here):
const __hasDefault = Symbol('__hasDefault');
type WithDefault<T> = T & { [__hasDefault]: never }
type User = {
firstName: string
lastName: string
fullName: WithDefault<string>
}
type ConvertSchema<S extends object> = {
[key in keyof S]: S[key] extends WithDefault<infer T> ? T | undefined : S[key];
}
type result = ConvertSchema<User>;
This gives you the following result - is that what you were looking for?
Upvotes: 2