Skip to content

Commit 5dd798b

Browse files
committed
Add styled-component/native types; fix bug with children
1 parent 1b3c564 commit 5dd798b

5 files changed

Lines changed: 306 additions & 5 deletions

File tree

types/styled-components/index.d.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// Ihor Chulinda <https://github.com/Igmat>
55
// Adam Lavin <https://github.com/lavoaster>
66
// Jessica Franco <https://github.com/Jessidhia>
7+
// Jason Killian <https://github.com/jkillian>
78
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
89
// TypeScript Version: 2.9
910

@@ -65,7 +66,7 @@ export type StyledComponentProps<
6566
A
6667
> & Partial<Pick<React.ComponentPropsWithRef<C> & O, A>>,
6768
T
68-
>;
69+
> & { children?: React.ReactNode };
6970

7071
type StyledComponentPropsWithAs<
7172
C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
@@ -263,24 +264,24 @@ type ThemedStyledComponentFactories<T extends object> = {
263264
[TTag in keyof JSX.IntrinsicElements]: ThemedStyledFunction<TTag, T>
264265
};
265266

266-
type StyledComponentInnerComponent<
267+
export type StyledComponentInnerComponent<
267268
C extends React.ComponentType<any>
268269
> = C extends
269270
| StyledComponent<infer I, any, any, any>
270271
| StyledComponent<infer I, any, any>
271272
? I
272273
: C;
273-
type StyledComponentPropsWithRef<
274+
export type StyledComponentPropsWithRef<
274275
C extends keyof JSX.IntrinsicElements | React.ComponentType<any>
275276
> = C extends AnyStyledComponent
276277
? React.ComponentPropsWithRef<StyledComponentInnerComponent<C>>
277278
: React.ComponentPropsWithRef<C>;
278-
type StyledComponentInnerOtherProps<C extends AnyStyledComponent> = C extends
279+
export type StyledComponentInnerOtherProps<C extends AnyStyledComponent> = C extends
279280
| StyledComponent<any, any, infer O, any>
280281
| StyledComponent<any, any, infer O>
281282
? O
282283
: never;
283-
type StyledComponentInnerAttrs<
284+
export type StyledComponentInnerAttrs<
284285
C extends AnyStyledComponent
285286
> = C extends StyledComponent<any, any, any, infer A> ? A : never;
286287

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
import * as ReactNative from 'react-native'
2+
import * as React from 'react'
3+
import { StatelessComponent, ComponentClass } from 'react'
4+
5+
export {
6+
DefaultTheme,
7+
css,
8+
isStyledComponent,
9+
ThemeProps,
10+
ThemeProvider,
11+
ThemeConsumer,
12+
ThemeContext,
13+
withTheme,
14+
} from './index';
15+
16+
import {
17+
AnyStyledComponent,
18+
StyledComponentInnerComponent,
19+
StyledComponentInnerOtherProps,
20+
StyledComponentInnerAttrs,
21+
ThemedStyledFunction,
22+
ThemedStyledInterface,
23+
DefaultTheme
24+
} from './index'
25+
26+
type AnyIfEmpty<T extends object> = keyof T extends never ? any : T;
27+
28+
export type ReactNativeThemedStyledFunction<
29+
C extends React.ComponentType<any>,
30+
T extends object,
31+
> = ThemedStyledFunction<C, T>;
32+
33+
// Copied over from "ThemedBaseStyledInterface" in index.d.ts in order to remove DOM element typings
34+
interface ReactNativeThemedBaseStyledInterface<T extends object> {
35+
<C extends AnyStyledComponent>(component: C): ThemedStyledFunction<
36+
StyledComponentInnerComponent<C>,
37+
T,
38+
StyledComponentInnerOtherProps<C>,
39+
StyledComponentInnerAttrs<C>
40+
>;
41+
<C extends React.ComponentType<any>>(
42+
// unfortunately using a conditional type to validate that it can receive a `theme?: Theme`
43+
// causes tests to fail in TS 3.1
44+
component: C
45+
): ThemedStyledFunction<C, T>;
46+
}
47+
48+
type ReactNativeThemedStyledInterface<T extends object> = ReactNativeThemedBaseStyledInterface<
49+
AnyIfEmpty<T>
50+
>;
51+
52+
export interface ReactNativeStyledInterface<T extends object> extends ReactNativeThemedStyledInterface<T> {
53+
ActivityIndicator: ReactNativeThemedStyledFunction<
54+
typeof ReactNative.ActivityIndicator,
55+
T
56+
>;
57+
ActivityIndicatorIOS: ReactNativeThemedStyledFunction<
58+
typeof ReactNative.ActivityIndicator,
59+
T
60+
>;
61+
Button: ReactNativeThemedStyledFunction<
62+
typeof ReactNative.Button,
63+
T
64+
>;
65+
DatePickerIOS: ReactNativeThemedStyledFunction<
66+
typeof ReactNative.DatePickerIOS,
67+
T
68+
>;
69+
DrawerLayoutAndroid: ReactNativeThemedStyledFunction<
70+
typeof ReactNative.DrawerLayoutAndroid,
71+
T
72+
>;
73+
Image: ReactNativeThemedStyledFunction<
74+
typeof ReactNative.Image,
75+
T
76+
>;
77+
ImageBackground: ReactNativeThemedStyledFunction<
78+
typeof ReactNative.ImageBackground,
79+
T
80+
>;
81+
KeyboardAvoidingView: ReactNativeThemedStyledFunction<
82+
typeof ReactNative.KeyboardAvoidingView,
83+
T
84+
>;
85+
ListView: ReactNativeThemedStyledFunction<
86+
typeof ReactNative.ListView,
87+
T
88+
>;
89+
MapView: ReactNativeThemedStyledFunction<
90+
typeof ReactNative.MapView,
91+
T
92+
>;
93+
Modal: ReactNativeThemedStyledFunction<
94+
typeof ReactNative.Modal,
95+
T
96+
>;
97+
NavigatorIOS: ReactNativeThemedStyledFunction<
98+
typeof ReactNative.NavigatorIOS,
99+
T
100+
>;
101+
Picker: ReactNativeThemedStyledFunction<
102+
typeof ReactNative.Picker,
103+
T
104+
>;
105+
PickerIOS: ReactNativeThemedStyledFunction<
106+
typeof ReactNative.PickerIOS,
107+
T
108+
>;
109+
ProgressBarAndroid: ReactNativeThemedStyledFunction<
110+
typeof ReactNative.ProgressBarAndroid,
111+
T
112+
>;
113+
ProgressViewIOS: ReactNativeThemedStyledFunction<
114+
typeof ReactNative.ProgressViewIOS,
115+
T
116+
>;
117+
ScrollView: ReactNativeThemedStyledFunction<
118+
typeof ReactNative.ScrollView,
119+
T
120+
>;
121+
SegmentedControlIOS: ReactNativeThemedStyledFunction<
122+
typeof ReactNative.SegmentedControlIOS,
123+
T
124+
>;
125+
Slider: ReactNativeThemedStyledFunction<
126+
typeof ReactNative.Slider,
127+
T
128+
>;
129+
SliderIOS: ReactNativeThemedStyledFunction<
130+
typeof ReactNative.Slider,
131+
T
132+
>;
133+
SnapshotViewIOS: ReactNativeThemedStyledFunction<
134+
typeof ReactNative.SnapshotViewIOS,
135+
T
136+
>;
137+
Switch: ReactNativeThemedStyledFunction<
138+
typeof ReactNative.Switch,
139+
T
140+
>;
141+
RecyclerViewBackedScrollView: ReactNativeThemedStyledFunction<
142+
typeof ReactNative.RecyclerViewBackedScrollView,
143+
T
144+
>;
145+
RefreshControl: ReactNativeThemedStyledFunction<
146+
typeof ReactNative.RefreshControl,
147+
T
148+
>;
149+
SafeAreaView: ReactNativeThemedStyledFunction<
150+
typeof ReactNative.SafeAreaView,
151+
T
152+
>;
153+
StatusBar: ReactNativeThemedStyledFunction<
154+
typeof ReactNative.StatusBar,
155+
T
156+
>;
157+
SwipeableListView: ReactNativeThemedStyledFunction<
158+
typeof ReactNative.SwipeableListView,
159+
T
160+
>
161+
SwitchAndroid: ReactNativeThemedStyledFunction<
162+
typeof ReactNative.Switch,
163+
T
164+
>;
165+
SwitchIOS: ReactNativeThemedStyledFunction<
166+
typeof ReactNative.SwitchIOS,
167+
T
168+
>;
169+
TabBarIOS: ReactNativeThemedStyledFunction<
170+
typeof ReactNative.TabBarIOS,
171+
T
172+
>;
173+
Text: ReactNativeThemedStyledFunction<
174+
typeof ReactNative.Text,
175+
T
176+
>;
177+
TextInput: ReactNativeThemedStyledFunction<
178+
typeof ReactNative.TextInput,
179+
T
180+
>;
181+
ToolbarAndroid: ReactNativeThemedStyledFunction<
182+
typeof ReactNative.ToolbarAndroid,
183+
T
184+
>;
185+
TouchableHighlight: ReactNativeThemedStyledFunction<
186+
typeof ReactNative.TouchableHighlight,
187+
T
188+
>;
189+
TouchableNativeFeedback: ReactNativeThemedStyledFunction<
190+
typeof ReactNative.TouchableNativeFeedback,
191+
T
192+
>;
193+
TouchableOpacity: ReactNativeThemedStyledFunction<
194+
typeof ReactNative.TouchableOpacity,
195+
T
196+
>;
197+
TouchableWithoutFeedback: ReactNativeThemedStyledFunction<
198+
typeof ReactNative.TouchableWithoutFeedback,
199+
T
200+
>;
201+
View: ReactNativeThemedStyledFunction<
202+
typeof ReactNative.View,
203+
T
204+
>;
205+
ViewPagerAndroid: ReactNativeThemedStyledFunction<
206+
typeof ReactNative.ViewPagerAndroid,
207+
T
208+
>;
209+
WebView: ReactNativeThemedStyledFunction<
210+
typeof ReactNative.WebView,
211+
T
212+
>;
213+
FlatList: ReactNativeThemedStyledFunction<
214+
typeof ReactNative.FlatList,
215+
T
216+
>;
217+
SectionList: ReactNativeThemedStyledFunction<
218+
typeof ReactNative.SectionList,
219+
T
220+
>;
221+
}
222+
223+
declare const styled: ReactNativeStyledInterface<DefaultTheme>;
224+
225+
export default styled;

