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

Restructured types to greatly reduce number of types created during c… #1501

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
a4e875c
Restructured types to greatly reduce number of types created during c…
Sep 12, 2019
f248044
Fixing tests
Sep 24, 2019
2609453
Fixed a bunch of tests and improved TypeScript docs
Sep 24, 2019
9964573
Updated a bunch of the TypeScript docs
Sep 24, 2019
93a5cd3
Removed WithTheme type, not sure it's usage and there is no tests
Sep 24, 2019
405b777
Few small cleanups around styled-base
Sep 24, 2019
33fdfd1
Fixed tests in a few more packages
Sep 26, 2019
51cc51f
Fixed serialise tests after changes in https://github.com/emotion-js/…
Sep 28, 2019
a16b80b
Removed failing redundant test in sheet typescript tests.
Sep 28, 2019
5be2e79
Removed line with expected error, I am not sure the reason it should …
Sep 28, 2019
fee9816
Need to bump the typescript version for styled-base for the union typ…
Sep 28, 2019
813d1ab
TypeScript tests passing
Sep 29, 2019
9b05e18
Upgrade build image version to get newer version of yarn
Sep 29, 2019
117b0ab
fix: styled component with static API
laysent Sep 25, 2019
f73957d
Added changes in https://github.com/JakeGinnivan/emotion/pull/1/files…
Sep 29, 2019
0fa359d
fix: type issue where styled component passed in
laysent Sep 29, 2019
b359132
Add some additional tests around theming and fix them
Oct 1, 2019
242688f
Restrict css function to css interpolation
Oct 1, 2019
c136f68
Fixed emotion-theming linting issue
Oct 1, 2019
58ca775
Reversed some incorrect type changes, withComponent has to include th…
Oct 1, 2019
064a193
Fixed some accidently formatted package.json files
Oct 1, 2019
7574110
Allowed theming of CreateStyled and StyledTags
Oct 1, 2019
a105f5a
Restructured generic type params to make it explicit about what compo…
Oct 1, 2019
c0fcdb4
Cleaned up some tests and added additional assertions
Oct 1, 2019
a05f240
Default the type of SpecificComponentProps in StyledComponent
Oct 2, 2019
dd8813d
Reverted changes around ThemeProvider and added tests
Oct 2, 2019
d43caa4
Added changeset
Oct 2, 2019
6ec5341
Fixed ThemeProvider after revert
Oct 2, 2019
0694cc9
Update tslint rules to fix error
Oct 2, 2019
e0871b6
Fixed linting issues
Oct 2, 2019
7d76626
Fixed import path for css and clarified docs
Oct 3, 2019
d41df4b
Added comment about fragment shorthand without babel being a typescri…
Oct 3, 2019
ced228c
Removed breaking change around some of the internal types
Oct 3, 2019
8a025e5
Reverted changes around removing function interpolation from the ret…
Oct 3, 2019
ae5b394
Renamed Omit to DistributiveOmit
Oct 3, 2019
58e0453
Removed duplicate intersected type
Oct 3, 2019
637b983
Renamed all usages of SFC to FC
Oct 3, 2019
71f9be7
Fixed poor grammar
Oct 3, 2019
a101f29
Ignore lint rule rather than exporting type
Oct 3, 2019
fb985b0
Updated generic constraints
Oct 3, 2019
6a54a7b
Reverted TypeScript version bump in create-emotion types
Oct 3, 2019
4606117
Sync docs and test code
Oct 3, 2019
bad9740
Constrained Theme to extend {}
Oct 28, 2019
5d4d1ef
Add tests for broken examples in #1298
Oct 29, 2019
7f6e717
Merge remote-tracking branch 'origin/master' into feature/improve-typ…
Nov 3, 2019
4f0e16b
Fix typo
Nov 3, 2019
c336eba
Add test which verifies #1226 is fixed by type changes
Nov 4, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .changeset/long-apes-admire/changes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"releases": [
{ "name": "@emotion/css", "type": "minor" },
{ "name": "emotion-theming", "type": "minor" },
{ "name": "@emotion/serialize", "type": "minor" },
{ "name": "@emotion/styled-base", "type": "minor" },
{ "name": "@emotion/styled", "type": "minor" }
],
"dependents": [
{
"name": "babel-plugin-emotion",
"type": "patch",
"dependencies": ["@emotion/serialize"]
},
{
"name": "@emotion/core",
"type": "patch",
"dependencies": [
"@emotion/css",
"emotion-theming",
"@emotion/serialize",
"@emotion/styled"
]
},
{
"name": "create-emotion",
"type": "patch",
"dependencies": ["@emotion/serialize"]
}
]
}
31 changes: 31 additions & 0 deletions .changeset/long-apes-admire/changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
TypeScript types have been restructured. These changes:

- Reduce build times when using emotion
- In many cases remove the need for manually specifying generic parameters for your emotion components.

If you encounter build issues after upgrade, try removing any manually specified generic types and let them be inferred. Otherwise refer to the breaking changes list below.

## Improvements

- useTheme added to EmotionTheming interface and can now create your own closed variation of withTheme. More information in the docs under the theming section.
- Union types as props are better supported and should be inferred properly
- Build times should be reduced significantly in larger projects.

## Breaking changes

- withTheme can now have the Theme type specified when calling it. For example `withTheme<MyTheme>(MyComponent)`

**Breaking change:** Generic argument changed, if you were specifying the ComponentType you will need to remove the generic parameter. Recommend following example setup in the TypeScript docs under theming section

- `css` function has been restricted to prevent passing of invalid types
- `CreateStyled` functions no longer take a second `ExtraProps` argument. Instead move it to after the create styled call. For example

`styled<typeof MyComponent, ExtraProps>(MyComponent)({})`
to
`styled(MyComponent)<ExtraProps>({})`
Andarist marked this conversation as resolved.
Show resolved Hide resolved

- `StyledComponent` type no longer supports the third generic `Theme` parameter. Instead add the `theme` prop to the first `Props` argument. For example:

`StyledComponent<Props, {}, MyTheme>`
to
`StyledComponent<Props & { theme?: MyTheme }>`
9 changes: 5 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 2
jobs:
flow:
docker:
- image: circleci/node:10.6.0-browsers
- image: circleci/node:10.16.3-browsers
working_directory: ~/repo
steps:
- checkout
Expand All @@ -25,7 +25,7 @@ jobs:

test:
docker:
- image: circleci/node:10.6.0
- image: circleci/node:10.16.3
working_directory: ~/repo
steps:
- checkout
Expand All @@ -48,7 +48,7 @@ jobs:

test_dist:
docker:
- image: circleci/node:10.6.0
- image: circleci/node:10.16.3
working_directory: ~/repo
steps:
- checkout
Expand All @@ -66,7 +66,7 @@ jobs:

lint_and_typescript:
docker:
- image: circleci/node:10.6.0
- image: circleci/node:10.16.3
working_directory: ~/repo
steps:
- checkout
Expand All @@ -77,6 +77,7 @@ jobs:
- v4-dependencies-
- run: yarn install --pure-lockfile
- run: yarn lint:check
- run: yarn test:typescript

workflows:
version: 2
Expand Down
117 changes: 68 additions & 49 deletions docs/typescript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,21 @@ To make the css prop work with pure TypeScript (without babel plugin) you need t

```tsx
/** @jsx jsx */
import { css, jsx } from '@emotion/core'
import { jsx } from '@emotion/core'

<div css={{ background: 'black' }} />
```

As a result you may be not able to use react fragment shorthand syntax - `<></>`, but still you can use `<Fragment></Fragment>`.
Andarist marked this conversation as resolved.
Show resolved Hide resolved
This is a limitation of the TypeScript compiler not being able to independently specify jsx pragma and jsxFrag pragma.

You can still use the css helper and pass the className yourself (ensure you are importing from the `@emotion` package, not `@emotion/core`).
Copy link
Member

@Andarist Andarist Nov 2, 2019

Choose a reason for hiding this comment

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

I'm not sure if this should be included in these sections - seem a little bit off-putting, especially given that we don't mention this in non-TS sections (as far as i know).

And also slight nit - @emotion should be emotion

Choose a reason for hiding this comment

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

I think that this is a crucial bit of information and should be included both here - and in the non TS docs. "Off putting" up front is better than broken and surprising in hindsight.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure about that @Andarist, @emotion/core is mentioned everywhere else. I personally don't use the css prop so I pulled this info out of somewhere when I noticed it. It felt like something which should be in the docs


```tsx
import { css } from '@emotion'

<div className={css({ background: 'black' })} />
Andarist marked this conversation as resolved.
Show resolved Hide resolved
```

## @emotion/styled

Expand Down Expand Up @@ -103,28 +114,20 @@ type ImageProps = {
width: number
}

const Image0 = styled('div')`
width: ${(props: ImageProps) => props.width};
background: url(${(props: ImageProps) => props.src})
center center;
// Using a css block
const Image0 = styled.div<ImageProps>`
width: ${props => props.width};
background: url(${props => props.src}) center center;
background-size: contain;
`
const Image0 = styled('div')<ImageProps>`
width: ${props => props.width};
background: url(${props => props.src}) center center;
background-size: contain;
`

// Or with object styles

const Image1 = styled('div')(
{
backgroundSize: 'contain'
},
(props: ImageProps) => ({
width: props.width,
background: `url(${props.src}) center center`
})
)

// Or with a generic type

const Image2 = styled('div')<ImageProps>(
const Image1 = styled('div')<ImageProps>(
{
backgroundSize: 'contain'
},
Expand All @@ -133,36 +136,28 @@ const Image2 = styled('div')<ImageProps>(
background: `url(${props.src}) center center`
})
)

// TS 2.9+ only
const Image3 = styled.div<ImageProps>`
width: ${(props: ImageProps) => props.width};
background: url(${(props: ImageProps) => props.src})
center center;
background-size: contain;
`
```

- For TypeScript <2.9, the generic type version only works with object styles due to https://github.com/Microsoft/TypeScript/issues/11947.

### React Components

Emotion can also style React components and will infer component props as expected.

```tsx
import React, { SFC } from 'react'
import React, { FC } from 'react'
import styled from '@emotion/styled'

type ComponentProps = {
interface ComponentProps {
className?: string
label: string
}

const Component: SFC<ComponentProps> = ({
const Component: FC<ComponentProps> = ({
label,
className
}) => <div className={className}>{label}</div>

const StyledComponent0 = styled(Component)`
color: red;
color: ${props => label === 'Important' ? 'red' : 'green'};
`

const StyledComponent1 = styled(Component)({
Expand All @@ -171,7 +166,7 @@ const StyledComponent1 = styled(Component)({

const App = () => (
<div>
<StyledComponent0 label="Yea! No need to re-type this label prop." />
<StyledComponent0 label="Important" />
<StyledComponent1 label="Yea! No need to re-type this label prop." />
</div>
)
Expand All @@ -180,37 +175,32 @@ const App = () => (
### Passing props when styling a React component

```tsx
import React, { SFC } from 'react'
import React, { FC } from 'react'
import styled from '@emotion/styled'

type ComponentProps = {
interface ComponentProps {
className?: string
label: string
}

const Component: SFC<ComponentProps> = ({
const Component: FC<ComponentProps> = ({
label,
className
}) => <div className={className}>{label}</div>

type StyledComponentProps = {
interface StyledComponentProps {
bgColor: string
}

const StyledComponent0 = styled(Component)`
const StyledComponent0 = styled(Component)<StyledComponentProps>`
color: red;
background: ${(props: StyledComponentProps) =>
props.bgColor};
background: ${props => props.label ? props.bgColor : 'white'};
`

const StyledComponent1 = styled(Component)<
StyledComponentProps
>(
{
color: 'red'
},
// or
const StyledComponent1 = styled(Component)<StyledComponentProps>(
props => ({
background: props.bgColor
color: 'red'
background: props.label ? props.bgColor : 'white'
})
)

Expand All @@ -237,6 +227,7 @@ _styled.tsx_

```tsx
import styled, { CreateStyled } from '@emotion/styled'
import * as emotionTheming from 'emotion-theming'

type Theme = {
color: {
Expand All @@ -248,6 +239,10 @@ type Theme = {
}

export default styled as CreateStyled<Theme>

// You can also create themed versions of all the other theme helpers and hooks
const { ThemeProvider, withTheme, useTheme } = emotionTheming as emotionTheming.EmotionTheming<Theme>
export { ThemeProvider, withTheme, useTheme }
```

_Button.tsx_
Expand All @@ -263,3 +258,27 @@ const Button = styled('button')`

export default Button
```

### TypeScript < 2.9

For Typescript <2.9, the generic type version only works with object styles due to https://github.com/Microsoft/TypeScript/issues/11947.

You can work around this by specifying the prop types in your style callback:

``` ts
const StyledComponent0 = styled(Component)`
color: red;
background: ${(props: StyledComponentProps) =>
props.bgColor};
`
```

NOTE: This approach you will have to perform the intersection with the component props yourself to get at the component props

``` ts
const StyledComponent0 = styled(Component)`
color: red;
background: ${(props: StyledComponentProps & ComponentProps) =>
props.bgColor};
`
```
3 changes: 3 additions & 0 deletions packages/babel-plugin-emotion/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"lib",
"dist"
],
"scripts": {
"test:typescript": "exit 0"
},
"dependencies": {
"@babel/helper-module-imports": "^7.0.0",
"@emotion/hash": "0.7.3",
Expand Down
3 changes: 3 additions & 0 deletions packages/babel-plugin-jsx-pragmatic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"module": "dist/babel-plugin-jsx-pragmatic.esm.js",
"license": "MIT",
"repository": "https://github.com/emotion-js/emotion/tree/master/packages/babel-plugin-jsx-pragmatic",
"scripts": {
"test:typescript": "exit 0"
},
"dependencies": {
"@babel/plugin-syntax-jsx": "^7.2.0"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/babel-preset-css-prop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"module": "dist/babel-preset-css-prop.esm.js",
"license": "MIT",
"repository": "https://github.com/emotion-js/emotion/tree/master/packages/babel-preset-css-prop",
"scripts": {
"test:typescript": "exit 0"
},
"dependencies": {
"@babel/plugin-transform-react-jsx": "^7.3.0",
"@babel/runtime": "^7.5.5",
Expand Down
10 changes: 6 additions & 4 deletions packages/core/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ComponentClass,
Context,
Provider,
SFC,
FC,
ReactElement,
ReactNode,
Ref,
Expand All @@ -30,7 +30,7 @@ export const ThemeContext: Context<object>
export const CacheProvider: Provider<EmotionCache>
export function withEmotionCache<Props, RefType = any>(
func: (props: Props, context: EmotionCache, ref: Ref<RefType>) => ReactNode
): SFC<Props & ClassAttributes<RefType>>
): FC<Props & ClassAttributes<RefType>>

export const jsx: typeof createElement

Expand All @@ -45,7 +45,9 @@ export interface GlobalProps<Theme> {
* @desc
* JSX generic are supported only after [email protected]
*/
export function Global<Theme = any>(props: GlobalProps<Theme>): ReactElement
export function Global<Theme extends {} = any>(
props: GlobalProps<Theme>
): ReactElement

export function keyframes(
template: TemplateStringsArray,
Expand Down Expand Up @@ -75,7 +77,7 @@ export interface ClassNamesProps<Theme> {
* @desc
* JSX generic are supported only after [email protected]
*/
export function ClassNames<Theme = any>(
export function ClassNames<Theme extends {} = any>(
props: ClassNamesProps<Theme>
): ReactElement

Expand Down
2 changes: 0 additions & 2 deletions packages/core/types/tests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import {
ClassNames,
ClassNamesContent,
Global,
Interpolation,
CacheProvider,
css,
jsx,
keyframes,
Expand Down
Loading