UNPKG

17.3 kBTypeScriptView Raw
1// forward declarations
2declare global {
3 namespace NodeJS {
4 // eslint-disable-next-line @typescript-eslint/no-empty-interface
5 interface ReadableStream {}
6 }
7 // eslint-disable-next-line @typescript-eslint/no-empty-interface
8 interface ShadowRoot {}
9}
10
11import * as CSS from "csstype";
12import * as hoistNonReactStatics from "hoist-non-react-statics";
13import * as React from "react";
14
15export type CSSProperties = CSS.Properties<string | number>;
16
17export type CSSPseudos = { [K in CSS.Pseudos]?: CSSObject };
18
19export interface CSSObject extends CSSProperties, CSSPseudos {
20 [key: string]: CSSObject | string | number | undefined;
21}
22
23export type CSSKeyframes = object & { [key: string]: CSSObject };
24
25export interface ThemeProps<T> {
26 theme: T;
27}
28
29export type ThemedStyledProps<P, T> = P & ThemeProps<T>;
30export type StyledProps<P> = ThemedStyledProps<P, AnyIfEmpty<DefaultTheme>>;
31export type IntrinsicElementsKeys = keyof JSX.IntrinsicElements;
32
33// Any prop that has a default prop becomes optional, but its type is unchanged
34// Undeclared default props are augmented into the resulting allowable attributes
35// If declared props have indexed properties, ignore default props entirely as keyof gets widened
36// Wrap in an outer-level conditional type to allow distribution over props that are unions
37type Defaultize<P, D> = P extends any ? string extends keyof P ? P
38 :
39 & PickU<P, Exclude<keyof P, keyof D>>
40 & Partial<PickU<P, Extract<keyof P, keyof D>>>
41 & Partial<PickU<D, Exclude<keyof D, keyof P>>>
42 : never;
43
44type ReactDefaultizedProps<C, P> = C extends { defaultProps: infer D } ? Defaultize<P, D> : P;
45
46type MakeAttrsOptional<
47 C extends string | React.ComponentType<any>,
48 O extends object,
49 A extends keyof P,
50 P = React.ComponentPropsWithRef<C extends IntrinsicElementsKeys | React.ComponentType<any> ? C : never>,
51> =
52 // Distribute unions early to avoid quadratic expansion
53 P extends any ? OmitU<ReactDefaultizedProps<C, P> & O, A> & Partial<PickU<P & O, A>> : never;
54
55export type StyledComponentProps<
56 // The Component from whose props are derived
57 C extends string | React.ComponentType<any>,
58 // The Theme from the current context
59 T extends object,
60 // The other props added by the template
61 O extends object,
62 // The props that are made optional by .attrs
63 A extends keyof any,
64 // The Component passed with "forwardedAs" prop
65 FAsC extends string | React.ComponentType<any> = C,
66> =
67 // Distribute O if O is a union type
68 O extends object ? WithOptionalTheme<
69 MakeAttrsOptional<C, O, A> & MakeAttrsOptional<FAsC, O, A>,
70 T
71 >
72 : never;
73
74type StyledComponentPropsWithAs<
75 C extends string | React.ComponentType<any>,
76 T extends object,
77 O extends object,
78 A extends keyof any,
79 AsC extends string | React.ComponentType<any> = C,
80 FAsC extends string | React.ComponentType<any> = C,
81> = StyledComponentProps<C, T, O, A, FAsC> & { as?: AsC | undefined; forwardedAs?: FAsC | undefined };
82
83export type FalseyValue = undefined | null | false;
84export type Interpolation<P> = InterpolationValue | InterpolationFunction<P> | FlattenInterpolation<P>;
85// cannot be made a self-referential interface, breaks WithPropNested
86// see https://github.com/microsoft/TypeScript/issues/34796
87export type FlattenInterpolation<P> = ReadonlyArray<Interpolation<P>>;
88export type InterpolationValue = string | number | FalseyValue | Keyframes | StyledComponentInterpolation | CSSObject;
89export type SimpleInterpolation = InterpolationValue | FlattenSimpleInterpolation;
90export type FlattenSimpleInterpolation = readonly SimpleInterpolation[];
91
92export type InterpolationFunction<P> = (props: P) => Interpolation<P>;
93
94type Attrs<P, A extends Partial<P>, T> = ((props: ThemedStyledProps<P, T>) => A) | A;
95
96export type ThemedGlobalStyledClassProps<P extends { theme?: T | undefined }, T> = WithOptionalTheme<P, T> & {
97 suppressMultiMountWarning?: boolean | undefined;
98};
99
100export interface GlobalStyleComponent<P extends { theme?: T | undefined }, T>
101 extends React.ComponentClass<ThemedGlobalStyledClassProps<P, T>>
102{}
103
104// remove the call signature from StyledComponent so Interpolation can still infer InterpolationFunction
105type StyledComponentInterpolation =
106 | PickU<StyledComponentBase<any, any, any, any>, keyof StyledComponentBase<any, any>>
107 | PickU<StyledComponentBase<any, any, any>, keyof StyledComponentBase<any, any>>;
108
109// abuse Pick to strip the call signature from ForwardRefExoticComponent
110type ForwardRefExoticBase<P> = PickU<React.ForwardRefExoticComponent<P>, keyof React.ForwardRefExoticComponent<any>>;
111
112// Config to be used with withConfig
113export interface StyledConfig<O extends object = {}> {
114 // TODO: Add all types from the original StyledComponentWrapperProperties
115 componentId?: string;
116 displayName?: string;
117 shouldForwardProp?: ((prop: keyof O, defaultValidatorFn: (prop: keyof O) => boolean) => boolean) | undefined;
118}
119
120// extracts React defaultProps
121type ReactDefaultProps<C> = C extends { defaultProps: infer D } ? D : never;
122
123// any doesn't count as assignable to never in the extends clause, and we default A to never
124export type AnyStyledComponent = StyledComponent<any, any, any, any> | StyledComponent<any, any, any>;
125
126export type StyledComponent<
127 C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
128 T extends object,
129 O extends object = {},
130 A extends keyof any = never,
131> = // the "string" allows this to be used as an object key
132 // I really want to avoid this if possible but it's the only way to use nesting with object styles...
133 & string
134 & StyledComponentBase<C, T, O, A>
135 & hoistNonReactStatics.NonReactStatics<C extends React.ComponentType<any> ? C : never>;
136
137export interface StyledComponentBase<
138 C extends string | React.ComponentType<any>,
139 T extends object,
140 O extends object = {},
141 A extends keyof any = never,
142> extends ForwardRefExoticBase<StyledComponentProps<C, T, O, A>> {
143 // add our own fake call signature to implement the polymorphic 'as' prop
144 (
145 props: StyledComponentProps<C, T, O, A> & { as?: never | undefined; forwardedAs?: never | undefined },
146 ): React.ReactElement<
147 StyledComponentProps<C, T, O, A>
148 >;
149 <AsC extends string | React.ComponentType<any> = C, FAsC extends string | React.ComponentType<any> = AsC>(
150 props: StyledComponentPropsWithAs<AsC, T, O, A, AsC, FAsC>,
151 ): React.ReactElement<StyledComponentPropsWithAs<AsC, T, O, A, AsC, FAsC>>;
152
153 withComponent<WithC extends AnyStyledComponent>(
154 component: WithC,
155 ): StyledComponent<
156 StyledComponentInnerComponent<WithC>,
157 T,
158 O & StyledComponentInnerOtherProps<WithC>,
159 A | StyledComponentInnerAttrs<WithC>
160 >;
161 withComponent<WithC extends keyof JSX.IntrinsicElements | React.ComponentType<any>>(
162 component: WithC,
163 ): StyledComponent<WithC, T, O, A>;
164}
165
166export interface ThemedStyledFunctionBase<
167 C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
168 T extends object,
169 O extends object = {},
170 A extends keyof any = never,
171> {
172 (first: TemplateStringsArray): StyledComponent<C, T, O, A>;
173 (
174 first:
175 | TemplateStringsArray
176 | CSSObject
177 | InterpolationFunction<ThemedStyledProps<StyledComponentPropsWithRef<C> & O, T>>,
178 ...rest: Array<Interpolation<ThemedStyledProps<StyledComponentPropsWithRef<C> & O, T>>>
179 ): StyledComponent<C, T, O, A>;
180 <U extends object>(
181 first:
182 | TemplateStringsArray
183 | CSSObject
184 | InterpolationFunction<ThemedStyledProps<StyledComponentPropsWithRef<C> & O & U, T>>,
185 ...rest: Array<Interpolation<ThemedStyledProps<StyledComponentPropsWithRef<C> & O & U, T>>>
186 ): StyledComponent<C, T, O & U, A>;
187}
188
189export interface ThemedStyledFunction<
190 C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
191 T extends object,
192 O extends object = {},
193 A extends keyof any = never,
194> extends ThemedStyledFunctionBase<C, T, O, A> {
195 // Fun thing: 'attrs' can also provide a polymorphic 'as' prop
196 // My head already hurts enough so maybe later...
197 attrs<
198 U,
199 NewA extends Partial<StyledComponentPropsWithRef<C> & U> & {
200 [others: string]: any;
201 } = {},
202 >(
203 attrs: Attrs<StyledComponentPropsWithRef<C> & U, NewA, T>,
204 ): ThemedStyledFunction<C, T, O & NewA, A | keyof NewA>;
205
206 withConfig: <Props extends O = O>(
207 config: StyledConfig<StyledComponentPropsWithRef<C> & Props>,
208 ) => ThemedStyledFunction<C, T, Props, A>;
209}
210
211export type StyledFunction<C extends keyof JSX.IntrinsicElements | React.ComponentType<any>> = ThemedStyledFunction<
212 C,
213 any
214>;
215
216type ThemedStyledComponentFactories<T extends object> = {
217 [TTag in keyof JSX.IntrinsicElements]: ThemedStyledFunction<TTag, T>;
218};
219
220export type StyledComponentInnerComponent<C extends React.ComponentType<any>> = C extends StyledComponent<
221 infer I,
222 any,
223 any,
224 any
225> ? I
226 : C extends StyledComponent<infer I, any, any> ? I
227 : C;
228export type StyledComponentPropsWithRef<
229 C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
230> = C extends AnyStyledComponent ? React.ComponentPropsWithRef<StyledComponentInnerComponent<C>>
231 : React.ComponentPropsWithRef<C>;
232export type StyledComponentInnerOtherProps<C extends AnyStyledComponent> = C extends StyledComponent<
233 any,
234 any,
235 infer O,
236 any
237> ? O
238 : C extends StyledComponent<any, any, infer O> ? O
239 : never;
240export type StyledComponentInnerAttrs<C extends AnyStyledComponent> = C extends StyledComponent<any, any, any, infer A>
241 ? A
242 : never;
243
244export interface ThemedBaseStyledInterface<T extends object> extends ThemedStyledComponentFactories<T> {
245 <C extends AnyStyledComponent>(component: C): ThemedStyledFunction<
246 StyledComponentInnerComponent<C>,
247 T,
248 StyledComponentInnerOtherProps<C>,
249 StyledComponentInnerAttrs<C>
250 >;
251 <C extends keyof JSX.IntrinsicElements | React.ComponentType<any>>(
252 // unfortunately using a conditional type to validate that it can receive a `theme?: Theme`
253 // causes tests to fail in TS 3.1
254 component: C,
255 ): ThemedStyledFunction<C, T>;
256}
257
258export type ThemedStyledInterface<T extends object> = ThemedBaseStyledInterface<AnyIfEmpty<T>>;
259export type StyledInterface = ThemedStyledInterface<DefaultTheme>;
260
261export interface BaseThemedCssFunction<T extends object> {
262 (first: TemplateStringsArray | CSSObject, ...interpolations: SimpleInterpolation[]): FlattenSimpleInterpolation;
263 (
264 first: TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<{}, T>>,
265 ...interpolations: Array<Interpolation<ThemedStyledProps<{}, T>>>
266 ): FlattenInterpolation<ThemedStyledProps<{}, T>>;
267 <P extends object>(
268 first: TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<P, T>>,
269 ...interpolations: Array<Interpolation<ThemedStyledProps<P, T>>>
270 ): FlattenInterpolation<ThemedStyledProps<P, T>>;
271}
272
273export type ThemedCssFunction<T extends object> = BaseThemedCssFunction<AnyIfEmpty<T>>;
274
275// Helper type operators
276// Pick that distributes over union types
277export type PickU<T, K extends keyof T> = T extends any ? { [P in K]: T[P] } : never;
278export type OmitU<T, K extends keyof T> = T extends any ? PickU<T, Exclude<keyof T, K>> : never;
279type WithOptionalTheme<P extends { theme?: T | undefined }, T> = OmitU<P, "theme"> & {
280 theme?: T | undefined;
281};
282type AnyIfEmpty<T extends object> = keyof T extends never ? any : T;
283
284export interface ThemedStyledComponentsModule<T extends object, U extends object = T> {
285 default: ThemedStyledInterface<T>;
286
287 css: ThemedCssFunction<T>;
288
289 // unfortunately keyframes can't interpolate props from the theme
290 keyframes: (strings: TemplateStringsArray | CSSKeyframes, ...interpolations: SimpleInterpolation[]) => Keyframes;
291
292 createGlobalStyle: <P extends object = {}>(
293 first: TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<P, T>>,
294 ...interpolations: Array<Interpolation<ThemedStyledProps<P, T>>>
295 ) => GlobalStyleComponent<P, T>;
296
297 withTheme: BaseWithThemeFnInterface<T>;
298 ThemeProvider: BaseThemeProviderComponent<T, U>;
299 ThemeConsumer: React.Consumer<T>;
300 ThemeContext: React.Context<T>;
301 useTheme(): T;
302
303 // This could be made to assert `target is StyledComponent<any, T>` instead, but that feels not type safe
304 isStyledComponent: typeof isStyledComponent;
305
306 ServerStyleSheet: typeof ServerStyleSheet;
307 StyleSheetManager: typeof StyleSheetManager;
308}
309
310declare const styled: StyledInterface;
311
312export const css: ThemedCssFunction<DefaultTheme>;
313
314export type BaseWithThemeFnInterface<T extends object> = <C extends React.ComponentType<any>>(
315 // this check is roundabout because the extends clause above would
316 // not allow any component that accepts _more_ than theme as a prop
317 component: React.ComponentProps<C> extends { theme?: T | undefined } ? C : never,
318) => React.ForwardRefExoticComponent<
319 WithOptionalTheme<JSX.LibraryManagedAttributes<C, React.ComponentPropsWithRef<C>>, T>
320>;
321export type WithThemeFnInterface<T extends object> = BaseWithThemeFnInterface<AnyIfEmpty<T>>;
322export const withTheme: WithThemeFnInterface<DefaultTheme>;
323
324export function useTheme(): DefaultTheme;
325
326/**
327 * This interface can be augmented by users to add types to `styled-components`' default theme
328 * without needing to reexport `ThemedStyledComponentsModule`.
329 */
330// Unfortunately, there is no way to write tests for this
331// as any augmentation will break the tests for the default case (not augmented).
332// eslint-disable-next-line @typescript-eslint/no-empty-interface
333export interface DefaultTheme {}
334
335export interface ThemeProviderProps<T extends object, U extends object = T> {
336 children?: React.ReactNode | undefined;
337 theme: T | ((theme: U) => T);
338}
339export type BaseThemeProviderComponent<T extends object, U extends object = T> = React.ComponentClass<
340 ThemeProviderProps<T, U>
341>;
342export type ThemeProviderComponent<T extends object, U extends object = T> = BaseThemeProviderComponent<
343 AnyIfEmpty<T>,
344 AnyIfEmpty<U>
345>;
346export const ThemeProvider: ThemeProviderComponent<AnyIfEmpty<DefaultTheme>>;
347// NOTE: this technically starts as undefined, but allowing undefined is unhelpful when used correctly
348export const ThemeContext: React.Context<AnyIfEmpty<DefaultTheme>>;
349export const ThemeConsumer: typeof ThemeContext["Consumer"];
350
351export interface Keyframes {
352 getName(): string;
353}
354
355export function keyframes(
356 strings: TemplateStringsArray | CSSKeyframes,
357 ...interpolations: SimpleInterpolation[]
358): Keyframes;
359
360export function createGlobalStyle<P extends object = {}>(
361 first: TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<P, DefaultTheme>>,
362 ...interpolations: Array<Interpolation<ThemedStyledProps<P, DefaultTheme>>>
363): GlobalStyleComponent<P, DefaultTheme>;
364
365export function isStyledComponent(target: any): target is StyledComponent<any, any>;
366
367export class ServerStyleSheet {
368 collectStyles(tree: React.ReactNode): React.ReactElement<{ sheet: ServerStyleSheet }>;
369
370 getStyleTags(): string;
371 getStyleElement(): Array<React.ReactElement<{}>>;
372 interleaveWithNodeStream(readableStream: NodeJS.ReadableStream): NodeJS.ReadableStream;
373 readonly instance: this;
374 seal(): void;
375 clearTag(): void;
376}
377
378export type StylisPlugin = (
379 context: number,
380 selector: string[],
381 parent: string[],
382 content: string,
383 line: number,
384 column: number,
385 length: number,
386 // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
387) => string | void;
388
389export interface StyleSheetManagerProps {
390 children?: React.ReactNode;
391 disableCSSOMInjection?: boolean | undefined;
392 disableVendorPrefixes?: boolean | undefined;
393 stylisPlugins?: StylisPlugin[] | undefined;
394 sheet?: ServerStyleSheet | undefined;
395 target?: HTMLElement | ShadowRoot | undefined;
396}
397
398export class StyleSheetManager extends React.Component<StyleSheetManagerProps> {}
399
400/**
401 * The CSS prop is not declared by default in the types as it would cause 'css' to be present
402 * on the types of anything that uses styled-components indirectly, even if they do not use the
403 * babel plugin.
404 *
405 * You can load a default declaration by using writing this special import from
406 * a typescript file. This module does not exist in reality, which is why the {} is important:
407 *
408 * ```ts
409 * import {} from 'styled-components/cssprop'
410 * ```
411 *
412 * Or you can declare your own module augmentation, which allows you to specify the type of Theme:
413 *
414 * ```ts
415 * import { CSSProp } from 'styled-components'
416 *
417 * interface MyTheme {}
418 *
419 * declare module 'react' {
420 * interface Attributes {
421 * css?: CSSProp<MyTheme>
422 * }
423 * }
424 * ```
425 */
426// ONLY string literals and inline invocations of css`` are supported, anything else crashes the plugin
427export type CSSProp<T = AnyIfEmpty<DefaultTheme>> = string | CSSObject | FlattenInterpolation<ThemeProps<T>>;
428
429export default styled;