Using styled-components With TypeScript
Using Styled-components with React and React Native is great. Where it really shines in my opinion is when you use it with TypeScript and VS Code, getting code suggestions and errors when you write something wrong. In this article, we are going to take a look at how to use TypeScript with styled-components for better developer experience:
- Styled-components with VS Code and types for styled-components
- Theme variable suggestions using declaration merging
- Type checking for component props
Styled-components With VS Code
As a prerequisite, it is crucial to mention the vscode-styled-components plugin for VS Code. This plugin vastly improves the writing of styled-components with syntax highlighting, error reporting, and IntelliSense. When combined with TypeScript and styled-components, the developer experience is truly enhanced.
Styled Components doesn’t come with types so we need to install them either running:
npm i --save-dev @types/styled-components
or alternatively
yarn add @types/styled-components --dev
Theme variable suggestions using declaration merging
Wouldn’t it be cool if you get type-checking for the themes you’ve created, as well as auto-complete for the theme variables? So that when you’re writing something like this:
// The commonly seen way of accessing them
const TextOne = styled.Text`
color: ${(props) => props.theme.primaryColor};
`
// Or by using object desctructuring for cleaner code
const TextSecond = styled.Text`
color: ${({ theme }) => theme.primaryColor};
`
Then you wouldn’t have to remember if whether the primary color was written as primaryColor
or primary_color.
Instead, your IDE tells you what theme variables stored inside the theme object you’ve created.
Well good news, you can easily achieve this by using the Typescript interface merging to override the default theme that comes with styled-components (more info on how declaration merging works can be found here, and here). Here’s how to achieve that:
-
To access the theme in our app, we need to first set up ThemeProvider and then pass down our custom theme inside it.
-
Then we create the theme file, import the original styled-components module declaration and extend it using declaration merging. We add our own theme variables like
primaryColor
to theDefaultTheme
and tell our theme objects to use that interface.
// App.tsx
import React from 'react'
import { ThemeProvider } from 'styled-components/native'
import Navigation from '/navigation'
import { lightTheme } from '/styles/theme'
const App = () => {
return (
<ThemeProvider theme={lightTheme}>
<Navigation />
</ThemeProvider>
)
}
export default App
We could do this in a separate styled-components.d.ts declaration file, but placing it inside the themes.ts file allows us to tweak the theme definition at the same when we add new variables.
With the declaration merging done using the theme variables suggestions in VS Code should look like this now:
No more guessing whether it was accentColor or colorAccent.
Type-checking for custom Props
Another typical case with styled-components is using the props of the styled component to alter the styling, e.g. creating a button container that has the prop “disabled” and then using it as the conditional for reducing opacity like this:
import React from 'react'
import styled from 'styled-components/native'
type Props = {
disabled: boolean
}
const StartButton = ({ disabled }: Props) => {
return (
<Button disabled={disabled}>
<ButtonText>Start counter</ButtonText>
</Button>
)
}
const Button = styled.TouchableOpacity`
opacity: ${(props) => (props.disabled ? 0.5 : 1)};
`
const ButtonText = styled.Text`
font-size: 17px;
`
export default StartButton
This works pretty well and when we type props.something
VS Code should even show us an IntelliSense suggestion for the disabled prop, as long as we’ve installed the styled-components type definition. This is because those type definitions contain the type definition for TouchableOpacity
with definition for the disabled
prop. However, if were to define our own prop, something such as primary
which would be of boolean value we would get a type error like the below:
To fix this we need to add a new type for our button which contains the primary prop and then tell styled-components to use it:
type ButtonProps = {
primary: boolean
}
const Button = styled.TouchableOpacity<ButtonProps>`
opacity: ${(props) => (props.primary ? 0.5 : 1)};
`
Now we should no longer get the error message unless we try to use the wrong value there. On top of that we also get autocomplete when using it to alter the styles: