-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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 types to react-emotion #398
Merged
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
77f512a
Add typings to react-emotion package
renatorib f8841cd
Fix CSSProperties and add more tests
renatorib 789acc0
Remove --jsx flag from tsc command
renatorib 71397a1
Add withComponent to typescript_tests
renatorib e43bdd3
Fix a mistake in withComponent typing
renatorib b6d3f50
Add support to more interpolations edge cases
renatorib 556463e
Added declaration to tsconfig
renatorib 1d37138
Merge branch 'master' into master
renatorib 651daf3
Can use emotion helpers importing from react-emotion in ts
renatorib c0f6436
Merge branch 'master' into master
renatorib ecdcb54
Merge branch 'master' into master
renatorib a009aef
Merge branch 'master' into master
renatorib ca17714
Merge branch 'master' into master
a48458d
Creates typescript documentation
renatorib f2e8603
Adds typescript link in docs readme
renatorib af24683
Update typescript.md
815dde2
Update typescript.md
8209aab
Update typescript.md
f74de2d
Merge branch 'master' into master
renatorib File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
## TypeScript | ||
|
||
Emotion includes TypeScript definitions for `styled` components and has type inferences for both html elements and React components. | ||
|
||
### html elements | ||
|
||
```jsx | ||
import styled from 'react-emotion' | ||
|
||
const Link = styled('a')` | ||
color: red; | ||
` | ||
|
||
const App = () => ( | ||
<Link href="#">Click me</Link> | ||
) | ||
``` | ||
|
||
```jsx | ||
import styled from 'react-emotion' | ||
|
||
const NotALink = styled('div')` | ||
color: red; | ||
` | ||
|
||
const App = () => ( | ||
<NotALink href="#">Click me</NotALink> | ||
^^^^^^^^ Property 'href' does not exist [...] | ||
) | ||
``` | ||
|
||
### `withComponent` | ||
|
||
```jsx | ||
import styled from 'react-emotion' | ||
|
||
const NotALink = styled('div')` | ||
color: red, | ||
` | ||
|
||
const Link = NotALink.withComponent('a') | ||
|
||
const App = () => ( | ||
<Link href="#">Click me</Link> | ||
) | ||
|
||
// No errors! | ||
``` | ||
|
||
### Passing Props | ||
|
||
You can type the props of your styled components. | ||
Unfortunately, you will need to pass a second parameter with the tag name because TypeScript is unable to infer the tagname. | ||
|
||
```jsx | ||
import styled from 'react-emotion' | ||
|
||
type ImageProps = { | ||
src: string, | ||
} | ||
|
||
const Image = styled<ImageProps, 'div'>('div')` | ||
background: url(${props => props.src}) center center; | ||
background-size: contain; | ||
` | ||
``` | ||
|
||
### Object Styles | ||
|
||
```jsx | ||
import styled from 'react-emotion' | ||
|
||
type ImageProps = { | ||
src: string, | ||
} | ||
|
||
const Image = styled<ImageProps, 'div'>('div')({ | ||
backgroundSize: contain; | ||
}, ({ src }) => ({ | ||
background: `url(${src}) center center`, | ||
})) | ||
|
||
// Or shorthand | ||
|
||
const Image = styled.div<ImageProps>({ | ||
backgroundSize: contain; | ||
}, ({ src }) => ({ | ||
background: `url(${src}) center center`, | ||
})) | ||
|
||
``` | ||
|
||
* Note that in shorthand example you don't need to pass the tag name argument. | ||
* The shorthand only works with object styles due to https://github.com/Microsoft/TypeScript/issues/11947. | ||
|
||
### React Components | ||
|
||
```jsx | ||
import React, { SFC } from 'react' | ||
import styled from 'react-emotion' | ||
|
||
type ComponentProps = { | ||
className?: string, | ||
label: string, | ||
} | ||
|
||
const Component: SFC = ({ label, className }) => ( | ||
<div className={className}> | ||
{label} | ||
</div> | ||
) | ||
|
||
const StyledComponent = styled(Component)` | ||
color: red; | ||
` | ||
|
||
const App = () => ( | ||
<StyledComponent label="Yea! No need to re-type this label prop." /> | ||
) | ||
``` | ||
|
||
### Passing props when styling a React component | ||
|
||
```jsx | ||
import React, { SFC } from 'react' | ||
import styled from 'react-emotion' | ||
|
||
type ComponentProps = { | ||
className?: string, | ||
label: string, | ||
} | ||
|
||
const Component: SFC = ({ label, className }) => ( | ||
<div className={className}> | ||
{label} | ||
</div> | ||
) | ||
|
||
type StyledComponentProps = { | ||
bgColor: string, | ||
} & ComponentProps | ||
// ^^^ You will need this | ||
|
||
const StyledComponent = styled<StyledComponentProps>(Component)` | ||
color: red; | ||
background: ${props => props.bgColor}; | ||
` | ||
|
||
const App = () => ( | ||
<StyledComponent bgColor="red" label="Oh, needs to re-type label prop =(" /> | ||
) | ||
``` | ||
|
||
Unfortunately, when you pass custom props to a styled component, TypeScript will stop inferring your Component props, and you will need to re-type them. | ||
|
||
### Define a Theme | ||
|
||
By default, the `props.theme` has `any` type annotation and works without error. | ||
However, you can define a theme type by creating a another `styled` instance. | ||
|
||
*styled.tsx* | ||
```jsx | ||
import styled, { ThemedReactEmotionInterface } from 'react-emotion' | ||
|
||
type Theme = { | ||
color: { | ||
primary: string, | ||
positive: string, | ||
negative: string, | ||
}, | ||
// ... | ||
} | ||
|
||
export default styled as ThemedReactEmotionInterface<Theme> | ||
``` | ||
|
||
*Button.tsx* | ||
```jsx | ||
import styled from '../pathto/styled' | ||
|
||
const Button = styled('button')` | ||
padding: 20px; | ||
background-color: ${props => props.theme.primary}; | ||
border-radius: 3px; | ||
` | ||
|
||
export default Button | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "es5", | ||
"module": "es2015", | ||
"declaration": true, | ||
"strict": true, | ||
"allowSyntheticDefaultImports": true, | ||
"moduleResolution": "node", | ||
"jsx": "react" | ||
}, | ||
"include": [ | ||
"./*.ts", | ||
"./*.tsx" | ||
] | ||
} |
133 changes: 133 additions & 0 deletions
133
packages/react-emotion/typescript_tests/typescript_tests.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import React from 'react'; | ||
import styled, { flush, ThemedReactEmotionInterface } from '../'; | ||
|
||
let Component; | ||
let mount; | ||
|
||
/* | ||
* Inference HTML Tag Props | ||
*/ | ||
Component = styled.div({ color: 'red' }); | ||
mount = <Component onClick={event => event} />; | ||
|
||
Component = styled('div')({ color: 'red' }); | ||
mount = <Component onClick={event => event} />; | ||
|
||
Component = styled.div`color: red;`; | ||
mount = <Component onClick={(e) => e} />; | ||
|
||
Component = styled('div')`color: red;`; | ||
mount = <Component onClick={(e) => e} />; | ||
|
||
Component = styled.a({ color: 'red' }); | ||
mount = <Component href="#" />; | ||
|
||
Component = styled('a')({ color: 'red' }); | ||
mount = <Component href="#" />; | ||
|
||
/* | ||
* Passing custom props | ||
*/ | ||
type CustomProps = { lookColor: string }; | ||
|
||
Component = styled.div<CustomProps>( | ||
{ color: 'blue' }, | ||
props => ({ | ||
background: props.lookColor, | ||
}), | ||
props => ({ | ||
border: `1px solid ${props.lookColor}`, | ||
}), | ||
); | ||
mount = <Component lookColor="red" />; | ||
|
||
Component = styled<CustomProps, 'div'>('div')( | ||
{ color: 'blue' }, | ||
props => ({ | ||
background: props.lookColor, | ||
}), | ||
); | ||
mount = <Component lookColor="red" />; | ||
|
||
const anotherColor = 'blue'; | ||
Component = styled<CustomProps, 'div'>('div')` | ||
background: ${props => props.lookColor}; | ||
color: ${anotherColor}; | ||
` | ||
mount = <Component lookColor="red" />; | ||
|
||
/* | ||
* With other components | ||
*/ | ||
type CustomProps2 = { customProp: string }; | ||
type SFCComponentProps = { className?: string, foo: string }; | ||
|
||
const SFCComponent: React.StatelessComponent<SFCComponentProps> = props => ( | ||
<div className={props.className}>{props.children} {props.foo}</div> | ||
); | ||
|
||
// infer SFCComponentProps | ||
Component = styled(SFCComponent)({ color: 'red' }); | ||
mount = <Component foo="bar" />; | ||
|
||
// infer SFCComponentProps | ||
Component = styled(SFCComponent)`color: red`; | ||
mount = <Component foo="bar" />; | ||
|
||
// do not infer SFCComponentProps with pass CustomProps, need to pass both | ||
Component = styled<CustomProps2 & SFCComponentProps>(SFCComponent)({ | ||
color: 'red', | ||
}, props => ({ | ||
background: props.customProp, | ||
})); | ||
mount = <Component customProp="red" foo="bar" />; | ||
|
||
// do not infer SFCComponentProps with pass CustomProps, need to pass both | ||
Component = styled<CustomProps2 & SFCComponentProps>(SFCComponent)` | ||
color: red; | ||
background: ${props => props.customProp}; | ||
`; | ||
mount = <Component customProp="red" foo="bar" />; | ||
|
||
|
||
/* | ||
* With explicit theme | ||
*/ | ||
|
||
type Theme = { | ||
color: { | ||
primary: string, | ||
secondary: string, | ||
} | ||
}; | ||
|
||
const _styled = styled as ThemedReactEmotionInterface<Theme>; | ||
|
||
Component = _styled.div` | ||
color: ${props => props.theme.color.primary} | ||
`; | ||
mount = <Component onClick={event => event} />; | ||
|
||
/* | ||
* withComponent | ||
*/ | ||
|
||
type CustomProps3 = { | ||
bgColor: string, | ||
}; | ||
|
||
Component = styled.div<CustomProps3>(props => ({ | ||
bgColor: props.bgColor, | ||
})); | ||
|
||
let Link = Component.withComponent('a'); | ||
mount = <Link href="#" bgColor="red" />; | ||
|
||
let Button = Component.withComponent('button'); | ||
mount = <Button type="submit" bgColor="red" />; | ||
|
||
/* | ||
* Can use emotion helpers importing from react-emotion | ||
*/ | ||
|
||
flush(); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
For glamorous we've added declaration: true to help make sure we're exporting everything required for use in libraries microsoft/TypeScript#5938.
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.
Done! Added.
No warnings
😄