Skip to content

Commit

Permalink
Merge 99cea84 into c234d0f
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Wullems committed Jan 11, 2020
2 parents c234d0f + 99cea84 commit 13f29ad
Show file tree
Hide file tree
Showing 5 changed files with 1,142 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -12,6 +12,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
* [`jsx-props-no-spreading`][]: add `explicitSpread` option to allow explicit spread of props ([#2449][] @pawelnvk)
* [`jsx-no-target-blank`][]: warn on `target={'_blank'}` expressions ([#2451][] @timkraut)
* [`require-default-props`]: add option to ignore functional components ([#2532][] @RedTn)
* [`function-component-definition`]: Enforce a specific function type for function components ([#2414][] @Stefanwullems)

### Fixed
* [`sort-prop-types`][], [`jsx-sort-default-props`][]: disable broken autofix ([#2505][] @webOS101)
Expand Down Expand Up @@ -56,6 +57,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
[#2443]: https://github.com/yannickcr/eslint-plugin-react/pull/2443
[#2438]: https://github.com/yannickcr/eslint-plugin-react/pull/2438
[#2436]: https://github.com/yannickcr/eslint-plugin-react/pull/2436
[#2414]: https://github.com/yannickcr/eslint-plugin-react/pull/2414
[#2273]: https://github.com/yannickcr/eslint-plugin-react/pull/2273

## [7.16.0] - 2019-10-04
Expand Down Expand Up @@ -2811,3 +2813,4 @@ If you're still not using React 15 you can keep the old behavior by setting the
[`jsx-no-useless-fragment`]: docs/rules/jsx-no-useless-fragment.md
[`jsx-no-script-url`]: docs/rules/jsx-no-script-url.md
[`no-adjacent-inline-elements`]: docs/rules/no-adjacent-inline-elements.md
[`function-component-definition`]: docs/rules/function-component-definition.md
254 changes: 254 additions & 0 deletions docs/rules/function-component-definition.md
@@ -0,0 +1,254 @@
# Enforce a specific function type for function components (react/function-component-definition)

This option enforces a specific function type for function components.

**Fixable:** This rule is automatically fixable using the `--fix` flag on the command line.

## Rule Details

This rule is aimed to enforce consistent function types for function components. By default it prefers function declarations for named components and function expressions for unnamed components.

The following patterns are considered warnings:

```jsx
// function expression for named component
var Component = function (props) {
return <div>{props.content}</div>;
};

// arrow function for named component
var Component = (props) => {
return <div>{props.content}</div>;
};

// arrow function for unnamed component
function getComponent() {
return (props) => {
return <div>{props.content}</div>;
};
}
```

## Rule Options

This rule takes an options object as a second parameter where the preferred function type for components can be specified. The first property of the options object is `"namedComponents"` which can be `"function-declaration"`, `"function-expression"`, or `"arrow-function"` and has `'function-declaration'` as its default. The second property is `"unnamedComponents"` that can be either `"function-expression"` or `"arrow-function"`, and has `'function-expression'` as its default.

```js
...
"react/function-component-definition": [<enabled>, {
"namedComponents": "function-declaration" | "function-expression" | "arrow-function",
"unnamedComponents": "function-expression" | "arrow-function"
}]
...
```

The following patterns are considered warnings:

```jsx
// only function declarations for named components
// [2, { "namedComponents": "function-declaration" }]
var Component = function (props) {
return <div />;
};

var Component = (props) => {
return <div />;
};

// only function expressions for named components
// [2, { "namedComponents": "function-expression" }]
function Component (props) {
return <div />;
};

var Component = (props) => {
return <div />;
};

// only arrow functions for named components
// [2, { "namedComponents": "arrow-function" }]
function Component (props) {
return <div />;
};

var Component = function (props) {
return <div />;
};

// only function expressions for unnamed components
// [2, { "unnamedComponents": "function-expression" }]
function getComponent () {
return (props) => {
return <div />;
};
}

// only arrow functions for unnamed components
// [2, { "unnamedComponents": "arrow-function" }]
function getComponent () {
return (props) => {
return <div />;
};
}

```

The following patterns are **not** warnings:

```jsx

// only function declarations for named components
// [2, { "namedComponents": "function-declaration" }]
function Component (props) {
return <div />;
}

// only function expressions for named components
// [2, { "namedComponents": "function-expression" }]
var Component = function (props) {
return <div />;
};

// only arrow functions for named components
// [2, { "namedComponents": "arrow-function" }]
var Component = (props) => {
return <div />;
};

// only function expressions for unnamed components
// [2, { "unnamedComponents": "function-expression" }]
function getComponent () {
return (props) => {
return <div />;
};
}

// only arrow functions for unnamed components
// [2, { "unnamedComponents": "arrow-function" }]
function getComponent () {
return (props) => {
return <div />;
};
}

```

## Unfixable patterns

There is one unfixable pattern in JavaScript.

It has to do with the fact that this is valid syntax:

```js
export default function getComponent () {
return <div />;
}
```

While these are not:

```js
export default var getComponent = () => {
return <div />;
}

export default var getComponent = function () {
return <div />;
}
```

These patterns have to be manually fixed.

## Heads up, TypeScript users

Note that the autofixer is somewhat constrained for TypeScript users.

The following patterns can **not** be autofixed in TypeScript:

```tsx
// function expressions and arrow functions that have type annotations cannot be autofixed to function declarations
// [2, { "namedComponents": "function-declaration" }]
var Component: React.FC<Props> = function (props) {
return <div />;
};

var Component: React.FC<Props> = (props) => {
return <div />;
};

// function components with one unconstrained type parameter cannot be autofixed to arrow functions because the syntax conflicts with jsx
// [2, { "namedComponents": "arrow-function" }]
function Component<T>(props: Props<T>) {
return <div />;
};

var Component = function <T>(props: Props<T>) {
return <div />;
};

// [2, { "unnamedComponents": "arrow-function" }]
function getComponent() {
return function <T>(props: Props<T>) => {
return <div />;
}
}
```

Type parameters do not produce syntax conflicts if either there are multiple type parameters or, if there is only one constrained type parameter.

The following patterns can be autofixed in TypeScript:

```tsx
// autofix to function expression with type annotation
// [2, { "namedComponents": "function-expression" }]
var Component: React.FC<Props> = (props) => {
return <div />;
};

// autofix to arrow function with type annotation
// [2, { "namedComponents": "function-expression" }]
var Component: React.FC<Props> = function (props) {
return <div />;
};

// autofix to named arrow function with one constrained type parameter
// [2, { "namedComponents": "arrow-function" }]
function Component<T extends {}>(props: Props<T>) {
return <div />;
}

var Component = function <T extends {}>(props: Props<T>) {
return <div />;
};

// autofix to named arrow function with multiple type parameters
// [2, { "namedComponents": "arrow-function" }]
function Component<T1, T2>(props: Props<T1, T2>) {
return <div />;
}

var Component = function <T1, T2>(props: Props<T2>) {
return <div />;
};

// autofix to unnamed arrow function with one constrained type parameter
// [2, { "unnamedComponents": "arrow-function" }]
function getComponent() {
return function <T extends {}> (props: Props<T>) => {
return <div />;
};
}

// autofix to unnamed arrow function with multiple type parameters
// [2, { "unnamedComponents": "arrow-function" }]
function getComponent() {
return function <T1, T2>(props: Props<T1, T2>) => {
return <div />;
}
}

```

## When not to use

If you are not interested in consistent types of function components.
1 change: 1 addition & 0 deletions index.js
Expand Up @@ -15,6 +15,7 @@ const allRules = {
'forbid-elements': require('./lib/rules/forbid-elements'),
'forbid-foreign-prop-types': require('./lib/rules/forbid-foreign-prop-types'),
'forbid-prop-types': require('./lib/rules/forbid-prop-types'),
'function-component-definition': require('./lib/rules/function-component-definition'),
'jsx-boolean-value': require('./lib/rules/jsx-boolean-value'),
'jsx-child-element-spacing': require('./lib/rules/jsx-child-element-spacing'),
'jsx-closing-bracket-location': require('./lib/rules/jsx-closing-bracket-location'),
Expand Down

0 comments on commit 13f29ad

Please sign in to comment.