From 0dd2283a1c9b9c7784c26ea5530592c120ec63ce Mon Sep 17 00:00:00 2001 From: David Ruisinger Date: Sat, 23 Feb 2019 16:14:42 +0100 Subject: [PATCH 1/5] Added interface to re-export module with theme interface --- types/styled-components/index.d.ts | 1 + types/styled-components/native.d.ts | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/types/styled-components/index.d.ts b/types/styled-components/index.d.ts index a7dea63e06..2ade6848ec 100644 --- a/types/styled-components/index.d.ts +++ b/types/styled-components/index.d.ts @@ -5,6 +5,7 @@ // Adam Lavin // Jessica Franco // Jason Killian +// David Ruisinger /github.com/flavordaaave> // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.9 diff --git a/types/styled-components/native.d.ts b/types/styled-components/native.d.ts index 0c1c520270..71e361af26 100644 --- a/types/styled-components/native.d.ts +++ b/types/styled-components/native.d.ts @@ -2,24 +2,27 @@ import * as ReactNative from 'react-native'; import * as React from 'react'; export { - DefaultTheme, css, + DefaultTheme, isStyledComponent, - ThemeProps, - ThemeProvider, ThemeConsumer, ThemeContext, + ThemeProps, + ThemeProvider, withTheme, } from './index'; import { AnyStyledComponent, + DefaultTheme, + StyledComponentInnerAttrs, StyledComponentInnerComponent, StyledComponentInnerOtherProps, - StyledComponentInnerAttrs, + ThemedCssFunction, ThemedStyledFunction, ThemedStyledInterface, - DefaultTheme + ThemeProviderComponent, + WithThemeFnInterface } from './index'; type AnyIfEmpty = keyof T extends never ? any : T; @@ -211,6 +214,20 @@ export interface ReactNativeStyledInterface extends ReactNativ >; } +export interface ReactNativeThemedStyledComponentsModule< + T extends object, + U extends object = T +> { + default: ReactNativeStyledInterface + + css: ThemedCssFunction + + withTheme: WithThemeFnInterface + ThemeProvider: ThemeProviderComponent + ThemeConsumer: React.Consumer + ThemeContext: React.Context +} + declare const styled: ReactNativeStyledInterface; export default styled; From e652c53a432ca75776bfad9a370c93260a2ae99e Mon Sep 17 00:00:00 2001 From: David Ruisinger Date: Sat, 23 Feb 2019 21:22:56 +0100 Subject: [PATCH 2/5] Fixed typo --- types/styled-components/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/styled-components/index.d.ts b/types/styled-components/index.d.ts index 2ade6848ec..00735dd469 100644 --- a/types/styled-components/index.d.ts +++ b/types/styled-components/index.d.ts @@ -5,7 +5,7 @@ // Adam Lavin // Jessica Franco // Jason Killian -// David Ruisinger /github.com/flavordaaave> +// David Ruisinger // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.9 From 14d234420f67d83246e99a92f67b3e0f16106e29 Mon Sep 17 00:00:00 2001 From: David Ruisinger Date: Sat, 23 Feb 2019 21:36:39 +0100 Subject: [PATCH 3/5] Fix linting errors --- types/styled-components/native.d.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/types/styled-components/native.d.ts b/types/styled-components/native.d.ts index 71e361af26..c67df4d7a1 100644 --- a/types/styled-components/native.d.ts +++ b/types/styled-components/native.d.ts @@ -218,14 +218,14 @@ export interface ReactNativeThemedStyledComponentsModule< T extends object, U extends object = T > { - default: ReactNativeStyledInterface + default: ReactNativeStyledInterface; - css: ThemedCssFunction + css: ThemedCssFunction; - withTheme: WithThemeFnInterface - ThemeProvider: ThemeProviderComponent - ThemeConsumer: React.Consumer - ThemeContext: React.Context + withTheme: WithThemeFnInterface; + ThemeProvider: ThemeProviderComponent; + ThemeConsumer: React.Consumer; + ThemeContext: React.Context; } declare const styled: ReactNativeStyledInterface; From 1d6edf7767d0d01bc66aa6a0b447b0e436cb4e16 Mon Sep 17 00:00:00 2001 From: David Ruisinger Date: Sat, 23 Feb 2019 22:31:07 +0100 Subject: [PATCH 4/5] Added isStyledComponent --- types/styled-components/native.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/types/styled-components/native.d.ts b/types/styled-components/native.d.ts index c67df4d7a1..189e284525 100644 --- a/types/styled-components/native.d.ts +++ b/types/styled-components/native.d.ts @@ -15,6 +15,7 @@ export { import { AnyStyledComponent, DefaultTheme, + isStyledComponent, StyledComponentInnerAttrs, StyledComponentInnerComponent, StyledComponentInnerOtherProps, @@ -226,6 +227,9 @@ export interface ReactNativeThemedStyledComponentsModule< ThemeProvider: ThemeProviderComponent; ThemeConsumer: React.Consumer; ThemeContext: React.Context; + + // This could be made to assert `target is StyledComponent` instead, but that feels not type safe + isStyledComponent: typeof isStyledComponent; } declare const styled: ReactNativeStyledInterface; From 93fb2ef1ffc278fc22272ab6419576e7809ece68 Mon Sep 17 00:00:00 2001 From: David Ruisinger Date: Sat, 23 Feb 2019 22:56:48 +0100 Subject: [PATCH 5/5] Adds tests for ReactNativeThemedStyledComponentsModule --- types/styled-components/test/native.tsx | 139 ++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/types/styled-components/test/native.tsx b/types/styled-components/test/native.tsx index 66b0f975ce..da2ba83390 100644 --- a/types/styled-components/test/native.tsx +++ b/types/styled-components/test/native.tsx @@ -9,6 +9,7 @@ import styled, { ThemeProvider, withTheme, ThemeConsumer, + ReactNativeThemedStyledComponentsModule, } from "styled-components/native"; import {} from "styled-components/cssprop"; @@ -57,3 +58,141 @@ const TomatoButton = styled(MyButton)` // needs name prop, but not theme prop const tomatoElement = ; + +async function typedThemes() { + const theme = { + 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")) as any as ReactNativeThemedStyledComponentsModule< + typeof theme + >; + + const ThemedView = styled.View` + background: ${props => { + // $ExpectType string + props.theme.color; + // $ExpectType string | undefined + props.testID; + return props.theme.color; + }}; + `; + const ThemedView2 = styled.View(props => { + // $ExpectType string + props.theme.color; + // $ExpectType string | undefined + props.testID; + + return { + background: props.theme.color + }; + }); + const ThemedView3 = styled.View(props => { + // $ExpectType string + props.theme.color; + // $ExpectType string | undefined + props.testID; + + return css` + background: ${props.theme.color}; + `; +}); +const themedCss = css` + background: ${props => { + // $ExpectType string + props.theme.color; + // $ExpectType "theme" + type Keys = keyof typeof props; + return props.theme.color; + }}; +`; +// can't use a FlattenInterpolation as the first argument, would make broken css +// $ExpectError +const ThemedView4 = styled.View(themedCss); + +const themedCssWithNesting = css(props => ({ + color: props.theme.color, + [ThemedView3]: { + color: "green" + } +})); + +return ( + + <> + + + + + {theme => { + // $ExpectType string + theme.color; + return theme.color; + }} + + + + ); +} + +async function reexportCompatibility() { + const sc = await import("styled-components/native"); + const themed = sc as ReactNativeThemedStyledComponentsModule; + + let { ...scExports } = sc; + let { ...themedExports } = themed; + // both branches must be assignable to each other + if (Math.random()) { + scExports = themedExports; + } else { + themedExports = scExports; + } +} + +async function themeAugmentation() { + interface BaseTheme { + background: string; + } + interface ExtraTheme extends BaseTheme { + 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< + ExtraTheme, + BaseTheme + >; + + return ( + + <> + base} // $ExpectError + > + {() => null} + + ({ + ...base, + accent: "blue" + })} + > + {() => null} + + + + ); +}