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

Add type-defs for styled-components v4 #2933

Merged
merged 13 commits into from Jan 29, 2019
Merged

Add type-defs for styled-components v4 #2933

merged 13 commits into from Jan 29, 2019

Conversation

omninonsense
Copy link
Contributor

@omninonsense omninonsense commented Nov 1, 2018

I'd like someone to thoroughly review this!

To-do:

  • Add types for styled-components/native (help wanted)
  • Add KeyFrames to Interpolation
  • Add CSSRules(Interpolation[]) to Interpolation
  • Improve tests for css (and maybed keyframes?); add comments too.
  • Add tests for refs
  • Add tests for stuff that doesn't exist (ie styled.derp/styled('derp'))
  • Set lower bound to flow 0.75!
  • Add support for attrs API

These are currently impossible (to the best of my knowledge) to express these safely and without breaking the types for the "main" functionality of the library, due to Flow's lack of support for some core React features (React.forwardRef) this library relies on:

  • Add support for withCompnent API
  • Add support for as prop API
  • Add support for custom props on built-in components (ie <MySpan myProp=... />)

Please let me know if you can think of anything else to add to the list.


Also, not sure if it's wise to simply merge this (if the PR is good enough), and then hope someone else contributes with whatever I missed?

@omninonsense
Copy link
Contributor Author

This should hopefully address #2880

@omninonsense
Copy link
Contributor Author

omninonsense commented Nov 1, 2018

Also, the justification for the horribly misleading StyledElementType<T> = T type is to make it seem like it's built-in elements, and to hide the fact (to IDEs) that we're lying about the returned type being a string. Yikes! I feel really bad about this. I hope someone knows of a better way.

Also, it's added so it works with forward refs (v4 doesn't use innerRef anymore). I forgot to add tests for refs; I'll add them later or tomorrow

@omninonsense
Copy link
Contributor Author

Damn you, Travis! Doesn't seem to be related to this PR, since master is also failing in the same ways. 🤷‍♂️

@omninonsense
Copy link
Contributor Author

Travis is back! 🎉

@AndrewSouthpaw
Copy link
Contributor

I suggest you tag a few people who have worked on this libdef already. :-)

@omninonsense
Copy link
Contributor Author

I suggest you tag a few people who have worked on this libdef already.

@AndrewSouthpaw Good idea!

Hi @dashed, and @shrynx! Would you two like to take a look at this too, please? 🐈

@zaguiini
Copy link

zaguiini commented Nov 6, 2018

Hi! I'm trying to use it but with no success. Successfully installed as custom definitions but I'm getting errors.

How should I use it, @omninonsense?

image

@omninonsense
Copy link
Contributor Author

omninonsense commented Nov 7, 2018

Hi @zaguiini!

So, the way you're trying to call the function (EDIT: only talking about the type arguments in the call expression) won't work with this libdef (I don't remember if this works for v3). The main reason is that we lie about the type that's returned by styled in order to compensate for the fact Flow currently doesn't have a good way of correctly typing React.forwardRef()s (see facebook/flow#6103), which is something styled-components started using in v4 instead of innerRef.

What we essentially do is:

  • for built-ins like styled.div, we say that it returns a string ("div"), but we hide/wrap this lie in StyledElementType<T>
  • for components we say that we're returning that same component type

This is not ideal, but it means that we have working refs, and prop validation is preserved for the non built-in components.

Once forward ref support lands in flow, these can be improved a lot, to even add custom props accepted by the styled component (which the wrapped component ignores, etc), and maybe even properly typing the functions inside the template literals. Although, I think flow doesn't really understand template literals expand to fn(strings: string[], ...interpolations : Interpolation[]), so I didn't bother too much with having Interpolation accept a prop parameter in there.

@omninonsense
Copy link
Contributor Author

omninonsense commented Nov 8, 2018

@zaguiini I never answered you other question. In the example you provided, I'd just do:

type Props = {
  a: boolean;
}

const CardContainer = styled.div`
  /* ... */
  background-color: ${(props: WithTheme<Props>) => props.theme.light.white};
  /* ... */
`

I usually have a theme.js file with something like this (this is where the WithTheme<> mentioned above comes from):

export const theme = {
  /* ... */
}

export type Theme = typeof theme
export type WithTheme<P : {} = {}> = P & {| theme: Theme |}

@dashed
Copy link
Contributor

dashed commented Nov 8, 2018

Hi @dashed, and @shrynx! Would you two like to take a look at this too, please? 🐈

@omninonsense At the moment, I don't have a project currently using styled-components v4 + flow types; and unfortunately, I won't have the bandwidth to review this PR anytime soon.

Awesome job though! 👍

@maamounapprise
Copy link

you would need to add for macro too

@AndrewSouthpaw
Copy link
Contributor

If we don't get a PR from people with more context within a week, I'm okay with merging it in (after reviewing with little context) and letting to be "better than nothing," and people can continue adding fixes as needed. @omninonsense if this stagnates for too long just ping again and I'll merge it in.

@iduuck
Copy link

iduuck commented Nov 16, 2018

I have a problem when using the as prop for the new styled-components version. I have a case, where I style the react-router-dom's own Link. After declaring it, I want to have a link to Instagram, but not with Link, but with a a tag.

<ListLink as="a" target="_blank" href="https://instagram.com/fintory">
  Instagram
</ListLink>

But now, I am getting an error, that I am not supplying the right Props:

Cannot create ListLink element because property to is missing in props [1] but exists in object type [2].

     client/components/Footer/index.js
     128│                   <ListLink as="a" target="_blank" href="https://www.facebook.com/fintory.agency/">
     129│                     Facebook
     130│                   </ListLink>
 [1] 131│                   <ListLink as="a" target="_blank" href="https://instagram.com/fintory">
     132│                     Instagram
     133│                   </ListLink>
     134│                   <ListLink as="a" target="_blank" href="https://twitter.com/fintory">
     135│                     Twitter
     136│                   </ListLink>

     flow-typed/npm/react-router-dom_v4.x.x.js
 [2]  20│   declare export class Link extends React$Component<{
      21│     className?: string,
      22│     to: string | LocationShape,
      23│     replace?: boolean,
      24│     children?: React$Node,
      25│   }> {}

@zaguiini
Copy link

I have a problem when using the as prop for the new styled-components version. I have a case, where I style the react-router-dom's own Link. After declaring it, I want to have a link to Instagram, but not with Link, but with a a tag.

<ListLink as="a" target="_blank" href="https://instagram.com/fintory">
  Instagram
</ListLink>

But now, I am getting an error, that I am not supplying the right Props:

Cannot create ListLink element because property to is missing in props [1] but exists in object type [2].

     client/components/Footer/index.js
     128│                   <ListLink as="a" target="_blank" href="https://www.facebook.com/fintory.agency/">
     129│                     Facebook
     130│                   </ListLink>
 [1] 131│                   <ListLink as="a" target="_blank" href="https://instagram.com/fintory">
     132│                     Instagram
     133│                   </ListLink>
     134│                   <ListLink as="a" target="_blank" href="https://twitter.com/fintory">
     135│                     Twitter
     136│                   </ListLink>

     flow-typed/npm/react-router-dom_v4.x.x.js
 [2]  20│   declare export class Link extends React$Component<{
      21│     className?: string,
      22│     to: string | LocationShape,
      23│     replace?: boolean,
      24│     children?: React$Node,
      25│   }> {}

You forgot to add the to prop. Make it optional if you don't want to pass it.

@omninonsense
Copy link
Contributor Author

@iduuck Try doing what @zaguiini suggested. I don't think this is related to styled-components typings directly (could be wrong). I wasn't aware of the as prop mechanism in styled-components.

@zaguiini
Copy link

@iduuck Try doing what @zaguiini suggested. I don't think this is related to styled-components typings directly (could be wrong). I wasn't aware of the as prop mechanism in styled-components.

There is indeed one "as" mechanism: https://www.styled-components.com/docs/basics#extending-styles

@omninonsense
Copy link
Contributor Author

omninonsense commented Nov 16, 2018

Hi @AndrewSouthpaw

If we don't get a PR from people with more context within a week, I'm okay with merging it in (after reviewing with little context) and letting to be "better than nothing," and people can continue adding fixes as needed. @omninonsense if this stagnates for too long just ping again and I'll merge it in.

I have some updated typings that I need to push, but got busy/distracted by work. I will probably get back to adding some updates early next week after cleaning them up and adding tests to try and add some of the missing APIs (if possible without breaking the typings for the "primary functionality" of the library).

@omninonsense
Copy link
Contributor Author

@iduuck Try doing what @zaguiini suggested. I don't think this is related to styled-components typings directly (could be wrong). I wasn't aware of the as prop mechanism in styled-components.

There is indeed one "as" mechanism: https://www.styled-components.com/docs/basics#extending-styles

Added to the checklist! :)

@omninonsense
Copy link
Contributor Author

I decided to give up on withComponent, attrs APIs and the as prop API for now; there is no way to add them without breaking more important stuff (or adding them at all).

I'll look into adding the react native stuff later today or tomorrow.

@omninonsense
Copy link
Contributor Author

omninonsense commented Nov 22, 2018

I think this is ready-ish for review, @AndrewSouthpaw. At least until we get better support for better typing from @facebook/flow

@SpainTrain
Copy link
Contributor

For tracking React feature support in flow:

Copy link
Contributor

@AndrewSouthpaw AndrewSouthpaw left a comment

Choose a reason for hiding this comment

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

Generally looks good. Unless there's a strong need, I'd collapse the separate test files into one and scope with describe/it blocks.

@omninonsense
Copy link
Contributor Author

Generally looks good. Unless there's a strong need, I'd collapse the separate test files into one and scope with describe/it blocks.

Will do! I only split them up because I assumed it would make them easier to read/understand. 😃

@omninonsense
Copy link
Contributor Author

@AndrewSouthpaw I used a few (random) other libdefs to see how to structure it. Is it okay like this?

@omninonsense
Copy link
Contributor Author

Had a random epiphany that attrs can be supported.

@omninonsense
Copy link
Contributor Author

Forgot about styled-components/native. 👀

Sorry about the noise!

@omninonsense
Copy link
Contributor Author

@egeriis Yes, but see #2933 (comment) about flow not fully supporting template literals.

@egeriis
Copy link

egeriis commented Jan 22, 2019

@omninonsense Yeah, I read it. Mind slip that I didn't understand it would affect being able to do this.

@omninonsense
Copy link
Contributor Author

omninonsense commented Jan 22, 2019

I think TypeScript supports something along these lines:

const MyDiv: StyledComponentType<'div', Props> = styled.div``;

It would be nice if we could support this too someday.

@egeriis
Copy link

egeriis commented Jan 23, 2019

@omninonsense Idea of effort required to fix the CI errors?

@omninonsense
Copy link
Contributor Author

omninonsense commented Jan 23, 2019

I haven't actually looked at fixing it.

I rebased and pushed. Hopefully that fixes it. 🤷‍♂️

(Didn't mean to close, I misclicked, I am stupid)

@egeriis
Copy link

egeriis commented Jan 25, 2019

@omninonsense It didn't work ;)

@pascalduez
Copy link
Member

Tests are failing for older versions of the typdef, mostly due to recent Flow changes.
Given it's been tested by some users here and all the work already been done, I would merge this. Opening the path for a follow-up on Flow > 0.75, okay for you @AndrewSouthpaw?

@egeriis
Copy link

egeriis commented Jan 28, 2019

Which Flow versions is this libdef compatible with?

@goodmind
Copy link
Contributor

facebook/flow#3936

@AndrewSouthpaw
Copy link
Contributor

Seems reasonable to me!

@AndrewSouthpaw AndrewSouthpaw merged commit 1a7d5ca into flow-typed:master Jan 29, 2019
@AndrewSouthpaw
Copy link
Contributor

Also, would just like to say, way to go @omninonsense on your commitment on this PR.

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.

None yet