-
-
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
adding types for @emotion/native #1634
Conversation
🦋 Changeset is good to goLatest commit: 2f08db6 We got this. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
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 2f08db6:
|
a662cbc
to
4f8a984
Compare
Thank you for working on this! From what I can see those are based on emotion@10 typings - would you be willing to convert them to what we have currently on the next branch for |
@Andarist the types are based on the |
For example there are no equivalents for |
it's possible the naming is just confusing. Themeless just means that the |
I think this still interacts a little bit different with Theme. On Looking also for example at this: emotion/packages/styled/types/base.d.ts Lines 134 to 141 in ad77ed2
and in Theme shows up twice - one is optional (passed as ComponentProps) and one is required (passed as StyleProps). I guess this might be the difference linked to my first statement in this comment - you don't allow at the moment a theme prop which overrides context theme .
|
1a5c6b2
to
77de716
Compare
The conditional types were meant as an improvement to these types. i can completely remove the |
I would prefer to keep those types structured in the very same way as I'm not yet entirely sure, but it's also very likely that Theme will get reworked quite a bit (but not focus on this as part of this PR - unless you want to wait till we merge changes to |
ok, i reduced the types to just be analogies to the default |
That's fine - sharing probably would make them more complex than they need to be. Thanks for doing this! I'll probably merge this in over the weekend or shortly after that. |
Shall I move this out of draft? |
@patsissons yeah, you can do that. I'm in the middle of aligning those types just a little bit more to what we have in |
sure thing, let me know if you want me to make any other changes. |
I've pushed out my changes - the work is not 100% done yet though. I would highly appreciate your review on this one. From what I understand Unfortunately, types which I have used to create emotion/packages/native/types/base.d.ts Lines 14 to 18 in c3d48f9
I'm not sure what's the best way to work around this here. Any ideas? Other than that tests need some work - I haven't really touched them, so they are using a type that doesn't exist anymore. Would you be willing to work on making those tests work? |
packages/native/types/base.d.ts
Outdated
type ReactNative = typeof RN | ||
|
||
export type ReactNativeStyle = ReturnType<ReactNative['StyleSheet']['flatten']> | ||
export type ObjectInterpolation = RN.ViewStyle | RN.TextStyle | RN.ImageStyle |
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 union should be fine instead of the polymorphic version that was being used previously.
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.
Seems like it's hard for us to create strict typings for those if we want to have types similar to those for the web version. From what I understand this will indeed work somewhat OK, but will allow incorrect object styles to be set on a particular component (in example it will allow text styles to be used on a view component). To keep things simple, I would say it's OK. WDYT?
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'll take another pass to see if I can improve it, but I think that may not be avoidable
packages/native/types/base.d.ts
Outdated
shouldForwardProp?(propName: PropertyKey): boolean | ||
} | ||
|
||
export interface StyledWithComponent<ComponentProps extends {}> { |
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.
open to a better name for this
component: Component, | ||
options?: StyledOptions<ComponentPropsWithoutRef<Component>> | ||
): CreateStyledComponent< | ||
ComponentPropsWithoutRef<Component> & { theme?: Theme }, |
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 wasn't sure why the custom component variant is using an intersection for component props rather than specific props like the react native components are 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.
cc @JakeGinnivan, that was based on the types for @emotion/styled
e9a525d
to
1343b88
Compare
I see you have restructured typings a little bit. I'm not saying that those changes are bad, most of them are probably good - but also many of them could be considered rather cosmetic. I've intentionally written them like I've written them, so they could mirror what we have in for a web version. Truth to be told If you believe that some changes you have made are particularly good we could evaluate if they could be backported to |
Most of the cosmetic/name changes were to help me trace how the types were being expanded so I could ensure all types were being forwarded through properly. Removal of the |
1781c39
to
755ca6c
Compare
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.
hopefully these notes clear up some of the changes i made earlier. I'm going to rebase shortly to 🔥 the merge commit and cleanup the commit history.
packages/native/types/base.d.ts
Outdated
|
||
export interface FunctionInterpolation<MergedProps> { | ||
(mergedProps: MergedProps): Interpolation<MergedProps> | ||
} | ||
|
||
export type Interpolation<MergedProps = undefined> = | ||
export type Interpolation<MergedProps = unknown> = |
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.
unknown
is a more descriptive default for these MergedProps
than undefined
packages/native/types/base.d.ts
Outdated
export interface StyledWithComponent<ComponentProps extends {}> { | ||
withComponent< | ||
Component extends ComponentType<ComponentPropsWithoutRef<Component>> | ||
>( | ||
component: Component | ||
): StyledComponent<ComponentProps & ComponentPropsWithoutRef<Component>> | ||
withComponent<ComponentName extends ReactNativeComponentNames>( | ||
component: ReactNativeComponents[ComponentName] | ||
): StyledComponent<ComponentProps, ReactNativeComponentProps<ComponentName>> | ||
} |
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.
these withComponent
signatures were pulled out into their own interface so that we can use a type union below for StyledComponent
.
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.
wouldnt we be able to do the same without pulling out into its own interface?
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 you're right, we don't need this to be its own interface any more (i think it was useful before when i needed to use a union).
packages/native/types/base.d.ts
Outdated
): StyledComponent<ComponentProps, ReactNativeElements[Tag]> | ||
} | ||
> = ComponentType<ComponentProps & SpecificComponentProps> & | ||
StyledWithComponent<ComponentProps> |
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.
It doesn't make much sense to type StyledComponent
as an extension to a functional component. Technically it should be typed as a ForwardRefExoticComponent
(and more generally, NamedExoticComponent
). This might be a more appropriate choice (i'll give it a try in a moment).
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.
NamedExoticComponent
works appropriately here so i've gone with that choice.
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 makes sense, cc @JakeGinnivan - shouldn't we do the same for web types?
529c6ea
to
7a4a433
Compare
7a4a433
to
c2f6f6f
Compare
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 the interpolation types are now working with inference, I think that's about as far as I can go with the typings. LMK how you want to proceed from here (feel free to commit on top and adjust names or squash the branch at this point)
packages/native/types/base.d.ts
Outdated
export type ReactNativeStyleType<Props> = Props extends { | ||
style?: RN.StyleProp<infer StyleType> | ||
} | ||
? StyleType | ||
: ReactNativeStyle |
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 construct lets us extract the specific shape of a react-native
style prop, and support custom components too.
packages/native/types/base.d.ts
Outdated
): StyledComponent<ComponentProps, ReactNativeElements[Tag]> | ||
} | ||
> = ComponentType<ComponentProps & SpecificComponentProps> & | ||
StyledWithComponent<ComponentProps> |
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.
NamedExoticComponent
works appropriately here so i've gone with that choice.
packages/native/types/base.d.ts
Outdated
ComponentProps extends {}, | ||
SpecificComponentProps extends {} = {}, | ||
StyleProps extends {} = {}, | ||
StyleType = ReactNativeStyle |
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 found that the StyleType
, while properly inferred, was allowing an ImageStyle
to be used as a TextStyle
but not the other way around. Feels like a bug in the TypeScript inference logic because i couldn't see a relation between the two, but i couldn't get a better answer as to why (i left some comments in the test file).
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.
type True = RN.ImageStyle extends RN.TextStyle ? true : false
type False = RN.TextStyle extends RN.ImageStyle ? true : false
Seems like ImageStyle is a subtype of TextStyle
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.
haha interesting, i'm not going to dig further since it's already difficult to understand why that may be.
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.
Similarly on web input is a subtype of div. It's not like those types form such hierarchy, but rather that div is so basic, that it has no special props associated with it and everything that can be used on it can be used on input as well (+ input has some specific props for it). And because TS type system is structural rather than nominal this forms implicit supertype-subtype relationship.
ComponentPropsWithoutRef<Component> & { theme?: Theme }, | ||
{}, | ||
{ theme: Theme }, | ||
ReactNativeStyleType<ComponentPropsWithoutRef<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.
as long as the custom component defines a style?: StyleProp<T>
, the T
will get inferred and applied to the template interpolation types.
{ theme?: Theme }, | ||
ReactNativeComponentProps<ComponentName>, | ||
{ theme: Theme }, | ||
ReactNativeStyleType<ReactNativeComponentProps<ComponentName>> |
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.
all styled react-native
components should now be strongly typed against their specific style prop shape.
I ran into some composition issues testing out these types with a more complicated setup. The |
329f542
to
b7bea71
Compare
@patsissons sorry that I haven't yet reviewed this, I hope to do it this week |
|
||
export function css<StyleType extends ReactNativeStyle = ReactNativeStyle>( | ||
template: TemplateStringsArray, | ||
...args: Array<Interpolation> |
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'm not sure if this should use Interpolation
. For instance, it doesn't make sense for css
to accept functions - for the web we've split this into two similar, but separate, Interpolation and CSSInterpolation. I feel like the same should be done 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.
makes sense to me, i can add those suggestions in pretty quickly
@patsissons sorry that I haven't reviewed this sooner but had plenty on my plate. Let me know if you are still interested in working on this one (not much left to do). |
No worries, i'm in the same boat. I've addressed your review suggestions and things looks reasonable to me right now. My mind isn't as deep into these types as it was a few weeks ago so maybe spot check the changes i made. Otherwise i think i'm satisfied with these types for an MVP release, i'll try and pull them into a project later today to give them a broader test. |
StyleType extends ReactNativeStyle = ReactNativeStyle | ||
> extends Array<CSSInterpolation<MergedProps, StyleType>> {} | ||
|
||
export type CSSInterpolation< |
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 don't think that MergedProps
props are actually used anyhow inside CSSInterpolation, it only seems to be passed around, but not utilized. This is good though - with css
you don't get access to any props at all. This means though that we can just drop this typeparam 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.
yup, absolutely. a bit of blind refactoring lands you with useless type params 😄
e8a542b
to
cf8cb89
Compare
@Andarist are we good to ship? 🚢 |
* adding types for react native * fixing styled component types * removing condition type inference for existence of a theme * Move @emotion/native TS types closer to what we have for @emotion/styled * some minor adjustments to the types * updating interpolation types to support inferred style type * addressing some deficiencies * Use Theme interface from @emotion/core in @emotion/native * adding review suggestions * Add changeset
What:
adds some types for
@emotion/native
Why:
How:
Checklist: