Skip to content

Commit e0666be

Browse files
committed
feat: add basic flow types for css and styled tags
Now the result of the `css` tag will always be of the type string, and the result of the `styled.x` or `styled(x)` tag will be `React.ComponentType`. If the `styled(x)` tag wraps another component, the type of the props will also include the type from that component. Limitations: - It's not possible to type-check the interpolations currently. I have added annotations for them, but they don't work. - It doesn't handle `defaultProps` property on the styled component, will look into it in future. - The type annotations for tags (e.g. - `styled.div`) are broad, but React DOM [doesn't seem to type it either](https://github.com/facebook/flow/blob/master/lib/react-dom.js#L406).
1 parent b5c37ec commit e0666be

File tree

2 files changed

+36
-10
lines changed

2 files changed

+36
-10
lines changed

src/core/css.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
/* @flow */
2+
13
function css() {
24
throw new Error(
35
'Using the "css" tag in runtime is not supported. Make sure you have set up the Babel plugin correctly.'
46
);
57
}
68

79
module.exports = css;
10+
11+
/* ::
12+
declare module.exports: (string[], Array<string | number | {}>) => string;
13+
*/

src/react/styled.js

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1+
/* @flow */
2+
13
const React = require('react'); // eslint-disable-line import/no-extraneous-dependencies
24

3-
function styled(tag) {
4-
return options => {
5+
/* ::
6+
type Options = {
7+
name: string,
8+
class: string,
9+
vars?: { [string]: [string | number | ((props: *) => string | number), string | void] }
10+
}
11+
*/
12+
13+
function styled(tag /* : React.ComponentType<*> | string */) {
14+
return (options /* : Options */) => {
515
if (process.env.NODE_ENV !== 'production') {
616
if (Array.isArray(options)) {
717
// We received a strings array since it's used as a tag
@@ -11,20 +21,23 @@ function styled(tag) {
1121
}
1222
}
1323

24+
/* $FlowFixMe: Flow doesn't know about forwardRef */
1425
const Result = React.forwardRef((props, ref) => {
15-
const { as: component, ...rest } = props;
26+
const { as: component = tag, ...rest } = props;
1627
const next = Object.assign(rest, {
1728
ref,
1829
className: props.className
1930
? `${options.class} ${props.className}`
2031
: options.class,
2132
});
2233

23-
if (options.vars) {
34+
const { vars } = options;
35+
36+
if (vars) {
2437
const style = {};
2538

26-
Object.keys(options.vars).forEach(name => {
27-
const [value, unit = ''] = options.vars[name];
39+
Object.keys(vars).forEach(name => {
40+
const [value, unit = ''] = vars[name];
2841
style[`--${name}`] = `${
2942
typeof value === 'function' ? value(props) : value
3043
}${unit}`;
@@ -40,10 +53,6 @@ function styled(tag) {
4053
Result.className = options.class;
4154
Result.extends = tag;
4255

43-
Result.defaultProps = {
44-
as: tag,
45-
};
46-
4756
return Result;
4857
};
4958
}
@@ -57,3 +66,14 @@ if (process.env.NODE_ENV !== 'production') {
5766
} else {
5867
module.exports = styled;
5968
}
69+
70+
/* ::
71+
type StyledComponent<T> = React.ComponentType<T & { as?: React$ElementType }>;
72+
73+
type StyledTag<T> = (string[], Array<string | number | {} | (T => string | number)>) => StyledComponent<T>;
74+
75+
declare module.exports: {|
76+
<T>(T): StyledTag<React.ElementConfig<T>>,
77+
[string]: StyledTag<{ children?: React.Node, [key: string]: any }>,
78+
|};
79+
*/

0 commit comments

Comments
 (0)