UNPKG

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