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

styled-components: Add more complete support for object styles, tests #30511

Merged

Conversation

Jessidhia
Copy link
Member

  • Use a meaningful title for the pull request. Include the name of the package modified.
  • Test the change in your own code. (Compile and run.)
  • Add or edit tests to reflect the change. (Run with npm test.)
  • Follow the advice from the readme.
  • Avoid common mistakes.
  • Run npm run lint package-name (or tsc if no tslint.json is present).

@Jessidhia Jessidhia requested a review from Igorbek as a code owner November 14, 2018 04:15
@typescript-bot
Copy link
Contributor

typescript-bot commented Nov 14, 2018

@Kovensky Thank you for submitting this PR!

🔔 @Igorbek @Igmat @lavoaster - please review this PR in the next few days. Be sure to explicitly select Approve or Request Changes in the GitHub UI so I know what's going on.

If no reviewer appears after a week, a DefinitelyTyped maintainer will review the PR instead.

> =
// at least the first argument is required, whatever it is
<U extends object>(
first: NonNullable<
Copy link
Member Author

Choose a reason for hiding this comment

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

Testing all these functions at runtime; if the first argument is missing or undefined, styled-components will throw by trying to index it. If it is null, styled-components will try to call it as a function 😆

Anyway, first interpolation is mandatory.

Copy link
Member Author

@Jessidhia Jessidhia Nov 14, 2018

Choose a reason for hiding this comment

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

Oh, this doesn't break usage as a template string because both Interpolation and SimpleInterpolation accept TemplateStringsArray (effectively string[] & { raw: string[] }) by being assignable to ReadonlyArray<string>.

Let me know if you want it to still be left there explicitly.

| FlattenInterpolation<P>;
// must be an interface to be self-referential
export interface FlattenInterpolation<P>
extends ReadonlyArray<Interpolation<P>> {}
Copy link
Member Author

Choose a reason for hiding this comment

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

They can be arbitrarily nested.

> sc.css([[[[[[['color: green;']]]]]]])
[ 'color: green;' ]

| FlattenSimpleInterpolation;
// must be an interface to be self-referential
interface FlattenSimpleInterpolation
extends ReadonlyArray<SimpleInterpolation> {}
Copy link
Member Author

Choose a reason for hiding this comment

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

Same with SimpleInterpolation

> sc.keyframes([[[[[[['from { color: green; }']]], { to: { color: 'red' } }]]]])
Keyframes {
  inject: [Function],
  toString: [Function],
  name: 'ijNbFt',
  rules:
   [ '@-webkit-keyframes ijNbFt{from{color:green;}to{color:red;}}',
     '@keyframes ijNbFt{from{color:green;}to{color:red;}}' ],
  id: 'sc-keyframes-ijNbFt' }

However, keyframes absolutely cannot take any function. It'll just call .toString() on it and add to the rules.

export type ThemedGlobalStyledClassProps<P, T> = P & {
suppressMultiMountWarning?: boolean
theme?: T
export type ThemedGlobalStyledClassProps<P, T> = WithOptionalTheme<P, T> & {
Copy link
Member Author

Choose a reason for hiding this comment

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

This wasn't excluding any theme that might have been expected by interpolations, so it'd be kept as a required prop.

StyledComponent<any, any>,
keyof StyledComponent<any, any>
AnyStyledComponent,
keyof StyledComponentBase<any, any>
Copy link
Member Author

Choose a reason for hiding this comment

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

Taking the keyof StyledComponentBase to get rid of everything in interface String {}...

A extends keyof any = never
> = // the "string" allows this to be used as an object key
// I really want to avoid this if possible but it's the only way to use nesting with object styles...
string & StyledComponentBase<C, T, O, A>;
Copy link
Member Author

Choose a reason for hiding this comment

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

This hack was needed to allow this:

const StyledDiv = styled.div``
css({
  background: 'white',
  [StyledDiv]: {
    background: 'black'
  }
})

This works because styled components have a toString() implementation, but just adding a toString(): string to the interface is not sufficient to make typescript like it as an object key.

export type BaseThemedCssFunction<T extends object> = <P>(
first: NonNullable<Interpolation<ThemedStyledProps<P, T>>>,
...interpolations: Array<Interpolation<ThemedStyledProps<P, T>>>
) => Array<FlattenInterpolation<ThemedStyledProps<P, T>>>;
Copy link
Member Author

Choose a reason for hiding this comment

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

The result is indeed always an array.

keyframes(
strings: TemplateStringsArray,
strings: TemplateStringsArray | CSSKeyframes,
...interpolations: SimpleInterpolation[]
): Keyframes;
Copy link
Member Author

Choose a reason for hiding this comment

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

This kinda doesn't belong here as it can't be affected by the type of theme anyway...... but on the other hand, omitting it would make it harder to use, with you having to import keyframes from elsewhere instead of from your strongly typed wrapper.

* without needing to reexport `ThemedStyledComponentsModule`.
*/
// Unfortunately, there is no way to write tests for this
// as any augmentation will break the tests for the default case (not augmented).
// tslint:disable-next-line:no-empty-interface
export interface DefaultTheme {}
Copy link
Member Author

Choose a reason for hiding this comment

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

I couldn't find any way to test this in an isolated context that wouldn't affect the type of DefaultTheme as seen from index.tsx. It's very important for the existing tests that DefaultTheme be empty...

However, augmenting DefaultTheme did cause expected type errors so it seems to work 🤷‍♀️

Jessidhia referenced this pull request Nov 14, 2018
…afe ref, and as (#30467)

* Add back context; add more helper context types and documentation

* Fix the handling of ref to properly exclude string refs where not supported

* Fix erroneous tests that got caught by the better Ref type

* Augment ComponentProps to support JSX.IntrinsicElements

* Add tests, doc comments for ComponentProps*

* Add self to Definitions by

* Add TODO comment

* Add comments about the "'ref' extends keyof P" checks

* Fix the handling of ref and props when using withComponent in styled-components

* Swap nesting order of mapped types to fix missing $ExpectErrors

* Comment out test that fails in [email protected]

* Hack to deal with the tests not failing when they should

* Rewrite styled-components

* Bump version

* Bump minimum TypeScript version

* Update types of @rebass/grid (depends on styled-components)

* Update styled-react-modal types to 1.1 (also styled-components related)

* Reformat styled-components's index.d.ts
@Jessidhia
Copy link
Member Author

Jessidhia commented Nov 15, 2018

Trying this out in a full codebase instead of just the tests...... there is an annoying amount of places where the generic inference stops working and you have to pass an explicit generic argument to css or styled 😕


There is one fix I need to make to the type of StyledComponentInterpolation, but the strangest part is that a function that accepts what would be a part of the interpolation type is no longer acceptable for inference (O & U is being inferred as never).

image

Giving it directly as a template argument using <> works, though.


Oh...... it seems that, because StyledComponent now "looks callable", that also having a StyledComponentInterpolation will cause its props to be united with function interpolation props, leading to chaos. 😭

I have no idea why, React.ReactElement is not a valid Interpolation.


I also managed to fix that, but the fix for that broke inference for the <U> argument in both css and styled. Unless you explicitly specify the generic argument, it will always be inferred as {}.

I also have no idea why 😢

More EDIT: I was accidentally returning an array array in css, fixing it to just being one array seems to have fixed everything 🎉

@Jessidhia
Copy link
Member Author

This is probably good for review

@typescript-bot typescript-bot added the Popular package This PR affects a popular package (as counted by NPM download counts). label Nov 17, 2018
@Igorbek
Copy link
Collaborator

Igorbek commented Nov 17, 2018

Awesome work, I hope I find time to try it out on my code base this weekend.

@franky47
Copy link

I had the same issue as @joealden as described in 5c49d4d#commitcomment-31305259, and I can confirm this PR fixed the problem, thanks !

@typescript-bot typescript-bot added the Unmerged The author did not merge the PR when it was ready. label Nov 21, 2018
@typescript-bot
Copy link
Contributor

After 5 days, no one has reviewed the PR 😞. A maintainer will be reviewing the PR in the next few days and will either merge it or request revisions. Thank you for your patience!

@uniqueiniquity uniqueiniquity merged commit aa7279d into DefinitelyTyped:master Nov 21, 2018
@Jessidhia Jessidhia deleted the styled-components-cssobject branch November 22, 2018 01:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Popular package This PR affects a popular package (as counted by NPM download counts). Unmerged The author did not merge the PR when it was ready.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants