https://github.com/sbdchd/tslint-cake
:cake: TSLint rules for sweet code
https://github.com/sbdchd/tslint-cake
tslint typescript
Last synced: about 2 months ago
JSON representation
:cake: TSLint rules for sweet code
- Host: GitHub
- URL: https://github.com/sbdchd/tslint-cake
- Owner: sbdchd
- Created: 2019-01-18T03:47:31.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2019-03-21T14:26:44.000Z (about 7 years ago)
- Last Synced: 2025-01-02T02:29:15.142Z (over 1 year ago)
- Topics: tslint, typescript
- Language: TypeScript
- Homepage:
- Size: 75.2 KB
- Stars: 0
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# tslint-cake [](https://www.npmjs.com/package/tslint-cake) [](https://circleci.com/gh/sbdchd/tslint-cake)
> TSLint rules for sweet code
## Usage
1. Install
```shell
yarn add tslint-cake
```
2. Update `tslint.json`
```json
{
"extends": ["tslint-cake"],
"rules": {
"react-prefer-simple-fragment": true
// ...
}
}
```
## Why?
To have a place to add miscellaneous TSLint rules that don't exist in TSLint
or common TSLint libraries.
## Rules
### `no-pointless-computed-property-name`
Use `{ foo: bar }` instead of `{ ["foo"]: bar }`
### `react-prefer-simple-fragment` [Fixer]
Use `<>>` instead of ``
### `jsx-no-true-attribute` [Fixer]
Use `` instead of ``
### `no-template-string-cast`
Prefer `String()` or `.toString()` to cast as a string instead of `` `${}` ``.
### `no-pointless-case-scope`
Remove unnecessary scopes in `switch` statement `case`s when the only child
expression is a `return` statement.
E.g.,
```typescript
switch (foo) {
case bar: {
return "foo"
}
}
// can become
switch (foo) {
case bar:
return "foo"
}
```
### `no-name-never`
Using a variable `name` with type `never` is likely a mistake.
`name` is defined globally if you include `--lib dom`.
see:
### `improper-map-prefer-foreach`
Prefer `forEach` instead of `map` when the result isn't used
```typescript
foo.map(x => {
x.id = 10
})
// should be
foo.forEach(x => {
x.id = 10
})
```
### `no-promise-catch`
Using `.catch()` on a `Promise` usually means that you could better describe
the outputs of the async function using a union or `Result` types.
```typescript
declare const getFooAsync: () => Promise
getFooAsync()
.then(r => console.log(r))
.catch(e => console.error(e)) // `e` could be anything. We can't type the arg to catch.
// instead we can do the following
declare const getBarAsync: () => Promise
getBarAsync().then(r => {
if (r instanceof Error) {
console.error(r)
} else {
console.log(r)
}
})
```
### `object-index-must-return-possibly-undefined`
The values of an index signature of a type are always possibly `undefined`
even though TypeScript won't warn you. This lint forces you to define your
index signature to possibly return `undefined`.
```typescript
interface IFoo {
[key: string]: number // Error: Value of an object key is possibly undefined.
}
interface IBar {
[key: string]: number | undefined // ok
}
```
### `exact-object-spread`
This rule is an attempt at gaining some semblence of
[exactness](https://github.com/Microsoft/TypeScript/issues/12936) with object
spread.
Currently, there are cases where TypeScript won't warn about adding extra,
non-existing properties to an object when spreading. This lint fills in some
of those gaps and warns you when adding non-existent properties.
Note, this rule attempts to enforce
[exactness](https://flow.org/en/docs/types/objects/#exact-object-types) on
all spreads and this might not be what you want.
```typescript
interface IState {
id: number
name: string
address: {
street: string
state: string
country: string
}
}
function update(state: IState): IState {
return {
...state,
notProp: false // TypeScript error
}
}
// TypeScript will also warn with nested spreading
function update(state: IState): IState {
return {
...state,
address: {
...state.address,
notProp: false // TypeScript error
}
}
}
// However, if we pull the nested spread out into a variable TypeScript won't
// warn us about extra properties
// no errors with TypeScript
function update(state: IState): IState {
const address = {
// TSLint error when we enable this rule
...state.address,
foo: "bar"
}
return {
...state,
address
}
}
```
### `react-memo-requires-custom-compare`
When using [`React.memo()`](https://reactjs.org/docs/react-api.html#reactmemo) or [`extends React.PureComponent`](https://reactjs.org/docs/react-api.html#reactpurecomponent) the default
comparsions are shallow which means they will always render for complex props
like `Date`'s, `Array`s, or `Object`s, even if the underlying values are equivalent.
In the cases of these complex props, this lint will warn you and recommend
passing a custom compare function `React.memo()` or defining a custom
`shouldComponentUpdate` and extending `React.Component`.
**Caveat:** If an object is passed as a prop and isn't copied/changed, i.e., no
`{...x}` then referential integrity is retained and the shallow compare of
`React.memo()` and `PureComponent` will correctly prevent a render. So if you
are using something like
[Immutable-js](https://github.com/immutable-js/immutable-js) where shallow
equals is maintained then this lint might be less helpful.
```typescript
interface IOkayProps {
name: string
accountAge: number | string
admin: boolean
}
const Okay = React.memo((props: IOkayProps) => (
{props.name} ({props.accountAge})
))
interface IBadProps {
user: {
name: string
}
}
// TSLint raises error
const Bad = React.memo((props: IBadProps) =>
{props.user.name}
)
// TSLint raises error
class BadPure extends React.PureComponent {
render() {
return
{props.user.name}
}
}
```
### `no-implicit-to-string`
Checks for cases where `null`, `undefined`, or `object` are converted to
`string`.
```typescript
const userName: string | null | Date = null
// all of the following error
const foo = `hello ${userName}`
const bar = String(userName)
const blah = "hello " + userName
```
## Dev
```shell
yarn build
yarn test
yarn lint
yarn fmt
yarn publish
```
## TODO
- add fixers