rebassjs / rebass

:atom_symbol: React primitive UI components built with styled-system.
https://rebassjs.org
MIT License
7.94k stars 658 forks source link

@types/rebass and Emotion #755

Open thebuilder opened 4 years ago

thebuilder commented 4 years ago

Hey, wanted to get a discussion going about this.

With the switch from styled-components to emotion as the default css-in-js in version 4.0, I think it would make sense to have the DefinetlyTyped typings follow suit.

Right now the types have been updated to match Rebass 4.0 - But, they are using styled-components as the base. This works for the most part, except for css prop, which conflicts with the Emotion definition. Sure you might mostly be using the sx prop for styling Rebass, but it will result in an error if you try to create a component that composes the BoxProps.

// This causes a TypeScript error when using Emotion
type Props = BoxProps & {
 customProp: string
}

Basically the problem is this definition:

export interface BaseProps extends React.RefAttributes<any> {
    as?: React.ElementType;
    css?:
        | StyledComponents.CSSObject
        | StyledComponents.FlattenSimpleInterpolation
        | string;
}

It should look like this when using Emotion:

export interface BaseProps extends React.RefAttributes<any> {
    as?: React.ElementType;
    css?: InterpolationWithTheme<any>
}

I'm not 100% sure of the best way to handle this in DefinetlyTyped, but I think it would make sense to have them split:

I've been trying to get it solved in this pull request but surprisingly hard to get the build to pass. I might just try again in a new branch. I've created a local copy of the typings, that are working fine on the project i'm working on.

See also #664 which is caused by this issue.

ubbe-xyz commented 4 years ago

TS doesn't seem to be able to read the types when using rebass/styled-components ?

error TS7016: Could not find a declaration file for module 'rebass/styled-components'. '.../node_modules/rebass/styled-components/index.js' implicitly has an 'any' type.

Try `npm install @types/rebass` if it exists or add a new declaration (.d.ts) file containing `declare module 'rebass/styled-components';`

I have @types/rebass installed πŸ™‡πŸ»β€β™‚οΈ

thebuilder commented 4 years ago

Right - all the more reason to have it switched to Emotion then. :)

ubbe-xyz commented 4 years ago

I could override the error above by pointing TS to the declaration file:

// tsconfig.json
{
  ...,
  "paths": {
    "rebass/styled-components": ["node_modules/@types/rebass"]
  }
}

Not ideal but it kinda saved the day. I'll keep watching  πŸ‘€ this issue and consider find time to fix the types on DefinitivelyTyped πŸ‘πŸ»

lednhatkhanh commented 4 years ago

Hello, any updates on this?

russellr922 commented 4 years ago

Having same issue using Rebass with TS and Emotion. As soon as anything is imported from '@emotion/core' TS compiling breaks. Getting errors like this when rendering Rebass components:

Type 'FlattenSimpleInterpolation' is not assignable to type 'ObjectInterpolation<undefined>'.

russellr922 commented 4 years ago

For anyone else needing to resolve this immediately, put a rebass.overrides.ts file in the src directory with the code below, add any other Prop interfaces from Rebass you may need.:


import { InterpolationWithTheme } from '@emotion/core'

declare module "rebass" {
  interface FlexProps {
    as?: React.ElementType;
    css?: InterpolationWithTheme<any>;
  }
  interface BoxProps {
    as?: React.ElementType;
    css?: InterpolationWithTheme<any>;
  }
  interface TextProps {
    as?: React.ElementType;
    css?: InterpolationWithTheme<any>;
  }
}

declare module 'react' {
  interface DOMAttributes<T> {
    css?: InterpolationWithTheme<any>;
  }
}

declare global {
  namespace JSX {
    interface IntrinsicAttributes {
      css?: InterpolationWithTheme<any>;
    }
  }
}
matt-koevort commented 4 years ago

For anyone else needing to resolve this immediately, put a rebass.overrides.ts file in the src directory with the code below, add any other Prop interfaces from Rebass you may need.:

import { InterpolationWithTheme } from '@emotion/core'

declare module "rebass" {
  interface FlexProps {
    as?: React.ElementType;
    css?: InterpolationWithTheme<any>;
  }
  interface BoxProps {
    as?: React.ElementType;
    css?: InterpolationWithTheme<any>;
  }
  interface TextProps {
    as?: React.ElementType;
    css?: InterpolationWithTheme<any>;
  }
}

declare module 'react' {
  interface DOMAttributes<T> {
    css?: InterpolationWithTheme<any>;
  }
}

declare global {
  namespace JSX {
    interface IntrinsicAttributes {
      css?: InterpolationWithTheme<any>;
    }
  }
}

The above is a great workaround, but for our use case we need it to be fairly open ended, so that we wouldn't need to keep adding to the override type definition as and when we require the use of more Rebass props.

Samueldhardy commented 4 years ago

+1

euirim commented 4 years ago

I think this more general solution based on the code in the post by @russellr86 works without needing to add additional props manually:

import { InterpolationWithTheme } from '@emotion/core';
import {
  BoxProps as BoxP,
  ButtonProps as ButtonP,
  FlexProps as FlexP,
  LinkProps as LinkP,
  TextProps as TextP,
} from 'rebass';
import {
  FormProps as FormP,
  InputProps as InputP,
  LabelProps as LabelP,
} from '@rebass/forms';

declare module 'rebass' {
  interface BoxProps extends BoxP {
    css?: InterpolationWithTheme<any>;
  }
  interface ButtonProps extends ButtonP {
    css?: InterpolationWithTheme<any>;
  }
  interface FlexProps extends FlexP {
    css?: InterpolationWithTheme<any>;
  }
  interface LinkProps extends LinkP {
    css?: InterpolationWithTheme<any>;
  }
  interface TextProps extends TextP {
    css?: InterpolationWithTheme<any>;
  }
}

/* Required only if @rebass/forms is used */
declare module '@rebass/forms' {
  interface FormProps extends FormP {
    css?: InterpolationWithTheme<any>;
  }
  interface InputProps extends InputP {
    css?: InterpolationWithTheme<any>;
  }
  interface LabelProps extends LabelP {
    css?: InterpolationWithTheme<any>;
  }
}

Someone else might be able to come up with stricter type overrides.