Rework TypeScript types around registry, codecs, resources and relations#1784
Rework TypeScript types around registry, codecs, resources and relations#1784wesselvdv wants to merge 10 commits intographile:mainfrom
Conversation
|
|
@benjie I think I found a way to delay the inference without causing export interface AnyPgCodec extends PgCodec {} // <-- allows use of default generic parameters, and prevents "circular default detected" errors
/**
* A codec for a Postgres type, tells us how to convert to-and-from Postgres
* (including changes to the SQL statement itself). Also includes metadata
* about the type, for example any of the attributes it has.
*/
export interface PgCodec<
TName extends string = string,
TCodecAttributes extends
ReadonlyArray<PgCodecAttribute> = ReadonlyArray<PgCodecAttribute>,
TFromPostgres = any,
TFromJavaScript = TFromPostgres,
TArrayItemCodec extends AnyPgCodec = AnyPgCodec, // <-- using just PgCodec here causes circular default parameter issues
TDomainItemCodec extends AnyPgCodec = AnyPgCodec,
TRangeItemCodec extends PgRangeItemCodec = PgRangeItemCodec,
> {
// snip
}For example, I think I might've been able to get I haven't done all of it yet, but it seems promising. |
|
Exciting! This reminds me of the kind of trick you need to do to build a JSONValue type, I should have thought about that - the difference between eager evaluated and lazily evaluated types... I'm not yet good enough at TypeScript to figure these things out for myself. Keep up the great work! |
066e2a1 to
1c5e313
Compare
Thanks, I've got a basic working example schema again. There are still loads of mismatches, and biggest one is the |
d3a7030 to
336f644
Compare
| pgResource: "+delete:resource:select", | ||
| pgCodecAttribute(behavior, [codec, attributeName]) { | ||
| const attribute = codec.attributes[attributeName]; | ||
| const attribute = codec.attributes![attributeName]; |
There was a problem hiding this comment.
The ! shouldn't be required here since pgCodecAttribute will only ever be called with a PgCodec that has attributes (formerly a PgCodecWithAttributes)
| this: GraphileBuild.Inflection, | ||
| details: { | ||
| codec: PgCodecWithAttributes; | ||
| codec: DefaultPgCodec; |
There was a problem hiding this comment.
Should this (and the related changes below) have been DefaultPgCodecWithAttributes or similar?
There was a problem hiding this comment.
Yes, but this gave me a lot of errors, so I opted to widen the constraint for now, as I felt it wasn't necessarily a requirement for the purpose of this PR.
.gitignore
Outdated
| /WHAT_ARE_YOU_DOING.md | ||
| contrib | ||
| /env | ||
| /env No newline at end of file |
There was a problem hiding this comment.
I think you've removed the newline from the end of .gitignore - perhaps when you removed the nix stuff?
|
I've merged the latest and I've renamed
|
| * (except in 1-to-1 relationships). | ||
| */ | ||
| identicalVia?: PgCodecAttributeVia; | ||
| identicalVia?: _AnyPgCodecAttributeVia; |
There was a problem hiding this comment.
If I change via and identicalVia to GenericPgCodecAttributeVia then I get weird errors in exampleSchema.ts. However, I know that if via is set then it will always be string | { relation: string, attribute: string } (or a narrower form of this) so I don't really understand why this needs to use anys?
|
I've also fixed the linting issues, but I'm a bit lost in understanding what we're actually achieving here - seems that we're hitting |
|
(To be clear: the previous comment was stating that I'm lost because of my poor understanding of TypeScript, not because the PR is bad. It could be that we were hitting |
|
(@wesselvdv and I had a long call where we went through this, and unfortunately though it solves some issues it also creates others, in particular making the codebase harder to work on. Currently the |
Description
In this PR i've tried to rework to typescript system so it would be more ergonomic for both internal and external usage. Please be aware that it's mostly a showcase of how it could be, not how it should be.
Observations leading to the changes in this PR:
any.PgRegistryinterface because of the type parameter being objects ({ [indexName: string]: etc }) which causes early evaluation tostringwhich loses the actual properties.keyofwhen inferring objects, which can cause early evaluation resulting instring | numbereven when explicitly defining an object with index string:keyof { [index: string]: number } === string | numberundefinedas bottom type instead ofneverChanges in this PR:
Any<PgType>andDefault<PgType>interfaces.Any<PgType>interfaces are for internal usage, and theDefault<PgType>for external usage. This because the latter ones cause massive circular reference issue for typescript when used in places where they're being defined. (e.g. inside dataplan/pg, but not in graphile-build-pg)Expand<>which is quite performance intensive.inferto delay the inference internally and have less type casting.The changes in dataplan/pg are the core changes, and the resulting changes in graphile-build-pg and others are a consequence of this. The changes in the latter have mostly been changing
PgCodectoDefaultPgCodecand removing a LOT of explicit type casts because this now "just" works.Biggest achievement which I am not sure if this is because of this PR, but nonetheless useful. The correct typing of the below snippet in the exampleSchema:
crystal/grafast/dataplan-pg/src/examples/exampleSchema.ts
Lines 3386 to 3396 in 5589d14
Having the ability to define a correctly typed parent step with a specific resource, and having it infer correctly and type check that it adheres to said parent. (e.g.
RelationalTopicStep extends RelationalItemsLikeStep ? 'yes' : 'no' === 'yes')Outstanding tasks
GetPgCodecAttributesvsPgCodecAttributes, or even consider namespacesPgCodec.getAttributes<> | PgCodec.Attributes<>)fixes #1755
Performance impact
Non empirical observation is that the
exampleSchema.tsfile has become significantly faster.Security impact
Checklist
yarn lint:fixpasses.yarn testpasses.RELEASE_NOTES.mdfile (if one exists).