-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Resolve type incompatibilities with legacy type #722
Conversation
bc6a2a5
to
91e43e8
Compare
@@ -131,9 +131,9 @@ const StyledTag1 = createStyled('label')` | |||
const StyledCompWithButton = StyledClassComp0.withComponent('button'); | |||
const StyledCompWithFunComp2 = StyledFunComp0.withComponent(TestFunComp1); | |||
|
|||
<StyledCompWithButton />; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we keep this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tkh44 This is the problem what I mentioned in #721.
We cannot distinguish props that is used to make style or props that is passed to internal component without type parameter, so there are only two ways, considering them as props for style, or considering them as a internal-only props.
#721, @mvestergaard said complaint about second choice (my original choice), so I changed this into first one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tkh44 Could you discuss this with @mvestergaard ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be naive, but wouldn't this make that use case work?
withComponent<T extends keyof JSX.IntrinsicElements>(
tag: T,
options?: StyledOptions,
): StyledOtherComponent<JSX.IntrinsicElements[T], JSX.IntrinsicElements[T], Theme>;
Basically force Props to be the same as InnerProps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mvestergaard The problem occurs in original styles (styles those came from StyledComponent
before withComponent
is applied). Original styles already depend on old Props
, so we cannot change them freely. If we do so, it will break the type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyway, I'm not sure what i can discuss with @tkh44
I've spoken my case on #721 already. The gist is basically, that a breaking change was made. Something that worked just fine before, now requires explicit typing.
In my head this is wrong, but I can't force you guys to change it based on that. So you need to decide internally how you intend the library to be used.
The most common use case should be prioritized.
My personal opinion is that restyling components:
const Restyled = styled(OtherComponent)``
is a more common use case than switching the internal component
const SomeStyledThing = styled.div``;
const SomeOtherStyledThing = SomeStyledThing.withComponent('span');
But @Ailrun believes it's the other way around
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mvestergaard Thank you for your summary!
What I mean with 'discussion' is about 'Which one is more common and preferable use case'.
How about your opinion, @tkh44?
@tkh44 Why did codecov coverage decrease? Does codecov coverage include .ts files? |
@Ailrun It said that because this branch was out of date with master |
docs/typescript.md
Outdated
const Image0 = styled('div')` | ||
width: ${(props: ImageProps) => props.width}; | ||
const Image0 = styled<ImageProps, 'div'>('div')` | ||
width: ${(props) => props.width}; | ||
background: url(${(props: ImageProps) => props.src}) center center; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should props: ImageProps
be changed to props
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mitchellhamilton Oh, thanks! I will change it.
docs/typescript.md
Outdated
background: url(${(props: ImageProps) => props.src}) center center; | ||
background-size: contain; | ||
` | ||
|
||
// Or with object styles | ||
|
||
const Image1 = styled('div')({ | ||
const Image1 = styled<ImageProps, 'div'>('div')({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain why people would want to do this over the generic way below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mitchellhamilton Actually, I don't think this is the preferable way.... I add this because of compatibilities. If you think 'Document only for compatibility reason is not needed', I will change this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, in case of string style, as you already know, situation is little different, since we cannot use generic template string with TS < 2.9, and even with TS >= 2.9, vscode-styled-components
does not support syntax highlight.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you move it below the one that people should use and add a comment about it only being there for compatibility and that people shouldn’t write new code with it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I will move this and add a comment.
docs/typescript.md
Outdated
@@ -119,7 +133,8 @@ const Image1 = styled('div')<ImageProps>({ | |||
})); | |||
``` | |||
|
|||
* The generic type version only works with object styles due to https://github.com/Microsoft/TypeScript/issues/11947. | |||
* The generic function version only works with object styles in TS <= 2.8 due to https://github.com/Microsoft/TypeScript/issues/11947. | |||
* If you use TS > 2.9, generic function will works with string styles too, but it will break VSCode syntax highlighting. See https://github.com/emotion-js/emotion/issues/721#issuecomment-396954993 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you replace generic function will works with string styles too
with generic functions will work with string styles too
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, my mistake! I will fix it
<div className={className}>{label}</div> | ||
) | ||
|
||
type StyledComponentProps = { | ||
bgColor: string | ||
}; | ||
|
||
const StyledComponent0 = styled(Component)` | ||
const StyledComponent00 = styled<StyledComponentProps, ComponentProps0>(Component)` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is a prop type passed here but in other places div
is passed (shouldn't this be a component type)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mitchellhamilton This is for compatibilities, and, sadly, old typings did so...
emotion/packages/react-emotion/types/index.d.ts
Lines 101 to 108 in 24fa6ed
<Props, Tag extends keyof JSX.IntrinsicElements>( | |
tag: Tag, | |
options?: Options, | |
// tslint:disable-next-line:no-unnecessary-generics | |
): CreateStyled<Props, Theme, ElementProps<Tag>>; | |
// overload for component | |
<Props, CustomProps>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the preferred way to do it now?
If not, could you add a note saying that it's only for compatibility and tell people what they should use now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mitchellhamilton
I notice that this is the preferred way.... There is no walkaround for this case, to be compatible with old one.
I will try better typing at upcoming emotion@10
docs/typescript.md
Outdated
const App = () => <Link href="#">Click me</Link> | ||
|
||
// No errors! | ||
``` | ||
|
||
When you use `withComponent`, you should explicitly provide the type of props used to make style. If you don't, TS will think all props for `Text` are used to make style, and request user to give all those props when using the result component of `withComponent`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you elaborate on TS will think all props for Text are used to make style
, I don't really understand what it means.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mitchellhamilton I mean TS will consider all props for Text as props to make style
. Is this sentence more sensible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I still don’t understand it. I don’t understand what you mean by as props to make style
. how do the props make
the style?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mitchellhamilton I mean something like following
(props) => ({
backgroundColor: props.bgColor
})
(bgColor
props is used to make style)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example,
-
When you have
Text
component that requiresbgColor
,content
, you can make following styled component.const StyledText = styled(Text)({ fontSize: '50px', }, props => ({ backgroundColor: props.bgColor, }));
In this
StyledText
,bgColor
prop is used to make style, butcontent
prop isn't. -
Now, suppose that you want to make a new styled component with different inner (base?) component
Link
, by usingwithComponent
. Suppose thatLink
requires onlytarget
as a prop. You probably do something like following.const StyledLink = StyledText.withComponent(Link);
-
However, the problem occurs in TypeScript. TypeScript cannot determine which props are used to make style, i.e., it cannot find the fact that
bgColor
is the only prop used in style ofStyledText
. Therefore it should do one of following things.- Suppose that all props are used in style
- Suppose that no props are used in style
However, if you choose first one, TypeScript request to use
bgColor
,content
,target
toStyledLink
, even ifLink
does not requirecontent
. This is why I choose second one, but legacy typing choose first one and after I changed this, some users complain about 'Why are there no props type inference?'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do styled-components and glamorous do for these cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mitchellhamilton Glamorous does something like second choice (not exactly same, but similar), and styled-components
has something similar with first one, but with wrong typed withComponent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
props used to make style
Maybe try:
The prop types used to construct the resulting style definition of
withComponent
should be explicitly provided to avoid TypeScript compiler errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tkh44 I just changed the docs. Could you check this again?
@@ -50,15 +50,15 @@ const TestFunComp1 = (props: TestFunProps1) => ( | |||
</div> | |||
); | |||
|
|||
const StyledClassComp0 = createStyled(TestClassComp)({ | |||
const StyledClassComp0 = createStyled(TestClassComp)<{}>({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was <{}>
added?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mitchellhamilton Now, all props of component that passed to createStyled
(or styled
) considered as props for styling, so if you want to use withComponent
and don't use any props of passed component (or use only some of them), you should restrict props type by providing type parameter.
Ref: #722 (comment)
@mitchellhamilton Could you check this again? |
I think the main hold up is around the documentation. Once we get this worked out I feel like it should be good to go. |
`; | ||
|
||
const OtherLink = StyledText.withComponent('a'); | ||
|
||
const App = () => <Link href="#">Click me</Link> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should Link
be OtherLink
in this example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also have Link
... Do I need to use all these components (Link
, OtherLink
, ...)?
@Ailrun could you fix the conflicts? |
The compatibility is about old type & styled-component
fd2af86
to
8f36c4f
Compare
@mitchellhamilton Sorry for delay. I just came back from my vacation. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions. |
What: Enhance type inference for following case.
and add type parameter for compatibilities with old type
Why: #721.
How: By adding default type parameter
Checklist:
Resolves #721.