1

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?

JoeTidee
  • 24,754
  • 25
  • 104
  • 149

2 Answers2

1

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;
};
hawschiat
  • 306
  • 1
  • 5
  • This works, but now I get a different error when passing in the prop `intent={intent}` - Type 'string' is not assignable to type '"default" | "error" | "warning"'. – JoeTidee Apr 07 '22 at 23:06
  • You can fix that issue by casting `intent` to a const like `intent={intent as const}`. See this thread for more info https://stackoverflow.com/questions/37978528/typescript-type-string-is-not-assignable-to-type – hawschiat Apr 07 '22 at 23:10
  • 1
    This didn't work, so managed to fix it using `intent={intent as IntentType}`, where `IntentType` is `type IntentType = keyof typeof theme.button` – JoeTidee Apr 07 '22 at 23:24
0

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};
`;
jered
  • 11,220
  • 2
  • 23
  • 34