-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add typings to react-emotion package * Fix CSSProperties and add more tests * Remove --jsx flag from tsc command * Add withComponent to typescript_tests * Fix a mistake in withComponent typing * Add support to more interpolations edge cases * Added declaration to tsconfig * Can use emotion helpers importing from react-emotion in ts * Creates typescript documentation * Adds typescript link in docs readme * Update typescript.md * Update typescript.md * Update typescript.md
- Loading branch information
Showing
6 changed files
with
455 additions
and
2 deletions.
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.