Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
feat(engine): support imperative wire adapters & fix wire adapter config handling #5084
base: master
Are you sure you want to change the base?
feat(engine): support imperative wire adapters & fix wire adapter config handling #5084
Changes from 1 commit
488bfff
0a0e675
ac422be
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
It's possible to do
$array.0.prop
(playground), so this will also need to support numbers, somehow.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.
If
ExpectedType
isobject
, then we'll never recursively search for props. Definitely an edge case, but maybe something like this might work?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.
Poked around and came up with this:
playground
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.
@wjhsf I think I mostly like that. I'm a bit worried about the
type Obj = PropertiesOfType<Test, object>
example because it is pulling functions as options. Does that feel like something we should specifically avoid? What will LWC do if we reference a function as a reactive prop?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.
You're right, it does feel weird to be pulling in functions. But I'm not too concerned, because it seems unlikely that anyone is using plain
object
as a type. They'd be more likely to use a more specific object, like{id: number}
, which the methods won't match.The framework doesn't do anything with the reactive values, it just passes them through to the wire adapter implementation. So if a wire adapter asks for an
object
, then I guess it's technically not wrong if someone provides it with a function. It's up to the adapter implementation to ask for the correct thing. But even if an adapter does ask forobject
, then the end user will probably have a$data
prop or something that they'll know to use. The impact of the extra types is just unnecessary autocomplete suggestions, not really anything breaking.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.
I can get behind that, hopefully it never comes up.
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.
If
Config[K]
isstring
, then an invalid reactive string (e.g."$number"
) will pass validation, which is a regression from the current type def.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.
@wjhsf I did notice that. I didn't know what was valid here so I didn't block it. What does the framework do if I pass a string that is patterned like a reactive string but is really just intended to be a string?
If the framework rejects it then I can go back and add it in. Shouldn't be too hard to alter the type if it is
string
to ensure it doesn't start with a$
.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.
I don't know that this is a regression, if you look at my example sheet here you can see that I've added some examples of invalid reactive prop references passing validation.
Typescript Playground for LWC Wire Adapter Typings
Such as:
@wire(getBookWireAdapter, { id: "$propDoesNotExist", title: "$alsoNotHere" }) invalidConfigWithBinds?: Book
where both the number and string props accepted anything that looks like a reactive prop.I do think it should be pretty easy to filter out if you can confirm that LWC will choke on it.
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.
So there's a subtle thing happening here,
{title: "$alsoNotHere"}
gets inferred as{title: string}
. And astring
type must always pass validation, because we can't definitively tell whether or not it's a valid reactive string. If you do{title: "$alsoNotHere"} as const
, then you get the string literal types as expected. When usingas const
, you get an error with the current type def, but not with the proposal. That's the regression I'm concerned about. (Not too concerned, though. I'd probably still ship this PR even if we can't fix it.)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.
@wjhsf to confirm. LWC has a problem if a "reactive-like" string is provided but it doesn't map to a component property?
If that is the case then it is safe to restrict this and I will make that change.
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.
If a prop doesn't exist, the framework will use
undefined
.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.
OK, that seems clear. A literal string that starts with a
$
but doesn't match a valid prop is still treated as a reactive prop and resolves toundefined
, not back to the literal string value. I agree it makes sense to exclude those if we can.I've been trying to define a type that does that. I've tried several things, some of them look like they worked in the past but don't work anymore (or the articles I pulled them from were simply wrong).
I was playing with versions of
but haven't been able to make anything stick. If you have some ideas of how to type this please let me know. I think the biggest part of the problem is the strategy used in this PR is deriving types from the adapter's stated Config, not the provided values. So the type resolution happens prior to the config values being considered. I would need some way of saying "I see you said allows
string
type, let me massage that to be any of these prop strings or any string as long as it doesn't start with$
" but I haven't been able to get so far as defining a type that ensures "string that doesn't start with $"Maybe we can find a middle ground that somehow has two layers of type checking, even though it wouldn't be the best error messages, layer 1 is extract valid types based on the config, layer 2 determines the valid strings based on the values passed to the config param, using some of the previous config. The generic type resolution strategy may be hard to manage from both directions.
This open issue (from 2022) is presumably the feature we're looking for to supports this, it doesn't seem to have a lot of traction right now.
microsoft/TypeScript#49867
I think this is the "official" issue for negated types which seems to match our goal
microsoft/TypeScript#4196
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.
Yeah, I don't think we can validate "string but not invalid
$
string" with this approach. We can mitigate the issue with something like this. It doesn't change the validation at all, but at least it shows the$
props in the IDE autocomplete suggestions.(Explanation:
string | 'foo'
gets collapsed tostring
, but(string & {}) | 'foo'
doesn't because of the& {}
. The& {}
essentially means "non-nullable"; since every string is by definition not null, every string is still valid. But because the type doesn't collapse,'foo'
is still part of the union, so it gets suggested.)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.
In general, I like this approach better, despite this issue. But we want to avoid breaking existing usage, so I'll have to do some analysis to see what's likely to explode if we make this change.