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

Typescript definitions for @emotion/native #839

Closed
yonatanmn opened this issue Sep 6, 2018 · 29 comments
Closed

Typescript definitions for @emotion/native #839

yonatanmn opened this issue Sep 6, 2018 · 29 comments

Comments

@yonatanmn
Copy link

Hey,
I'm building a RN app and wish to use @emotion/native, but since I'm using TS I'm having problems declaring correct typings.

@krzysztofzuraw
Copy link
Contributor

I can take look into it - is there anything before I jump into declaring types?

@frontendwizard
Copy link

@krzysztofzuraw Are you still on to this? I'm interested in this too.

@davidyeiser
Copy link

I'd be happy to help with this. (Though I've never done anything like it before.)

@patsissons
Copy link
Contributor

patsissons commented Jun 9, 2019

I was playing around with emotion in react-native today, and ended up writing some brief but fairly accurate typings for the native package. I'm not confident i will have time to author a PR for this any time soon, so i'll post the effort on this issue in case it helps anyone else. Note that I added @emotion/core and @emotion/styled-base to devDependencies so i can reuse their existing type definitions.

The strategy here was to reuse as much existing typing as i could. This was easy for the css export since it's effectively the same for react-native. The styled export is a bit more complicated. I took the list of bound components and turned it into a giant string literal union. Then i created a new mapped type for mapping component names into styled components and joined that with the CreateStyled types from styled-base. This should cover nearly every use case for react-native as far as i can tell.

// global.d.ts

declare module '@emotion/native' {
  import css from '@emotion/css';
  import {
    CreateStyled,
    CreateStyledComponentExtrinsic,
  } from '@emotion/styled-base';
  import React from 'react';
  import ReactNative from 'react-native';

  type StyledReactNativeComponents =
    | 'ActivityIndicator'
    | 'ActivityIndicatorIOS'
    | 'ART'
    | 'Button'
    | 'DatePickerIOS'
    | 'DrawerLayoutAndroid'
    | 'Image'
    | 'ImageBackground'
    | 'ImageEditor'
    | 'ImageStore'
    | 'KeyboardAvoidingView'
    | 'ListView'
    | 'MapView'
    | 'Modal'
    | 'NavigatorIOS'
    | 'Picker'
    | 'PickerIOS'
    | 'ProgressBarAndroid'
    | 'ProgressViewIOS'
    | 'ScrollView'
    | 'SegmentedControlIOS'
    | 'Slider'
    | 'SliderIOS'
    | 'SnapshotViewIOS'
    | 'Switch'
    | 'RecyclerViewBackedScrollView'
    | 'RefreshControl'
    | 'SafeAreaView'
    | 'StatusBar'
    | 'SwipeableListView'
    | 'SwitchAndroid'
    | 'SwitchIOS'
    | 'TabBarIOS'
    | 'Text'
    | 'TextInput'
    | 'ToastAndroid'
    | 'ToolbarAndroid'
    | 'Touchable'
    | 'TouchableHighlight'
    | 'TouchableNativeFeedback'
    | 'TouchableOpacity'
    | 'TouchableWithoutFeedback'
    | 'View'
    | 'ViewPagerAndroid'
    | 'WebView'
    | 'FlatList'
    | 'SectionList'
    | 'VirtualizedList';

  type StyledComponentsForReactNative<
    T extends keyof typeof ReactNative,
    ExtraProps,
    Theme
  > = {
    [K in T]: CreateStyledComponentExtrinsic<
      typeof ReactNative[K],
      ExtraProps,
      Theme
    >;
  };

  export interface Styled<Theme extends object = any, ExtraProps = {}>
    extends CreateStyled<Theme>,
      StyledComponentsForReactNative<
        StyledReactNativeComponents,
        ExtraProps,
        Theme
      > {}

  export {css};

  const styled: Styled;
  export default styled;
}

updated with the changes below

@kevinwolfcr
Copy link

@patsissons thanks, that did fixed the issue of styled.* not autocompleting. Do you have any idea on how to make it work with theming? (this is the solution when working with react web).

I tried doing this but did not had success:

import styled, { Styled } from '@emotion/native'
import { Theme } from '../config/types'

export default styled as Styled<Theme>

@patsissons
Copy link
Contributor

I'll have a look tomorrow

@kevinwolfcr
Copy link

Thanks @patsissons. Any suggestion?

@patsissons
Copy link
Contributor

sorry for the delay. here are some updates to fix the issue (plus allow for ExtraProps support).

  type StyledComponentsForReactNative<
    T extends keyof typeof ReactNative,
    ExtraProps,
    Theme
  > = {
    [K in T]: CreateStyledComponentExtrinsic<
      typeof ReactNative[K],
      ExtraProps,
      Theme
    >;
  };

  export interface Styled<Theme extends object = any, ExtraProps = {}>
    extends CreateStyled<Theme>,
      StyledComponentsForReactNative<
        StyledReactNativeComponents,
        ExtraProps,
        Theme
      > {}

short demo of it working

import styledNative, {Styled} from '@emotion/native';

type Theme = {
  color: {
    primary: string;
    positive: string;
    negative: string;
  };
};

const styled = styledNative as Styled<Theme, {foo: string}>;

export const PositiveView = styled.View`
  background-color: ${({theme}) => theme.color.positive}; // ${({foo}) => foo}
`;

@kevinwolfcr
Copy link

Works awesome man! Thanks for helping.

@aecorredor
Copy link

hey guys, how are you adding the types to your project? I keep getting this error:

Invalid module name in augmentation. Module '@emotion/native' resolves to an untyped module at '...mypath.../node_modules/@emotion/native/dist/native.cjs.js', which cannot be augmented.

I'm adding them in src/typings/global.d.ts.

Thanks!

@aecorredor
Copy link

aecorredor commented Aug 3, 2019

never mind, my issue was that I'm using a monorepo and ran into some problems with emotion getting hoisted. Had to add @emotion to the nohoist option.

@aecorredor
Copy link

Ok, so that didn't solve my actual problem with adding the custom definitions...😔

@imcvampire
Copy link

Hi @patsissons, I want to thank you for your definition.

After adding your code to my codebase, I face a problem. Can you help me to debug it?

Screen Shot 2019-09-12 at 10 44 31 PM

@damathryx
Copy link

damathryx commented Sep 22, 2019

@patsissons, how would you handle with

SerializedStyles' is not assignable to type 'StyleProp'.

when using css on custom style attributes like contentContainerStyle={css``}, slideStyle

@patsissons
Copy link
Contributor

@damathryx not much you can do here, the two types are not compatible as defined and there is no real way to infer structure from the seralized form. you can either type cast down to {} or you can redefine the css export to return {} (if you never care about serialized properties). For the latter strategy you can replace export {css} with

export function css(
  template: TemplateStringsArray,
  ...args: Array<Interpolation>
): {};
export function css(...args: Array<Interpolation>): {};

Alternatively, I have been using this utility and type construct to share both types.

// utilities.ts
import {Interpolation, SerializedStyles} from '@emotion/serialize';
import {css} from '@emotion/native';

type EmotionStyles = Record<string, SerializedStyles>;

export type ReactNativeStyles<T extends EmotionStyles> = {
  [K in keyof T]: {};
};

export function cssRN(
  template: TemplateStringsArray,
  ...args: Array<Interpolation>
): {};
export function cssRN(...args: Array<Interpolation>): {};
export function cssRN(...args: any[]) {
  return css(args);
}

export function asReactNativeStyles<T extends EmotionStyles>(
  serialized: T,
): ReactNativeStyles<T> & {serialized: EmotionStyles} {
  return {
    serialized,
    ...serialized,
  };
}

now you can access the serialized styles if you need to, and otherwise just use styles.container for example when applying to a react native style prop.

import {css} from '@emotion/native';
import {asReactNativeStyles} from './utilities';

export const styles = asReactNativeStyles({
  container: css`
    flex: 1;
  `,
  centered: css`
    justify-content: center;
    align-items: center;
  `,
  // ...
});

cssRN is just a handy helper to do inline css expansions

@Andarist
Copy link
Member

Andarist commented Nov 12, 2019

@patsissons would you maybe be interested in helping to prepare a PR with official typings for those packages based on what we currently have on the next branch?

@patsissons
Copy link
Contributor

@Andarist i created a branch and added some (cleaned up) types to it. also turns out that all of that css stuff is unnecessary since under the hood react-native calls to css just invoke Stylesheet.flatten so i've adjusted the types to reflect that. Shall i fork or contribute directly?

for those not on the next release, here is the updated css type.

  export function css(
    template: TemplateStringsArray,
    ...args: Array<Interpolation>
  ): ReturnType<typeof StyleSheet.flatten>;
  export function css(
    ...args: Array<Interpolation>
  ): ReturnType<typeof StyleSheet.flatten>;

@patsissons
Copy link
Contributor

@imcvampire i cleaned up the types that i had originally posted with a better mapping pattern, this may solve or at least give you more context why there is an error. Below are the types that i have changed.

 type StyledReactNativeComponents = Pick<
    typeof ReactNative,
    | 'ActivityIndicator'
    | 'ActivityIndicatorIOS'
    | 'ART'
    | 'Button'
    | 'DatePickerIOS'
    | 'DrawerLayoutAndroid'
    | 'Image'
    | 'ImageBackground'
    | 'ImageEditor'
    | 'ImageStore'
    | 'KeyboardAvoidingView'
    | 'ListView'
    // does not exist?
    // | 'MapView'
    | 'Modal'
    | 'NavigatorIOS'
    | 'Picker'
    | 'PickerIOS'
    | 'ProgressBarAndroid'
    | 'ProgressViewIOS'
    | 'ScrollView'
    | 'SegmentedControlIOS'
    | 'Slider'
    // type alias to Slider
    // | 'SliderIOS'
    | 'SnapshotViewIOS'
    | 'Switch'
    | 'RecyclerViewBackedScrollView'
    | 'RefreshControl'
    | 'SafeAreaView'
    | 'StatusBar'
    | 'SwipeableListView'
    // does not exist?
    // | 'SwitchAndroid'
    | 'SwitchIOS'
    | 'TabBarIOS'
    | 'Text'
    | 'TextInput'
    | 'ToastAndroid'
    | 'ToolbarAndroid'
    // just an interface
    // | 'Touchable'
    | 'TouchableHighlight'
    | 'TouchableNativeFeedback'
    | 'TouchableOpacity'
    | 'TouchableWithoutFeedback'
    | 'View'
    | 'ViewPagerAndroid'
    | 'WebView'
    | 'FlatList'
    | 'SectionList'
    // migrated to FlatList?
    // | 'VirtualizedList'
  >;

  type ReactNativeStyledComponents<
    Theme extends object = any,
    ExtraProps = {}
  > = {
    [K in keyof StyledReactNativeComponents]: typeof ReactNative[K] extends ComponentType
      ? CreateStyledComponentExtrinsic<typeof ReactNative[K], ExtraProps, Theme>
      : never;
  };

  export interface Styled<Theme extends object = any, ExtraProps = {}>
    extends CreateStyled<Theme>,
      ReactNativeStyledComponents<Theme, ExtraProps> {}

@imcvampire
Copy link

@patsissons Thank you! It works great for me!

One more request, do you have any correct typing for css function?

Thank you!

@Andarist
Copy link
Member

@Andarist i created a branch and added some (cleaned up) types to it. also turns out that all of that css stuff is unnecessary since under the hood react-native calls to css just invoke Stylesheet.flatten so i've adjusted the types to reflect that. Shall i fork or contribute directly?

That would be sweet - just fork from next branch and send us a PR. We'd love to get this merged in. The types should be written fairly in the same manner as refactored typings for @emotion/styled (available on next branch) - this should make maintenance and interoperability easier.

@Andarist
Copy link
Member

Andarist commented Dec 16, 2019

A PR implementing this ( #1634 ) has just been merged into next branch. This will be a part of the upcoming v11 release.

@aecorredor
Copy link

Nice job on adding this 🎉 is there an estimated date for a stable release of v11?

@andrewphillipo
Copy link

Yes I'd love to hear about 11. Might just switch to it now for TS support? expo install @emotion/core@next @emotion/native@next ?

@Andarist
Copy link
Member

Andarist commented May 1, 2020

We hope to release v11 in May - there are no planned changes for native packages, so I would say that it's rather safe to use the next release line already. Just pin your versions and you should be able to use it without any problems.

@samburgers
Copy link

Any movement on this? Type safety on the css prop in react native would be an utter game changer

@Andarist
Copy link
Member

@samburgers those types are part of the v11 that is already released to npm. I'm going to release first RC version today - as the work on v11 has been, finally, completed.

@elektronik2k5
Copy link

@Andarist thank you so much for your hard work! 💪

@rezvalari
Copy link

rezvalari commented Dec 3, 2020

How to extend the Theme with this new version? Just like in here
#839 (comment)

@Andarist
Copy link
Member

Andarist commented Dec 3, 2020

Same as here: https://emotion.sh/docs/typescript#define-a-theme

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