Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

as prop of styled components in TypeScript #1137

Closed
felixjung opened this issue Dec 28, 2018 · 18 comments
Closed

as prop of styled components in TypeScript #1137

felixjung opened this issue Dec 28, 2018 · 18 comments
Milestone

Comments

@felixjung
Copy link
Contributor

  • emotion version: 10.0.5
  • react version: 16.6.3

Relevant code:

// Custom styled function that is typed with my theme interface
import styled, { CreateStyled } from '@emotion/styled'

import { ITheme } from '../theme'

export default styled as CreateStyled<ITheme>

// Style function interface in a Util module
declare module 'Util' {
  import { css } from '@emotion/core'
  import { ITheme } from '../util/theme'

  type CssType = typeof css

  export interface IStyleFunction<P = {}> {
    ( arg0: { theme: ITheme } & P): ReturnType<CssType> | false | null
  }
}

// Component code
type HeadingProps = {
  size?: FontSizes
}

const baseStyles: IStyleFunction<HeadingProps> = ({ theme }) => css`
  font-family: ${theme.fonts.heading};
`

const sizeStyles: IStyleFunction<HeadingProps> = ({
  theme,
  size = 'regular',
}) => {
  const [defaultSize, smallBreakPoint] = fontSizes[size]

  return css`
    font-size: ${theme.fontSizes[defaultSize]};

    ${theme.mq[0]} {
      font-size: ${theme.fontSizes[smallBreakPoint]};
    }
  `
}

const Heading = styled.h3<HeadingProps>(baseStyles, sizeStyles)

// Using the component
<Heading as="h5" size="tiny">
  This is an important heading
</Heading>

What you did:

  • Set up a Next js project with Typescript in strict mode
  • Use Emotion 10
  • Using a customized styled function
  • Using the ThemeProvider
  • Create a styled component and pass the component props as ExtraProps to the styled function
  • When using the styled component pass the as prop from Emotion 10 to change the element being used.

What happened:

Typescript complains about the as prop not existing on the styled component

screenshot 2018-12-28 at 10 56 05

Reproduction:

I've created a code sandbox for this, but I don't think the setup there properly reflects mine. Since you can't seem to customize the tsconfig in the default Typescript + React starter, I don't know what else to do. In any case code sandbox does not show any typescript errors.

https://codesandbox.io/s/mzyzm524lj

Problem description:

I would like to not get compiler warnings about the as prop. If I add as to my component's ExtraProps (in the above example the HeadingProps), the compiler stops complaining.

Thanks a lot for the help. I love emotion and I've been using it for about a year now. Just new to the whole TypeScript thing. 😅

@Ailrun
Copy link
Member

Ailrun commented Jan 27, 2019

I cannot find a simple way that works with native DOM components and React components.
If you have a proper way to support as props, please feel free to send a PR!

@felixjung
Copy link
Contributor Author

Thanks for looking into this!

@SavePointSam
Copy link
Contributor

just hit the same problem myself :(

@peduarte
Copy link

Same here 😄

@brandonkal
Copy link

Ran into this as well... Looks like withComponent works alright, so perhaps there is a way to use the logic there.

@Andarist
Copy link
Member

Andarist commented Nov 4, 2019

After tinkering with this myself and consulting other people - I don't think as can be strongly typed. I have to close this as non-actionable and we have to consider this a limitation of TS+emotion. Unless of course somebody figures it out and prepares a PR for this.

@Andarist Andarist closed this as completed Nov 4, 2019
@slavikdenis
Copy link

@Andarist what about as?: React.ElementType; ? Thats how it's typed in reflexbox typings.

See: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/reflexbox/index.d.ts#L24

@brandonkal
Copy link

I don't use emotion anymore, but if it does not have the as prop as an optional parameter it should be done for all emotion components.

The other issue (which is what I assume Andarist is referring to) that can't be solved now is getting TS to change the type signature based on what is specified in the as prop.

@quantizor
Copy link
Contributor

@Andarist would love to get this reopened and implement @slavikdenis's suggestion

@Andarist
Copy link
Member

This wouldn't be type-safe, but I guess we can just put it onto type system not being flexible enough to support this dynamic pattern. cc @JakeGinnivan thoughts on enabling this simplistic type for as prop?

@JakeGinnivan
Copy link
Contributor

The as prop should have a type so it can be used. I just don't think we want to go near the changing prop types based on the type of as. as?: React.ElementType; seems reasonable. Even as?: React.ElementType | keyof JSX.IntrinsicElements

@connor-baer
Copy link
Contributor

Has this been resolved in the upcoming v11? Otherwise, I'd like to take a stab at it — any pointers to relevant files would be appreciated :)

@JakeGinnivan
Copy link
Contributor

I don't think it has been done.

In packages/styled-base/types/index.d.ts, add the as prop to StyledComponent. I think as?: React.ElementType | keyof JSX.IntrinsicElements should be enough as mentioned above.

Then in packages/styled-base/types/tests.tsx, write a component which consumes the prop to just make sure it all works as expected.

@connor-baer
Copy link
Contributor

Thanks for the hints @JakeGinnivan! Much appreciated.

Unfortunately, the types have changed quite a bit in the next branch for v11. I've tried to make the changes there and while the test works, I'm not sure whether it's the correct approach. Here's the draft PR: #1874.

Would you consider this a breaking change? Should I backport this to v10?

@samuelcastro
Copy link

I'm facing the same issue, the way I'm fixing it for now is just adding a as?: React.ElementType | keyof JSX.IntrinsicElements directly in my components.

Any update whether or not this is going to be natively supported?

@connor-baer
Copy link
Contributor

There’s a pending PR (#1874) to add it for Emotion 11. I’d be happy to backport it to 10 as well.

@flo-sch
Copy link

flo-sch commented Jun 9, 2020

Using emotion v10 as well, the type suggested above seems to work for me locally:

import React from 'react';
import { Link } from 'react-router-dom';
import styled from '@emotion/styled';

interface StyledLinkProps {
  as?: React.ElementType;
}

const StyledLink = styled.a<StyledLinkProps>`
  /* ... */
`;

const Nav = () => (
  <StyledLink as={(props) => <Link {...props} to="/somewhere" />}>
    Go somewhere
  </StyledLink>
);

@Andarist
Copy link
Member

Andarist commented Jul 9, 2020

Just merged this into next branch so it will be available in the next v11 release. There are no plans to backport this change to v10 though. Hope you understand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests