Skip to content
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(store): provide better TS errors for action creator props #3060

Merged
merged 8 commits into from
Nov 2, 2021

Conversation

david-shortman
Copy link
Contributor

@david-shortman david-shortman commented Jul 1, 2021

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[ ] Bugfix
[x] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] Other... Please describe:

What is the current behavior?

Closes #2892

What is the new behavior?

Does this PR introduce a breaking change?

[x] Yes - usage of `props` outside of an action creator now breaks for invalid types
[ ] No

Other information

Thanks to the advice from Nadia Chibrikova on StackOverflow, props can have its generic argument asserted to pass NotAllowedCheck:

Screen Shot 2021-06-30 at 21 43 28

This provides a more precise error than the current one which is hidden within TS outputting multiple errors for a mismatch for each overload of createAction:

Screen Shot 2021-06-30 at 21 44 48

Additionally, I've updated the error messages to be hopefully more explicit about what is wrong.

UPDATE: With a suggestive playground link, I took @markostanimirovic's subtle suggestion to explicitly restrict primitive types.

I've also separated the error messages to be more contextually meaningful when using props vs when providing a creator function to createAction.

@ngrxbot
Copy link
Collaborator

ngrxbot commented Jul 1, 2021

Preview docs changes for 994b640 at https://previews.ngrx.io/pr3060-994b640f/

Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat!

@@ -80,6 +95,8 @@ export type Creator<
R extends object = object
> = FunctionWithParametersType<P, R>;

type Primitive = string | number | bigint | boolean | symbol | null | undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there's a reason Typescript doesn't provide this type already...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Their site says

object is a type that represents the non-primitive type, i.e. anything that is not number, string, boolean, bigint, symbol, null, or undefined.

So it seems like checking if something extends object would be sufficient.

Perhaps I shouldn't have an explicit check for primitives then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need an explicit check because unknown does not extend object, and so it must be differentiated (but we can't check extends unknown because every type is assignable to unknown).

@brandonroberts brandonroberts added the Needs Cleanup Review changes needed label Jul 5, 2021
Copy link
Member

@markostanimirovic markostanimirovic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks much better now 🎉

modules/store/src/models.ts Outdated Show resolved Hide resolved
Copy link
Member

@markostanimirovic markostanimirovic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work David! Thank you 🥇

There are no breaking changes when props is used within createAction, but props itself has a breaking change. So, I would wait until v13 to merge this improvement.

@david-shortman
Copy link
Contributor Author

There are no breaking changes when props is used within createAction, but props itself has a breaking change. So, I would wait until v13 to merge this improvement.

Oh yeah, good point!

@timdeschryver timdeschryver added Breaking Change and removed Needs Cleanup Review changes needed labels Jul 7, 2021
Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

expectSnippet(`
const foo = createAction('FOO', props<null>());
`).toFail(
/Type 'ActionCreatorProps<null>' is not assignable to type '"action creator cannot return an array"'/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be

Suggested change
/Type 'ActionCreatorProps<null>' is not assignable to type '"action creator cannot return an array"'/
/Type 'ActionCreatorProps<null>' is not assignable to type '"action creator props cannot be a primitive value"'/

expectSnippet(`
const foo = createAction('FOO', props<undefined>());
`).toFail(
/Type 'ActionCreatorProps<undefined>' is not assignable to type '"action creator cannot return an array"'/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should also be

Suggested change
/Type 'ActionCreatorProps<undefined>' is not assignable to type '"action creator cannot return an array"'/
/Type 'ActionCreatorProps<undefined>' is not assignable to type '"action creator props cannot be a primitive value"'/

@brandonroberts brandonroberts merged commit 5ed3c3d into ngrx:master Nov 2, 2021
@david-shortman david-shortman deleted the props-type-assertion branch November 2, 2021 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

props doesn't accept HttpErrorResponse
5 participants