Home > front end >  Typescript and defaultProps on a styled component
Typescript and defaultProps on a styled component

Time:04-08

I have the following styled component:

import styled from "styled-components"
import { rem } from 'polished';
import theme from '../../theme';

type ButtonType = {
    intent?: keyof typeof theme.button;
};

const Button = styled.button<ButtonType>`
  border: ${({ intent }) => rem(theme.button[intent]["border-width"])} ${({ intent }) => theme.button[intent]["border-style"]} ${({ intent }) => theme.button[intent]["border-color"]};
  color: ${({ intent }) => theme.button[intent].color};
`;

Button.defaultProps = {
    intent: 'default',
};

export default Button;

where the theme is:

const intent = {
    default: '#000000',
    error: '#FF0000',
    warning: '#FF7900',
};

const theme = {
    button: {
        default: {
            'border-color': intent.default,
            'border-style': intent.default,
            'border-width': 2,
            color: intent.default,
        },
        error: {
            'border-color': intent.error,
            'border-style': intent.error,
            'border-width': 2,
            color: intent.error,
        },
        warning: {
            'border-color': intent.warning,
            'border-style': intent.warning,
            'border-width': 2,
            color: intent.warning,
        }
    }
};

export default theme;

I'm getting the following Typescript error:

Type 'undefined' cannot be used as an index type.

Not sure why it is assuming that intent is ever undefined if it is defined in the defaultProps - how can I get TypeScript to recognise this?

CodePudding user response:

Based on your type definition for ButtonType, it is possible for intent to be undefined. Typescript compiler detects that and gives you the said error.

Making intent non-optional should fix the issue:

type ButtonType = {
    intent: keyof typeof theme.button;
};

CodePudding user response:

TypeScript is not going to pick up on anything you define via Button.defaultProps, so it doesn't "know" that it has a default value. Instead you may have to set the default value directly in the component definition:

const Button = styled.button<ButtonType>`
  border: ${({ intent = 'default' }) => rem(theme.button[intent]["border-width"])} ${({ intent = 'default' }) => theme.button[intent]["border-style"]} ${({ intent = 'default' }) => theme.button[intent]["border-color"]};
  color: ${({ intent = 'default' }) => theme.button[intent].color};
`;
  • Related