-
Notifications
You must be signed in to change notification settings - Fork 35
The components folder has been converted to TypeScript. #650
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
base: develop
Are you sure you want to change the base?
Conversation
sheenarbw
left a comment
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 is a good start but has a few rough edges:
Always try to be explicit:
- Use of
any. Please try not to useany. Rather be explicit. Otherwise when a new coder works on this stuff they will be encouraged to guess and there will be errors that come from that. - Use of ReactNode when we can refer to a specific type.
Make sure you aren't making changes you don't meant to make. There are a few strange things in here.
I haven't actually run the code and looked for errors. Can you please check yourself for errors by running
npm run build- the storybook tests
The storybook tests use this https://storybook.js.org/docs/react/writing-tests/test-runner
You can run them by opening two terminals:
# terminal 1
npm run storybook
# terminal 2
npm run test-storybook
| padding="md" | ||
| header={ | ||
| <Header height={60} p="xs"> | ||
| <Container></Container> |
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.
Why is there a container in the header now?
| children: React.ReactNode; | ||
| serverSidePropsCorrectlyCalled: boolean; | ||
| isLoggedIn: boolean; | ||
| loggedInUserData: any; |
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.
loggedInUserData shouldn't be any
| query, | ||
| req, | ||
| }: { | ||
| query: any; |
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 shoulnd't be any
| query: any; | ||
| req: any; | ||
| }) { | ||
| const whoAmIResponse = await serverSideWhoAmI({ query, req } as any); |
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.
also not any
| "incremental": true | ||
| }, | ||
| "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], | ||
| "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "components/LoggedOutPage.tsx"], |
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.
Look at the existing patterns here. Do you think "components/LoggedOutPage.tsx" is actually helpful? Or do you think it is already included?
| } | ||
|
|
||
| export function Underlined({ children }) { | ||
| export function Underlined({ children }: { children: React.ReactNode }) { |
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.
Look at how these functions are used. Are you sure they take in any ReactNode or are they called with one specific type of node
sheenarbw
left a comment
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 have some guesswork in here. Specifically, your use of GetServerSidePropsContext is dodgy.
In the face of ambiguity, refuse the temptation to guess
If you put guesses in your code then it will be hard for me to trust your code. Every time I've put in the up-front effort to understand things properly it's worked out well for me. Remember that part of the reason you are doing this work is so that you can level up and help others to level up.
One thing I'm not sure of myself if the difference between JSX.Element, ReactElement and ReactNode. So I'm going to need to research that before reviewing everything properly. If you feel like you made any guesses there then please revise that.
| query, | ||
| req, | ||
| }: GetServerSidePropsContext) { | ||
| const whoAmIResponse = await serverSideWhoAmI({ query, req } as GetServerSidePropsContext); |
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 seems like a lot of guessing...
As far as I know, GetServerSidePropsContext looks like this:
export interface GetServerSidePropsContext {
req: IncomingMessage
res: ServerResponse
params?: ParsedUrlQuery
query: ParsedUrlQuery
preview?: boolean
previewData?: any
}
serverSideWhoAmI returns something completely different to that. Just because it is used in server side things doesn't mean that the type is this random thing.
GetServerSidePropsContext is used like this only:
getServerSideProps = async ({ arguments,you,want }: GetServerSidePropsContext) => {
...
In other words, the arguments sent to a getServerSideProps function will adhere to that interface.
If you look at the return below, you can see these lines:
isLoggedIn: whoAmIResponse.status === 200,
loggedInUserData: whoAmIResponse.responseData,
This tells us that the whoAmIResponse at least has a status that can be a number, and responseData. The responseData would be a JSON response. So basically an object.
sheenarbw
left a comment
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.
Still some rough edges...
| children: React.ReactNode; | ||
| serverSidePropsCorrectlyCalled: boolean; | ||
| isLoggedIn: boolean; | ||
| loggedInUserData: { firstName: string; email: string } |
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 gets copy-pasted all over the place now:
{ firstName: string; email: string }
What if we decide to add a lastName or a cellphoneNumber? Then we'll have to change the code in a million places.
Make an interface in one file, and then import it as needed.
Remember DRY
| children, | ||
| }: { | ||
| handleLogout: () => void; | ||
| loggedInUserData: { firstName: string; email: string } |
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.
not DRY
| const whoAmIResponse = await serverSideWhoAmI({ query, req }); | ||
|
|
||
|
|
||
| export const getServerSidePropsForLoggedInPage = async (context: GetServerSidePropsContext) => { |
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.
explicit is better than implicit.
Are we really expecting the props to look like this?
It looks like we don't use most of that.
Good code makes its intentions clear. So it's important to be specific about what is required.
We are using Typescript so that when other coders work on this project they don't mess up and pass the wrong thing into a function. So we should not accept the wrong thing. We should only accept exactly the correct thing.
sheenarbw
left a comment
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.
Some repeated comments. Please address everything.
|
|
||
|
|
||
|
|
||
| const LoggedInUserDataType = { |
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.
Should this not be an interface?
| const whoAmIResponse = await serverSideWhoAmI({ query, req }); | ||
|
|
||
|
|
||
| export const getServerSidePropsForLoggedInPage = async ({ query, req }: GetServerSidePropsContext) => { |
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 have mentioned this one multiple times now. If you do not understand a comment then please do not ignore the comment. I really don't like repeating myself this many times.
Look at how much information is inside GetServerSideProps:
https://github.com/vercel/next.js/blob/v10.2.0/packages/next/types/index.d.ts#L136-L151
if 90% of the interface is completely inaccurate then it's a bad choice.
Please use something appropriate here. GetServerSidePropsContext is inappropriate.
If you disagree then say so. Do not simply ignore this feedback.
sheenarbw
left a comment
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 think you can do better
| import { clearAuthToken } from "../lib/authTokenStorage"; | ||
| import { useCookies } from "react-cookie"; | ||
|
|
||
| interface Props { |
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.
The different components have different props. Please use different interfaces for the different things.
If the foo function has the arguments a, b and c and the bar function has d, e and f then it is incorrect to say that foo requires a,b,c,d,e, f, req and query.
Please make use of the correct interface. It should tell the truth of what is required in each function.. Each function requires different things. We need to be exact and specific. If you add in extra things that aren't needed at all then that makes it worse.
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.
please also make a point of importing things that are defined elsewhere in the code.
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.
and req is definitely not a string.
| email: string; | ||
| }; | ||
| handleLogout?: () => void; | ||
| req?: string; |
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.
req isn't used by any function here. Why is it in this interface at all?
sheenarbw
left a comment
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.
There is still one weird guess in here that I can see.
I need to learn about the different React children prototypes still so there is a chance I've missed something. Please triple-check that there is nothing else that you guessed on. I'm very keen to get this finished.
| export function ErrorAlert({ children, title }) { | ||
| interface Props { | ||
| title: string; | ||
| children: string; |
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 would be better here to say that the children could be a string or another component. Eg if we wanted to have multiple paragraphs of text then a string wouldn't cut it. We would either use multiple Text components or a Stack with a bunch of Text components inside it.
| export async function getServerSidePropsForLoggedInPage({ query, req }) { | ||
| const whoAmIResponse = await serverSideWhoAmI({ query, req }); | ||
|
|
||
| export async function getServerSidePropsForLoggedInPage({ query, req }: { query: { [key: string]: string }, req: IncomingMessage }) { |
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.
There is no reason to invent things here. Look:
type GetServerSidePropsContext<
Q extends ParsedUrlQuery = ParsedUrlQuery
> = {
req: IncomingMessage & {
cookies: NextApiRequestCookies
}
res: ServerResponse
params?: Q
query: ParsedUrlQuery
preview?: boolean
previewData?: PreviewData
resolvedUrl: string
locale?: string
locales?: string[]
defaultLocale?: string
}
This information comes from https://github.com/vercel/next.js/blob/v10.2.0/packages/next/types/index.d.ts#L136-L151
What datatype is query? What datatype is req? Please use those. We know where these props come from, we know exactly what the types are.
sheenarbw
left a comment
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.
There is still one thing that looks inaccurate as far as I can see.
Also, this branch is not up to date with the latest code.
Please do the following:
- fix the last inaccuracy
- merge the latest develop branch into your branch and fix any merge conflicts that come up
- make sure that the storybook tests still pass
- make sure you can build the application. You can see how to run it by looking at package.json
| req, | ||
| }: { | ||
| query: ParsedUrlQuery; | ||
| req: IncomingMessage; |
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.
Please use exactly this for req's type. There is no need to be creative here, we can just copy.
Is there a reason you want to leave out the part about the cookies?
req: IncomingMessage & {
cookies: NextApiRequestCookies
}
Related issues: [please specify]
Description:
What are you up to? Fill us in :)
Screenshots/videos
I solemnly swear that: