-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove Guaranteed
from CellSuccessData
#9010
Remove Guaranteed
from CellSuccessData
#9010
Conversation
// This is necessary for Cells, because if it doesn't exist it'll go to Empty or Failure | ||
type Guaranteed<T> = { | ||
[K in keyof T]-?: NonNullable<T[K]> | ||
} | ||
|
||
/** | ||
* Use this type, if you are forwarding on the data from your Cell's Success component | ||
* Because Cells automatically checks for "empty", or "errors" - if you receive the data type in your | ||
* Success component, it means the data is guaranteed (and non-optional) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These comments are no longer accurate because we render Success
if any property is present/non-empty. Other properties can still be missing/empty.
A custom isEmpty
implementation or a missing Empty
definition can also result in Success
.
* | ||
* @params TData = Type of data based on your graphql query. This can be imported from 'types/graphql' | ||
* @example | ||
* import type {FindPosts} from 'types/graphql' | ||
* | ||
* const { post } = CellSuccessData<FindPosts> | ||
* | ||
* post.id // post is non optional, so no need to do post?.id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would only be true when all of the following are true:
Empty
is definedisEmpty
is not customized, or its custom implementation retains the presence check (which is admittedly likely 🙂)post
is the only field in your graphql query, or all fields are present/non-empty
@pvenable Thanks for working on this. I haven't done a proper review yet, but reading through the PR description and your comments I like where this is going 👍 One thought that came to mind is if we could still keep |
@Tobbe Thanks for the comment.
Yes! -- I'm hoping for something like this too in the long run. There are many happy cases where the data could be guaranteed, and the best experience would be to make it automatic, such that I tried to figure out a way to do something like this solely via Conditional Types a little while ago, but to my surprise I couldn't find a safe/reliable way to count the properties of a type in the type system. 😬 Combined with the I guess an interim option could be to have e.g. both I do consider the current |
I'm more than happy to do this in steps, with a codegen solution later. I'll bring this PR up with the rest of the team to get their input |
@pvenable So we discussed this today. We agree that the current behavior is wrong, and just making everything optional (i.e. getting rid of With all that said, we'd prefer not to merge this PR as it stands right now. Please let me know what you think about the reasoning above. And definitely tell me if it sounds like I might have misunderstood something about your current solution. |
Thanks for the response. Here are some of my thoughts, and I apologize in advance for my verbosity. 🙂
Strictly speaking there's no (runtime) behavior change in this PR. It's only correcting a type that misrepresents as guaranteed-to-be-present that which is not. There is not currently enough information at build time to guarantee this data. There's not necessarily anything wrong with the current behavior of Cells; it's just that we can't be assured that the data will be present due to factors that can't be (or aren't yet?) statically assessed. Note that this can also make it difficult to properly test
They may already need to the moment they add another query field or remove For what it's worth, I think this is only a "breaking" change to users of TypeScript strict mode, who (like me) would almost certainly want this type to accurately reflect the potential optionality of these data fields absent a way to conditionally guarantee it according to actual Cell behavior. I see it rather as a "fixing" change. 🙂 After a cursory experiment, I don't think this change is even observable to non-strict TypeScript, but I admit that since I always use strict mode I'm not familiar with any potential "gotchas".
The tutorial states this in Chapter 2 (Cells): "The minimum you need for a cell are the QUERY and Success exports. If you don't export an Empty component, empty results will be sent to your Success component. If you don't provide a Failure component, you'll get error output sent to the console." So it's well-known that empty results can be sent to Success -- but the types don't represent that. Defining a cell without the
Unfortunately, this is likely more than I expect to be able to commit to in the near future.
I understand the tension around the "breaking" change, and particularly the awkwardness of accepting at the type-level that we can't (currently) guarantee that Ultimately it's up to Redwood whether and when this or any solution for this is integrated in terms of release cycles. Around 20% of our project's cells do not meet the single-root-query happy path criteria, and it's too easy to make the mistakes this PR prevents, so if now is not the right time for a Redwood fix, I think I can make this change locally for our project as an interim workaround. |
Thanks for your thorough response @pvenable. I really appreciate you taking the time to write that all down. I agree with pretty much everything you said. And it sounds really promising if this would only be breaking for strict mode users. If that's the case I think we can merge this sooner rather than later. And, just to clarify, we generally consider it a breaking change if code goes from non-red to red, even if it's "just" types and the runtime behavior stays the same.
Totally understand. And grateful for the time you've already spent on this. We'll leave that task open for some other contributor, or a core-team member, to tackle another time :) |
Thanks, @Tobbe.
Personally, I see this as similar to a "breaking" 6.0.3 (patch) change accepted via the rationale given here: #8918 (comment). With that said, I do recognize that this is a more complicated case since it's technically only broken "sometimes", and Cells have an established behavior and history one wouldn't want to hastily destabilize, so I can definitely appreciate the reasoning here. I am planning to implement roughly this PR's solution directly into our current project until Redwood integrates a fix, so the urgency from my perspective is somewhat relieved. I'm also not married to this particular implementation if there are any misgivings about it, or if a "better" solution can be devised in the meantime. I appreciate the consideration and discussion. 👍 |
I couldn't stop thinking about this, so I've proposed an alternative in #9037. 🙂 |
Closing since #9037 has been merged instead. |
Alternative to #8186. Addresses #8179 (comment).
#7704 was a fairly significant Cell behavior change in Redwood 5.
Success
can be rendered with partial data, butCellSuccessData
was not updated to reflect the change. Other variables such as whetherisEmpty
orEmpty
are defined in a Cell can also make it possible to renderSuccess
with partial data even in cases that would otherwise renderEmpty
instead.This can lead to runtime errors that are better made impossible to ship via typing that accurately reflects the possibility of missing data even in
Success
.Unfortunately I don't see any obvious way to conditionally "guarantee" the presence of data at the type level based on the various factors that can impact it (custom
isEmpty
implementations, missingEmpty
definitions, or the number of fields in your GraphQL query result), so it seems the only safe thing to do is to stop representing that all data properties are guaranteed to exist when renderingSuccess
.Side note: At least under strict typing, this change makes "automatic"
Empty
somewhat less useful since it's now necessary to do presence checks inSuccess
anyway. I suspectEmpty
will generally remain useful mainly for the "empty array" case and less for the "null result" case.