diff --git a/types/styled-components/index.d.ts b/types/styled-components/index.d.ts index e28b05066e..59bceabd2c 100644 --- a/types/styled-components/index.d.ts +++ b/types/styled-components/index.d.ts @@ -4,6 +4,7 @@ // Ihor Chulinda // Adam Lavin // Jessica Franco +// Jason Killian // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.9 @@ -65,7 +66,7 @@ export type StyledComponentProps< A > & Partial & O, A>>, T ->; +> & { children?: React.ReactNode }; type StyledComponentPropsWithAs< C extends keyof JSX.IntrinsicElements | React.ComponentType, @@ -263,24 +264,24 @@ type ThemedStyledComponentFactories = { [TTag in keyof JSX.IntrinsicElements]: ThemedStyledFunction }; -type StyledComponentInnerComponent< +export type StyledComponentInnerComponent< C extends React.ComponentType > = C extends | StyledComponent | StyledComponent ? I : C; -type StyledComponentPropsWithRef< +export type StyledComponentPropsWithRef< C extends keyof JSX.IntrinsicElements | React.ComponentType > = C extends AnyStyledComponent ? React.ComponentPropsWithRef> : React.ComponentPropsWithRef; -type StyledComponentInnerOtherProps = C extends +export type StyledComponentInnerOtherProps = C extends | StyledComponent | StyledComponent ? O : never; -type StyledComponentInnerAttrs< +export type StyledComponentInnerAttrs< C extends AnyStyledComponent > = C extends StyledComponent ? A : never; diff --git a/types/styled-components/native.d.ts b/types/styled-components/native.d.ts new file mode 100644 index 0000000000..70f3eafe43 --- /dev/null +++ b/types/styled-components/native.d.ts @@ -0,0 +1,225 @@ +import * as ReactNative from 'react-native' +import * as React from 'react' +import { StatelessComponent, ComponentClass } from 'react' + +export { + DefaultTheme, + css, + isStyledComponent, + ThemeProps, + ThemeProvider, + ThemeConsumer, + ThemeContext, + withTheme, +} from './index'; + +import { + AnyStyledComponent, + StyledComponentInnerComponent, + StyledComponentInnerOtherProps, + StyledComponentInnerAttrs, + ThemedStyledFunction, + ThemedStyledInterface, + DefaultTheme +} from './index' + +type AnyIfEmpty = keyof T extends never ? any : T; + +export type ReactNativeThemedStyledFunction< + C extends React.ComponentType, + T extends object, +> = ThemedStyledFunction; + +// Copied over from "ThemedBaseStyledInterface" in index.d.ts in order to remove DOM element typings +interface ReactNativeThemedBaseStyledInterface { + (component: C): ThemedStyledFunction< + StyledComponentInnerComponent, + T, + StyledComponentInnerOtherProps, + StyledComponentInnerAttrs + >; + >( + // unfortunately using a conditional type to validate that it can receive a `theme?: Theme` + // causes tests to fail in TS 3.1 + component: C + ): ThemedStyledFunction; +} + +type ReactNativeThemedStyledInterface = ReactNativeThemedBaseStyledInterface< + AnyIfEmpty +>; + +export interface ReactNativeStyledInterface extends ReactNativeThemedStyledInterface { + ActivityIndicator: ReactNativeThemedStyledFunction< + typeof ReactNative.ActivityIndicator, + T + >; + ActivityIndicatorIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.ActivityIndicator, + T + >; + Button: ReactNativeThemedStyledFunction< + typeof ReactNative.Button, + T + >; + DatePickerIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.DatePickerIOS, + T + >; + DrawerLayoutAndroid: ReactNativeThemedStyledFunction< + typeof ReactNative.DrawerLayoutAndroid, + T + >; + Image: ReactNativeThemedStyledFunction< + typeof ReactNative.Image, + T + >; + ImageBackground: ReactNativeThemedStyledFunction< + typeof ReactNative.ImageBackground, + T + >; + KeyboardAvoidingView: ReactNativeThemedStyledFunction< + typeof ReactNative.KeyboardAvoidingView, + T + >; + ListView: ReactNativeThemedStyledFunction< + typeof ReactNative.ListView, + T + >; + MapView: ReactNativeThemedStyledFunction< + typeof ReactNative.MapView, + T + >; + Modal: ReactNativeThemedStyledFunction< + typeof ReactNative.Modal, + T + >; + NavigatorIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.NavigatorIOS, + T + >; + Picker: ReactNativeThemedStyledFunction< + typeof ReactNative.Picker, + T + >; + PickerIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.PickerIOS, + T + >; + ProgressBarAndroid: ReactNativeThemedStyledFunction< + typeof ReactNative.ProgressBarAndroid, + T + >; + ProgressViewIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.ProgressViewIOS, + T + >; + ScrollView: ReactNativeThemedStyledFunction< + typeof ReactNative.ScrollView, + T + >; + SegmentedControlIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.SegmentedControlIOS, + T + >; + Slider: ReactNativeThemedStyledFunction< + typeof ReactNative.Slider, + T + >; + SliderIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.Slider, + T + >; + SnapshotViewIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.SnapshotViewIOS, + T + >; + Switch: ReactNativeThemedStyledFunction< + typeof ReactNative.Switch, + T + >; + RecyclerViewBackedScrollView: ReactNativeThemedStyledFunction< + typeof ReactNative.RecyclerViewBackedScrollView, + T + >; + RefreshControl: ReactNativeThemedStyledFunction< + typeof ReactNative.RefreshControl, + T + >; + SafeAreaView: ReactNativeThemedStyledFunction< + typeof ReactNative.SafeAreaView, + T + >; + StatusBar: ReactNativeThemedStyledFunction< + typeof ReactNative.StatusBar, + T + >; + SwipeableListView: ReactNativeThemedStyledFunction< + typeof ReactNative.SwipeableListView, + T + > + SwitchAndroid: ReactNativeThemedStyledFunction< + typeof ReactNative.Switch, + T + >; + SwitchIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.SwitchIOS, + T + >; + TabBarIOS: ReactNativeThemedStyledFunction< + typeof ReactNative.TabBarIOS, + T + >; + Text: ReactNativeThemedStyledFunction< + typeof ReactNative.Text, + T + >; + TextInput: ReactNativeThemedStyledFunction< + typeof ReactNative.TextInput, + T + >; + ToolbarAndroid: ReactNativeThemedStyledFunction< + typeof ReactNative.ToolbarAndroid, + T + >; + TouchableHighlight: ReactNativeThemedStyledFunction< + typeof ReactNative.TouchableHighlight, + T + >; + TouchableNativeFeedback: ReactNativeThemedStyledFunction< + typeof ReactNative.TouchableNativeFeedback, + T + >; + TouchableOpacity: ReactNativeThemedStyledFunction< + typeof ReactNative.TouchableOpacity, + T + >; + TouchableWithoutFeedback: ReactNativeThemedStyledFunction< + typeof ReactNative.TouchableWithoutFeedback, + T + >; + View: ReactNativeThemedStyledFunction< + typeof ReactNative.View, + T + >; + ViewPagerAndroid: ReactNativeThemedStyledFunction< + typeof ReactNative.ViewPagerAndroid, + T + >; + WebView: ReactNativeThemedStyledFunction< + typeof ReactNative.WebView, + T + >; + FlatList: ReactNativeThemedStyledFunction< + typeof ReactNative.FlatList, + T + >; + SectionList: ReactNativeThemedStyledFunction< + typeof ReactNative.SectionList, + T + >; +} + +declare const styled: ReactNativeStyledInterface; + +export default styled; diff --git a/types/styled-components/test/index.tsx b/types/styled-components/test/index.tsx index bae94072ec..d6919e5dc3 100644 --- a/types/styled-components/test/index.tsx +++ b/types/styled-components/test/index.tsx @@ -1001,3 +1001,18 @@ function validateDefaultProps() { ; // $ExpectError } + +// failing example from https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31491#issuecomment-459353227 + +interface WrapperClassProps { + className?: string +} +export class WrapperClassComponent extends React.Component { + render() { + return
{this.props.children}
+ } +} +const WrapperClass = styled(WrapperClassComponent)` + border: 1px solid grey; +` +const wrapperClass = Text diff --git a/types/styled-components/test/native.tsx b/types/styled-components/test/native.tsx new file mode 100644 index 0000000000..537ffc8aba --- /dev/null +++ b/types/styled-components/test/native.tsx @@ -0,0 +1,58 @@ +import * as React from "react"; +import * as ReactNative from "react-native"; +import * as ReactDOMServer from "react-dom/server"; + +import styled, { + css, + isStyledComponent, + ThemeProps, + ThemeProvider, + withTheme, + ThemeConsumer, +} from "styled-components/native"; +import {} from "styled-components/cssprop"; + +const StyledView = styled.View` + background-color: papayawhip; +` + +const StyledText = styled(ReactNative.Text)` + color: palevioletred; +` + +class MyReactNativeComponent extends React.Component { + render() { + return ( + + Hello World! + + ) + } +} + +const invalidProp = ; // $ExpectError +const invalidTag = styled.div` margin-top: 5px; `; // $ExpectError + +interface MyTheme { + primary: string; +} + +interface ButtonProps { + name: string; + primary?: boolean; + theme: MyTheme; +} + +class MyButton extends React.Component { + render() { + return Custom button; + } +} + +const TomatoButton = styled(MyButton)` + color: tomato; + border-color: tomato; +`; + +// needs name prop, but not theme prop +const tomatoElement = diff --git a/types/styled-components/tsconfig.json b/types/styled-components/tsconfig.json index fb9b5a0f7b..2202fe8e4b 100644 --- a/types/styled-components/tsconfig.json +++ b/types/styled-components/tsconfig.json @@ -20,9 +20,11 @@ }, "files": [ "index.d.ts", + "native.d.ts", "macro.d.ts", "cssprop.d.ts", "test/index.tsx", + "test/native.tsx", "test/macro.tsx" ] } \ No newline at end of file