-
-
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
Add stricter ReactInterpolation type #2297
base: main
Are you sure you want to change the base?
Conversation
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 5e104f2:
|
packages/react/types/index.d.ts
Outdated
type ReactArrayInterpolation<Props> = Array<ReactInterpolation<Props>> | ||
|
||
interface ReactFunctionInterpolation<Props> { | ||
(props: Props): ReactInterpolation<Props> | ||
} | ||
|
||
export type ReactInterpolation<Props> = | ||
| ReactInterpolationPrimitive | ||
| ReactArrayInterpolation<Props> | ||
| ReactFunctionInterpolation<Props> | ||
|
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.
Can we call the type parameter Theme
since that's what it is 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.
Ive also used it for one of the styled overloads where it is equivalent to Props
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 type doesn't seem right for styled, e.g. styled.div('display:flex;')
is valid.
Also, this change isn't right for the css prop either since css={['display:flex;']}
is valid. The only thing that's wrong about the current types is that string
isn't allowed at the root of the css prop.
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.
Well, sure - the question is if we want to support this. Types don't always have to match the runtime reality fully. It feels better to guide users to better patterns if they are using a type checker.
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 ok, I must have missed these style string patterns in the doc because I based my suggestion on what I saw demonstrated. If we really want to allow this form of string we can go ultra geeky and use template literal types but it seems overengineering at this point.
To be honest, the one thing I'm really interested in is for TS to catch me (and anyone starting with the css
property) when I'm worngly assigning a class name to the css
property.
So I'd agree with @Andarist here. It's about nudging and guiding to use some patterns rather that fully typing everything that could work but it's up to you folks.
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.
Sure, let's change this for the css prop. Can you revert the change for @emotion/styled though since having @emotion/styled depend on a new thing from @emotion/react would be a breaking change since @emotion/styled has a peer dependency on @emotion/react? (also for styled, i believe we compile styles to styled.div('display: ', something, ';')
and making it so our types treat something that we compile to as invalid seems bad)
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've removed this from @emotion/styled
and also renamed Props to Theme since this will always be true right now.
This might be a user-facing change (some people might use Interpolation
type in their code) but I think this is OK if we make this a minor change. Tying major versioning to types (unless changes are really extreme) falls outside of the pragmatic semver for me. What's your opinion on this?
@@ -46,6 +46,24 @@ export function withEmotionCache<Props, RefType = any>( | |||
func: (props: Props, context: EmotionCache, ref: Ref<RefType>) => ReactNode | |||
): FC<Props & ClassAttributes<RefType>> | |||
|
|||
type ReactInterpolationPrimitive = |
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.
I think fundamentally what we mean is falsy or something that produce valid style information:
type ReactInterpolationPrimitive =
| Falsy
| SerializedStyles
| CSSObject
Falsy in TS can be expressed like that (note the ""
and false
instead of boolean
):
type Falsy = false | "" | 0 | null | undefined
Any other value would be probably the result of a programming mistake and would not be interpreted correctly by Emotion anyway, so we might as well catch them:
css={"my-custom-class"}
css={true}
whereas the following could be the intended result of a boolean shortcircuit conditional:
css={""}
css={false}
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.
Hah, interesting that with someString && somethingElse
TS actually computes the output as "" | typeof somethingElse
! TIL
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.
@Andarist yes this is pretty neat. From the quick test of my code base (a branch where I'm refactoring to use the css
property), these types already help me a lot in finding mistakes I made.
In your example, for res2
, I expected TS to be a little smarter with the ternary operator. I can't really understand what other value foo
can be in the right branch other then ""
🤷♂️..
So this case would generate a false negative, but to be fair I think this is a pattern that should be very rare when using Emotion. I can't really see what one would want to achieve with this where the shortcircuit conditional would be enough.
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.
In your example, for res2, I expected TS to be a little smarter with the ternary operator. I can't really understand what other value foo can be in the right branch other then "" 🤷♂️..
Yep, same - both ternary and &&
should really behave the same way. This was for illustration purposes - not that relevant for this PR really (I don't feel that it's a show-stopper or anything).
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.
FYI, after unsuccessfully trying to find the answer in TS repository, I just posted the question on SO
@Andarist did you need help with this? I'm quite keen to see it merged so tell me if I can do anything. |
@jraoult adding type tests and checking what happens with failed CI jobs (the ones on the CircleCI) would certainly help |
@Andarist I took some time today to work on this. I think I'm ready to push. How should I proceed? Can you give me write access to this branch? Should I create another PR? |
U can create a PR targeting this branch |
@jraoult @mitchellhamilton passing string prop is actually supported in the codebase: emotion/packages/react/src/emotion-element.js Lines 66 to 74 in 4d7efcb
I guess this was mainly to make the Emotion 9 -> Emotion 10 easier but this code has not been removed in Emotion 11. This logic probably kicks in when providing the |
Exactly, this is actually what got me into this rabbit hole initially 😉 During refactoring, I noticed one could still give the So my initial proposal for this typing was to make sure no undocumented pattern could be used and help people avoid the pitfall. |
fixes #2289