types/styled-components/test/index.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,3 +1001,18 @@ function validateDefaultProps() {
10011001

10021002
<OtherStyledComponent requiredProp="1" />; // $ExpectError
10031003
}
1004+
1005+
// failing example from https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31491#issuecomment-459353227
1006+
1007+
interface WrapperClassProps {
1008+
className?: string
1009+
}
1010+
export class WrapperClassComponent extends React.Component<WrapperClassProps> {
1011+
render() {
1012+
return <div className={this.props.className}>{this.props.children}</div>
1013+
}
1014+
}
1015+
const WrapperClass = styled(WrapperClassComponent)`
1016+
border: 1px solid grey;
1017+
`
1018+
const wrapperClass = <WrapperClass>Text</WrapperClass>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as React from "react";
2+
import * as ReactNative from "react-native";
3+
import * as ReactDOMServer from "react-dom/server";
4+
5+
import styled, {
6+
css,
7+
isStyledComponent,
8+
ThemeProps,
9+
ThemeProvider,
10+
withTheme,
11+
ThemeConsumer,
12+
} from "styled-components/native";
13+
import {} from "styled-components/cssprop";
14+
15+
const StyledView = styled.View`
16+
background-color: papayawhip;
17+
`
18+
19+
const StyledText = styled(ReactNative.Text)`
20+
color: palevioletred;
21+
`
22+
23+
class MyReactNativeComponent extends React.Component {
24+
render() {
25+
return (
26+
<StyledView collapsable>
27+
<StyledText adjustsFontSizeToFit>Hello World!</StyledText>
28+
</StyledView>
29+
)
30+
}
31+
}
32+
33+
const invalidProp = <StyledText randoName={2} />; // $ExpectError
34+
const invalidTag = styled.div` margin-top: 5px; `; // $ExpectError
35+
36+
interface MyTheme {
37+
primary: string;
38+
}
39+
40+
interface ButtonProps {
41+
name: string;
42+
primary?: boolean;
43+
theme: MyTheme;
44+
}
45+
46+
class MyButton extends React.Component<ButtonProps> {
47+
render() {
48+
return <ReactNative.TouchableOpacity>Custom button</ReactNative.TouchableOpacity>;
49+
}
50+
}
51+
52+
const TomatoButton = styled(MyButton)`
53+
color: tomato;
54+
border-color: tomato;
55+
`;
56+
57+
// needs name prop, but not theme prop
58+
const tomatoElement = <TomatoButton name="needed" />

types/styled-components/tsconfig.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
},
2121
"files": [
2222
"index.d.ts",
23+
"native.d.ts",
2324
"macro.d.ts",
2425
"cssprop.d.ts",
2526
"test/index.tsx",
27+
"test/native.tsx",
2628
"test/macro.tsx"
2729
]
2830
}

0 commit comments

Comments
 (0)