Skip to content

Commit

Permalink
[styled-components] Move React Native-dependent types to separate pac…
Browse files Browse the repository at this point in the history
…kage
  • Loading branch information
Methuselah96 committed Dec 18, 2020
1 parent 4c607e6 commit 48542fd
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 453 deletions.
125 changes: 125 additions & 0 deletions types/styled-components-react-native/index.d.ts
@@ -0,0 +1,125 @@
// Type definitions for styled-components-react-native 5.1
// Project: https://github.com/styled-components/styled-components
// Definitions by: Nathan Bierema <https://github.com/Methuselah96>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped

// tslint:disable-next-line:no-single-declare-module
declare module "styled-components/native" {
import * as ReactNative from "react-native";
import * as React from "react";

export {
css,
DefaultTheme,
isStyledComponent,
ThemeConsumer,
ThemeContext,
ThemeProps,
ThemeProvider,
withTheme,
useTheme,
} from "styled-components";

import {
AnyStyledComponent,
DefaultTheme,
isStyledComponent,
StyledComponentInnerAttrs,
StyledComponentInnerComponent,
StyledComponentInnerOtherProps,
ThemedCssFunction,
ThemedStyledFunction,
ThemedStyledInterface,
ThemeProviderComponent,
WithThemeFnInterface,
} from "styled-components";

type AnyIfEmpty<T extends object> = keyof T extends never ? any : T;

export type ReactNativeThemedStyledFunction<
C extends React.ComponentType<any>,
T extends object
> = ThemedStyledFunction<C, T>;

// Copied over from "ThemedBaseStyledInterface" in index.d.ts in order to remove DOM element typings
interface ReactNativeThemedBaseStyledInterface<T extends object> {
<C extends AnyStyledComponent>(component: C): ThemedStyledFunction<
StyledComponentInnerComponent<C>,
T,
StyledComponentInnerOtherProps<C>,
StyledComponentInnerAttrs<C>
>;
<C extends React.ComponentType<any>>(
// 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<C, T>;
}

type ReactNativeThemedStyledInterface<T extends object> = ReactNativeThemedBaseStyledInterface<AnyIfEmpty<T>>;

export interface ReactNativeStyledInterface<T extends object> extends ReactNativeThemedStyledInterface<T> {
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>;
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>;
FlatList: ReactNativeThemedStyledFunction<typeof ReactNative.FlatList, T>;
SectionList: ReactNativeThemedStyledFunction<typeof ReactNative.SectionList, T>;
}

export interface ReactNativeThemedStyledComponentsModule<T extends object, U extends object = T> {
default: ReactNativeStyledInterface<T>;

css: ThemedCssFunction<T>;

withTheme: WithThemeFnInterface<T>;
ThemeProvider: ThemeProviderComponent<T, U>;
ThemeConsumer: React.Consumer<T>;
ThemeContext: React.Context<T>;
useTheme(): T;

// This could be made to assert `target is StyledComponent<any, T>` instead, but that feels not type safe
isStyledComponent: typeof isStyledComponent;
}

const styled: ReactNativeStyledInterface<DefaultTheme>;

export default styled;
}
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as ReactNative from 'react-native';
import * as ReactDOMServer from 'react-dom/server';
import * as React from "react";
import * as ReactNative from "react-native";
import * as ReactDOMServer from "react-dom/server";

import styled, {
css,
Expand All @@ -10,8 +10,8 @@ import styled, {
withTheme,
ThemeConsumer,
ReactNativeThemedStyledComponentsModule,
} from 'styled-components/native';
import {} from 'styled-components/cssprop';
} from "styled-components/native";
import {} from "styled-components/cssprop";

const StyledView = styled.View`
background-color: papayawhip;
Expand Down Expand Up @@ -61,25 +61,25 @@ const tomatoElement = <TomatoButton name="needed" />;

async function typedThemes() {
const theme = {
color: 'green',
color: "green",
};

// abuse "await import(...)" to be able to reference the styled-components namespace
// without actually doing a top level namespace import
const { default: styled, css, ThemeProvider, ThemeConsumer } = ((await import(
'styled-components/native'
"styled-components/native"
)) as any) as ReactNativeThemedStyledComponentsModule<typeof theme>;

const ThemedView = styled.View`
background: ${props => {
background: ${(props) => {
// $ExpectType string
props.theme.color;
// $ExpectType string | undefined
props.testID;
return props.theme.color;
}};
`;
const ThemedView2 = styled.View(props => {
const ThemedView2 = styled.View((props) => {
// $ExpectType string
props.theme.color;
// $ExpectType string | undefined
Expand All @@ -89,7 +89,7 @@ async function typedThemes() {
background: props.theme.color,
};
});
const ThemedView3 = styled.View(props => {
const ThemedView3 = styled.View((props) => {
// $ExpectType string
props.theme.color;
// $ExpectType string | undefined
Expand All @@ -100,7 +100,7 @@ async function typedThemes() {
`;
});
const themedCss = css`
background: ${props => {
background: ${(props) => {
// $ExpectType string
props.theme.color;
// $ExpectType "theme"
Expand All @@ -112,10 +112,10 @@ async function typedThemes() {
// $ExpectError
const ThemedView4 = styled.View(themedCss);

const themedCssWithNesting = css(props => ({
const themedCssWithNesting = css((props) => ({
color: props.theme.color,
[ThemedView3]: {
color: 'green',
color: "green",
},
}));

Expand All @@ -126,7 +126,7 @@ async function typedThemes() {
<ThemedView2 />
<ThemedView3 />
<ThemeConsumer>
{theme => {
{(theme) => {
// $ExpectType string
theme.color;
return theme.color;
Expand All @@ -138,7 +138,7 @@ async function typedThemes() {
}

async function reexportCompatibility() {
const sc = await import('styled-components/native');
const sc = await import("styled-components/native");
const themed = sc as ReactNativeThemedStyledComponentsModule<any>;

let { ...scExports } = sc;
Expand All @@ -159,30 +159,30 @@ async function themeAugmentation() {
accent: string;
}

const base = ((await import('styled-components/native')) as any) as ReactNativeThemedStyledComponentsModule<
BaseTheme
>;
const extra = ((await import('styled-components/native')) as any) as ReactNativeThemedStyledComponentsModule<
const base = ((await import(
"styled-components/native"
)) as any) as ReactNativeThemedStyledComponentsModule<BaseTheme>;
const extra = ((await import("styled-components/native")) as any) as ReactNativeThemedStyledComponentsModule<
ExtraTheme,
BaseTheme
>;

return (
<base.ThemeProvider
theme={{
background: 'black',
background: "black",
}}
>
<>
<extra.ThemeProvider
theme={base => base} // $ExpectError
theme={(base) => base} // $ExpectError
>
<extra.ThemeConsumer>{() => null}</extra.ThemeConsumer>
</extra.ThemeProvider>
<extra.ThemeProvider
theme={base => ({
theme={(base) => ({
...base,
accent: 'blue',
accent: "blue",
})}
>
<extra.ThemeConsumer>{() => null}</extra.ThemeConsumer>
Expand Down
24 changes: 24 additions & 0 deletions types/styled-components-react-native/tsconfig.json
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"module": "commonjs",
"jsx": "react",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"styled-components-react-native-tests.tsx"
]
}
6 changes: 6 additions & 0 deletions types/styled-components-react-native/tslint.json
@@ -0,0 +1,6 @@
{
"extends": "dtslint/dt.json",
"rules": {
"npm-naming": false
}
}

0 comments on commit 48542fd

Please sign in to comment.