New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enforce default parameters to be last (default-param-last) #1414
Comments
Would be nice to confirm that our tested-against users have some default parameters. |
Only 1 failing repo. This will ship in standard 16! |
Whoever dropped this issue later, I've got problem on this because I am using redux and order of arguments matter on reducers, this is very common reducer I am using currently and violation of the export function reducer (state = [], action) {...} in order to disable only this example from my "overrides": [
{
"files": [
"./src/reducers/**/*.js"
],
"rules": {
"default-param-last" : "off"
}
}
] |
I agree with @Kjaer that this flies in the face of many accepted patterns. This was a bad call. Having default values indicates more than just optionality. It is also a signal to developers and tooling of the expected type. It assumes too much that an argument with a default value is simply optional. I strongly urge that this be removed as part of Standardjs. |
@Kjaer How do you call the reducer? Can you share some examples? Am I correct in assuming that you should always call it with two arguments? In which case, why are you using a default argument?
Which tooling works this way? |
@feross unfortunately it's not about how I call reducers, It's about how Redux as a lib wants me write the reducers. https://redux.js.org/api/combinereducers#reducerstodosjs You can check Redux's combineReducers test in order to confirm the order of arguments matter https://github.com/reduxjs/redux/blob/master/test/combineReducers.spec.ts#L14 It's common (maybe best) practice to assign default values to |
Oh totally, I understand that the order of arguments will matter to Redux. My question was would you ever invoke a reducer without any arguments, because this is the only circumstance in which the first default argument would take effect. For example, you could take this: export default function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([action.text])
default:
return state
}
} And you could rewrite it as: export default function todos(state, action) {
... There's no need to re-order the arguments. You can just remove the default argument. Unless you or Redux itself is calling If that is the case, then you'd need to rewrite it as: export default function todos(state = [], action = undefined) {
... Which I agree is not ideal. If this is the case, then I'm sympathetic to disabling this rule. |
When redux initializes it does call all reducers without a state... It's common to create reducers with initial state as
When using Duck Bundles
Redux's // redux/modules/counter.js
export default (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
} // redux/modules/index.js
import { combineReducers } from 'redux'
import counter from '@redux/modules/counter'
// .. more imports
export default combineReducers({
counter
// .. more reducers
}) // redux/configureStore.js
import { createStore } from 'redux'
import rootReducer from '@redux/modules'
export default (preloadedState) => createStore(rootReducer, preloadedState) // src/index.js
// react imports
import configureStore from '@redux/configureStore.js'
const preloadedState = window.__PRELOADED_STATE__ || {}
const store = configureStore(preloadedState)
//
ReactDOM.render(...)
// ... This rule would enforce dropping the convenience of having that default parameter, but to be fair when dealing with SSR preloadedState hydrating the is required // constants
const CHANGE_VIEWPORT = '.../viewport/CHANGE_VIEWPORT'
// action creators
export const changeViewport = payload => ({
type: CHANGE_VIEWPORT,
payload: payload
})
// reducer
const initialState = {
hydrated: false,
height: null,
width: null
}
export default (state, action) => {
if (!state || !state.hydrated) {
state = {
...initialState,
...state,
hydrated: true
}
}
switch (action.type) {
case CHANGE_VIEWPORT:
return {
...state,
...action.payload
}
default:
return state
}
} Sorry for the long code examples. |
My opinion is that this rule is way too opinionated to be set as a default. I just ran it against a Redux based project and got around 200 errors. There's just too many cases where you'd like to set defaults to a parameter at the head like: const defaultPosition = { x: 0, y: 0 }
const addPosition = (position = defaultPosition, options) => {} Adding EditFurthermore, this is very problematic if you introduce defaults to an already existing API. It would force you to either opt out from the rule on every case or do a far larger refactor. |
I'm now leaning toward disabling this rule. @standard/team Do you have any feedback before I do that? |
As it's not a syntax error or a major stylistic problem, it seems arbitrary, so I would lean strongly towards disabling. I can also think of plenty of cases like the above ones where argument order is not in control of the user, but default parameters are useful, and this rule would just get in the way of people getting the job done. |
I am in agreement with @feross, +1 to disable. |
Keen to disable - this rule doesn't currently work well with callback style functions:
|
Released as 16.0.3. |
https://eslint.org/docs/rules/default-param-last
Putting default parameter at last allows function calls to omit optional tail arguments.
Rule Details
This rule enforces default parameters to be the last of parameters.
Examples of incorrect code for this rule:
Examples of correct code for this rule:
The text was updated successfully, but these errors were encountered: