UNPKG

@types/styled-components

Version:
431 lines (370 loc) 17.4 kB
// forward declarations declare global { namespace NodeJS { // eslint-disable-next-line @typescript-eslint/no-empty-interface interface ReadableStream {} } // eslint-disable-next-line @typescript-eslint/no-empty-interface interface ShadowRoot {} } import * as CSS from "csstype"; import hoistNonReactStatics = require("hoist-non-react-statics"); import * as React from "react"; export type CSSProperties = CSS.Properties<string | number>; export type CSSPseudos = { [K in CSS.Pseudos]?: CSSObject }; export interface CSSObject extends CSSProperties, CSSPseudos { [key: string]: CSSObject | string | number | undefined; } export type CSSKeyframes = object & { [key: string]: CSSObject }; export interface ThemeProps<T> { theme: T; } export type ThemedStyledProps<P, T> = P & ThemeProps<T>; export type StyledProps<P> = ThemedStyledProps<P, AnyIfEmpty<DefaultTheme>>; export type IntrinsicElementsKeys = keyof React.JSX.IntrinsicElements; // Any prop that has a default prop becomes optional, but its type is unchanged // Undeclared default props are augmented into the resulting allowable attributes // If declared props have indexed properties, ignore default props entirely as keyof gets widened // Wrap in an outer-level conditional type to allow distribution over props that are unions type Defaultize<P, D> = P extends any ? string extends keyof P ? P : & PickU<P, Exclude<keyof P, keyof D>> & Partial<PickU<P, Extract<keyof P, keyof D>>> & Partial<PickU<D, Exclude<keyof D, keyof P>>> : never; type ReactDefaultizedProps<C, P> = C extends { defaultProps: infer D } ? Defaultize<P, D> : P; type MakeAttrsOptional< C extends string | React.ComponentType<any>, O extends object, A extends keyof P, P = React.ComponentPropsWithRef<C extends IntrinsicElementsKeys | React.ComponentType<any> ? C : never>, > = // Distribute unions early to avoid quadratic expansion P extends any ? OmitU<ReactDefaultizedProps<C, P> & O, A> & Partial<PickU<P & O, A>> : never; export type StyledComponentProps< // The Component from whose props are derived C extends string | React.ComponentType<any>, // The Theme from the current context T extends object, // The other props added by the template O extends object, // The props that are made optional by .attrs A extends keyof any, // The Component passed with "forwardedAs" prop FAsC extends string | React.ComponentType<any> = C, > = // Distribute O if O is a union type O extends object ? WithOptionalTheme< MakeAttrsOptional<C, O, A> & MakeAttrsOptional<FAsC, O, A>, T > : never; type StyledComponentPropsWithAs< C extends string | React.ComponentType<any>, T extends object, O extends object, A extends keyof any, AsC extends string | React.ComponentType<any> = C, FAsC extends string | React.ComponentType<any> = C, > = StyledComponentProps<C, T, O, A, FAsC> & { as?: AsC | undefined; forwardedAs?: FAsC | undefined }; export type FalseyValue = undefined | null | false; export type Interpolation<P> = InterpolationValue | InterpolationFunction<P> | FlattenInterpolation<P>; // cannot be made a self-referential interface, breaks WithPropNested // see https://github.com/microsoft/TypeScript/issues/34796 export type FlattenInterpolation<P> = ReadonlyArray<Interpolation<P>>; export type InterpolationValue = string | number | FalseyValue | Keyframes | StyledComponentInterpolation | CSSObject; export type SimpleInterpolation = InterpolationValue | FlattenSimpleInterpolation; export type FlattenSimpleInterpolation = readonly SimpleInterpolation[]; export type InterpolationFunction<P> = (props: P) => Interpolation<P>; type Attrs<P, A extends Partial<P>, T> = ((props: ThemedStyledProps<P, T>) => A) | A; export type ThemedGlobalStyledClassProps<P extends { theme?: T | undefined }, T> = WithOptionalTheme<P, T> & { suppressMultiMountWarning?: boolean | undefined; }; export interface GlobalStyleComponent<P extends { theme?: T | undefined }, T> extends React.ComponentClass<ThemedGlobalStyledClassProps<P, T>> {} // remove the call signature from StyledComponent so Interpolation can still infer InterpolationFunction type StyledComponentInterpolation = | PickU<StyledComponentBase<any, any, any, any>, keyof StyledComponentBase<any, any>> | PickU<StyledComponentBase<any, any, any>, keyof StyledComponentBase<any, any>>; // abuse Pick to strip the call signature from ForwardRefExoticComponent type ForwardRefExoticBase<P> = PickU<React.ForwardRefExoticComponent<P>, keyof React.ForwardRefExoticComponent<any>>; // Config to be used with withConfig export interface StyledConfig<O extends object = {}> { // TODO: Add all types from the original StyledComponentWrapperProperties componentId?: string; displayName?: string; shouldForwardProp?: ((prop: keyof O, defaultValidatorFn: (prop: keyof O) => boolean) => boolean) | undefined; } // extracts React defaultProps type ReactDefaultProps<C> = C extends { defaultProps: infer D } ? D : never; // any doesn't count as assignable to never in the extends clause, and we default A to never export type AnyStyledComponent = StyledComponent<any, any, any, any> | StyledComponent<any, any, any>; export type StyledComponent< C extends keyof React.JSX.IntrinsicElements | React.ComponentType<any>, T extends object, O extends object = {}, A extends keyof any = never, > = // the "string" allows this to be used as an object key // I really want to avoid this if possible but it's the only way to use nesting with object styles... & string & StyledComponentBase<C, T, O, A> & hoistNonReactStatics.NonReactStatics<C extends React.ComponentType<any> ? C : never>; export interface StyledComponentBase< C extends string | React.ComponentType<any>, T extends object, O extends object = {}, A extends keyof any = never, > extends ForwardRefExoticBase<StyledComponentProps<C, T, O, A>> { // add our own fake call signature to implement the polymorphic 'as' prop ( props: StyledComponentProps<C, T, O, A> & { as?: never | undefined; forwardedAs?: never | undefined }, ): React.ReactElement< StyledComponentProps<C, T, O, A> >; <AsC extends string | React.ComponentType<any> = C, FAsC extends string | React.ComponentType<any> = AsC>( props: StyledComponentPropsWithAs<AsC, T, O, A, AsC, FAsC>, ): React.ReactElement<StyledComponentPropsWithAs<AsC, T, O, A, AsC, FAsC>>; withComponent<WithC extends AnyStyledComponent>( component: WithC, ): StyledComponent< StyledComponentInnerComponent<WithC>, T, O & StyledComponentInnerOtherProps<WithC>, A | StyledComponentInnerAttrs<WithC> >; withComponent<WithC extends keyof React.JSX.IntrinsicElements | React.ComponentType<any>>( component: WithC, ): StyledComponent<WithC, T, O, A>; } export interface ThemedStyledFunctionBase< C extends keyof React.JSX.IntrinsicElements | React.ComponentType<any>, T extends object, O extends object = {}, A extends keyof any = never, > { (first: TemplateStringsArray): StyledComponent<C, T, O, A>; ( first: | TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<StyledComponentPropsWithRef<C> & O, T>>, ...rest: Array<Interpolation<ThemedStyledProps<StyledComponentPropsWithRef<C> & O, T>>> ): StyledComponent<C, T, O, A>; <U extends object>( first: | TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<StyledComponentPropsWithRef<C> & O & U, T>>, ...rest: Array<Interpolation<ThemedStyledProps<StyledComponentPropsWithRef<C> & O & U, T>>> ): StyledComponent<C, T, O & U, A>; } export interface ThemedStyledFunction< C extends keyof React.JSX.IntrinsicElements | React.ComponentType<any>, T extends object, O extends object = {}, A extends keyof any = never, > extends ThemedStyledFunctionBase<C, T, O, A> { // Fun thing: 'attrs' can also provide a polymorphic 'as' prop // My head already hurts enough so maybe later... attrs< U, NewA extends Partial<StyledComponentPropsWithRef<C> & U> & { [others: string]: any; } = {}, >( attrs: Attrs<StyledComponentPropsWithRef<C> & U, NewA, T>, ): ThemedStyledFunction<C, T, O & NewA, A | keyof NewA>; withConfig: <Props extends O = O>( config: StyledConfig<StyledComponentPropsWithRef<C> & Props>, ) => ThemedStyledFunction<C, T, Props, A>; } export type StyledFunction<C extends keyof React.JSX.IntrinsicElements | React.ComponentType<any>> = ThemedStyledFunction< C, any >; type ThemedStyledComponentFactories<T extends object> = { [TTag in keyof React.JSX.IntrinsicElements]: ThemedStyledFunction<TTag, T>; }; export type StyledComponentInnerComponent<C extends React.ComponentType<any>> = C extends StyledComponent< infer I, any, any, any > ? I : C extends StyledComponent<infer I, any, any> ? I : C; export type StyledComponentPropsWithRef< C extends keyof React.JSX.IntrinsicElements | React.ComponentType<any>, > = C extends AnyStyledComponent ? React.ComponentPropsWithRef<StyledComponentInnerComponent<C>> : React.ComponentPropsWithRef<C>; export type StyledComponentInnerOtherProps<C extends AnyStyledComponent> = C extends StyledComponent< any, any, infer O, any > ? O : C extends StyledComponent<any, any, infer O> ? O : never; export type StyledComponentInnerAttrs<C extends AnyStyledComponent> = C extends StyledComponent<any, any, any, infer A> ? A : never; export interface ThemedBaseStyledInterface<T extends object> extends ThemedStyledComponentFactories<T> { <C extends AnyStyledComponent>(component: C): ThemedStyledFunction< StyledComponentInnerComponent<C>, T, StyledComponentInnerOtherProps<C>, StyledComponentInnerAttrs<C> >; <C extends keyof React.JSX.IntrinsicElements | 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>; } export type ThemedStyledInterface<T extends object> = ThemedBaseStyledInterface<AnyIfEmpty<T>>; export type StyledInterface = ThemedStyledInterface<DefaultTheme>; export interface BaseThemedCssFunction<T extends object> { (first: TemplateStringsArray | CSSObject, ...interpolations: SimpleInterpolation[]): FlattenSimpleInterpolation; ( first: TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<{}, T>>, ...interpolations: Array<Interpolation<ThemedStyledProps<{}, T>>> ): FlattenInterpolation<ThemedStyledProps<{}, T>>; <P extends object>( first: TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<P, T>>, ...interpolations: Array<Interpolation<ThemedStyledProps<P, T>>> ): FlattenInterpolation<ThemedStyledProps<P, T>>; } export type ThemedCssFunction<T extends object> = BaseThemedCssFunction<AnyIfEmpty<T>>; // Helper type operators // Pick that distributes over union types export type PickU<T, K extends keyof T> = T extends any ? { [P in K]: T[P] } : never; export type OmitU<T, K extends keyof T> = T extends any ? PickU<T, Exclude<keyof T, K>> : never; type WithOptionalTheme<P extends { theme?: T | undefined }, T> = OmitU<P, "theme"> & { theme?: T | undefined; }; type AnyIfEmpty<T extends object> = keyof T extends never ? any : T; export interface ThemedStyledComponentsModule<T extends object, U extends object = T> { default: ThemedStyledInterface<T>; css: ThemedCssFunction<T>; // unfortunately keyframes can't interpolate props from the theme keyframes: (strings: TemplateStringsArray | CSSKeyframes, ...interpolations: SimpleInterpolation[]) => Keyframes; createGlobalStyle: <P extends object = {}>( first: TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<P, T>>, ...interpolations: Array<Interpolation<ThemedStyledProps<P, T>>> ) => GlobalStyleComponent<P, T>; withTheme: BaseWithThemeFnInterface<T>; ThemeProvider: BaseThemeProviderComponent<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; ServerStyleSheet: typeof ServerStyleSheet; StyleSheetManager: typeof StyleSheetManager; } declare const styled: StyledInterface; export const css: ThemedCssFunction<DefaultTheme>; export type BaseWithThemeFnInterface<T extends object> = <C extends React.ComponentType<any>>( // this check is roundabout because the extends clause above would // not allow any component that accepts _more_ than theme as a prop component: React.ComponentProps<C> extends { theme?: T | undefined } ? C : never, ) => React.ForwardRefExoticComponent< WithOptionalTheme<React.JSX.LibraryManagedAttributes<C, React.ComponentPropsWithRef<C>>, T> >; export type WithThemeFnInterface<T extends object> = BaseWithThemeFnInterface<AnyIfEmpty<T>>; export const withTheme: WithThemeFnInterface<DefaultTheme>; export function useTheme(): DefaultTheme; /** * This interface can be augmented by users to add types to `styled-components`' default theme * without needing to reexport `ThemedStyledComponentsModule`. */ // Unfortunately, there is no way to write tests for this // as any augmentation will break the tests for the default case (not augmented). // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface DefaultTheme {} export interface ThemeProviderProps<T extends object, U extends object = T> { children?: React.ReactNode | undefined; theme: T | ((theme: U) => T); } export type BaseThemeProviderComponent<T extends object, U extends object = T> = React.ComponentClass< ThemeProviderProps<T, U> >; export type ThemeProviderComponent<T extends object, U extends object = T> = BaseThemeProviderComponent< AnyIfEmpty<T>, AnyIfEmpty<U> >; export const ThemeProvider: ThemeProviderComponent<AnyIfEmpty<DefaultTheme>>; // NOTE: this technically starts as undefined, but allowing undefined is unhelpful when used correctly export const ThemeContext: React.Context<AnyIfEmpty<DefaultTheme>>; export const ThemeConsumer: typeof ThemeContext["Consumer"]; export interface Keyframes { getName(): string; } export function keyframes( strings: TemplateStringsArray | CSSKeyframes, ...interpolations: SimpleInterpolation[] ): Keyframes; export function createGlobalStyle<P extends object = {}>( first: TemplateStringsArray | CSSObject | InterpolationFunction<ThemedStyledProps<P, DefaultTheme>>, ...interpolations: Array<Interpolation<ThemedStyledProps<P, DefaultTheme>>> ): GlobalStyleComponent<P, DefaultTheme>; export function isStyledComponent(target: any): target is StyledComponent<any, any>; export class ServerStyleSheet { collectStyles(tree: React.ReactNode): React.ReactElement<{ sheet: ServerStyleSheet }>; getStyleTags(): string; getStyleElement(): Array<React.ReactElement<{}>>; interleaveWithNodeStream(readableStream: NodeJS.ReadableStream): NodeJS.ReadableStream; readonly instance: this; seal(): void; clearTag(): void; } export type StylisPlugin = ( context: number, selector: string[], parent: string[], content: string, line: number, column: number, length: number, // eslint-disable-next-line @typescript-eslint/no-invalid-void-type ) => string | void; export interface StyleSheetManagerProps { children?: React.ReactNode; disableCSSOMInjection?: boolean | undefined; disableVendorPrefixes?: boolean | undefined; stylisPlugins?: StylisPlugin[] | undefined; sheet?: ServerStyleSheet | undefined; target?: HTMLElement | ShadowRoot | undefined; } export class StyleSheetManager extends React.Component<StyleSheetManagerProps> {} /** * The CSS prop is not declared by default in the types as it would cause 'css' to be present * on the types of anything that uses styled-components indirectly, even if they do not use the * babel plugin. * * You can load a default declaration by using writing this special import from * a typescript file. This module does not exist in reality, which is why the {} is important: * * ```ts * import {} from 'styled-components/cssprop' * ``` * * Or you can declare your own module augmentation, which allows you to specify the type of Theme: * * ```ts * import { CSSProp } from 'styled-components' * * interface MyTheme {} * * declare module 'react' { * interface Attributes { * css?: CSSProp<MyTheme> * } * } * ``` */ // ONLY string literals and inline invocations of css`` are supported, anything else crashes the plugin export type CSSProp<T = AnyIfEmpty<DefaultTheme>> = string | CSSObject | FlattenInterpolation<ThemeProps<T>>; export default styled;