Got a handful of lint errors in a project to resolve. This would be an interesting JS best practice learning experience.

@typescript-eslint/no-this-alias

Origintal code

1
2
3
4
5
6
7
8
9
10
componentDidMount() {
let my = this
this.timeHandle = setTimeout(() => {
my.setState(prev => {
const state = {...prev}
state.timeSwitch = true
return state
})
}, this.props.timeLimitInSeconds * 1000)
}

Why this is an issue

Assigning a variable to this instead of properly using arrow lambdas may be a symptom of pre-ES6 practices or not managing scope well.

Fix

Use () => arrow lambdas, as they preserve this scope for you:

1
2
3
4
5
6
7
8
9
componentDidMount() {
this.timeHandle = setTimeout(() => {
this.setState(prev => {
const state = {...prev}
state.timeSwitch = true
return state
})
}, this.props.timeLimitInSeconds * 1000)
}

react/jsx-no-target-blank

Using target=_blank links with no rel=noreferrer attribute is a security hazard in older browsers.

@typescript-eslint/ban-types

{} type

This comment gives a clear explanation of why disallowing {} is a rule default.

The type {} doesn’t mean “any empty object”, it means “any non-nullish value”.
Unfortunately, there’s no type in TS that means “an empty object”.

See the link for the alternative (type EmptyObject = Record<string, never>) and the safe use case of {} (intersection type; as in React type Props={})

@typescript-eslint/no-namespace

Custom TypeScript modules (module foo {}) and namespaces (namespace foo {}) are considered outdated ways to organize TypeScript code. ES2015 module syntax is now preferred (import/export).

In this project, namespace is used to organise some constants:

1
2
3
4
5
6
// constants.ts

export namespace PageName {
export const Loading = 'Loading';
export const InitialAuthorization = 'InitialAuthorization'
}

So I just need to replace it with an object:

1
2
3
4
5
6
// constants.ts

export const PageName = {
Loading: 'Loading',
InitialAuthorization: 'InitialAuthorization'
}