# @typescript-eslint/prefer-nullish-coalescing

> Require `??` instead of `||` or a ternary to give a default for `null` or `undefined`

`port || 3000` falls back to `3000` for every falsy value, so a port of `0` is replaced, and so are `""` and `false`. `port ?? 3000` only falls back when `port` is `null` or `undefined`.

`||` and `||=` are reported when the left side's type includes `null` or `undefined`. A ternary or an `if` that does the job of `??` or `??=` by hand is reported too.

`--fix` doesn't change these. Look at each one before you change it, because `??` keeps `0`, `""`, and `false` where `||` replaced them.

This rule needs `strictNullChecks` (or `strict`) in your `tsconfig.json`.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. This rule needs types, so turning it on makes `bun lint` type check your code first.

```toml bunfig.toml
[lint.rules]
"@typescript-eslint/prefer-nullish-coalescing" = "error" # or "warn"
```

Every option, set to its default:

```toml bunfig.toml
[lint.rules]
"@typescript-eslint/prefer-nullish-coalescing" = ["error", {
  ignoreConditionalTests = true,
  ignoreTernaryTests = false,
  ignoreIfStatements = false,
  ignoreMixedLogicalExpressions = false,
  ignoreBooleanCoercion = false,
  ignorePrimitives = {
    bigint = false,
    boolean = false,
    number = false,
    string = false,
  },
  allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing = false,
}]
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad {"count": 4} */}
```ts
function connect(options: { port?: number; host: string | null; name?: string; tags?: string[] }) {
  const port = options.port || 3000;
  const host = options.host !== null ? options.host : "localhost";
  options.name ||= "default";
  if (!options.tags) {
    options.tags = [];
  }
}
```

Not reported:

{/* good */}
```ts
function connect(options: { port?: number; host: string | null; name?: string; tags?: string[] }) {
  const port = options.port ?? 3000;
  const host = options.host ?? "localhost";
  options.name ??= "default";
  options.tags ??= [];
}

function label(text: string) {
  return text || "untitled"; // never null or undefined
}
```

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `ignoreConditionalTests` | `true` | Allow `\|\|` in the test of an `if`, a loop, or a ternary, where only true or false matters. |
| `ignoreTernaryTests` | `false` | Don't report ternaries. |
| `ignoreIfStatements` | `false` | Don't report `if` statements. |
| `ignoreMixedLogicalExpressions` | `false` | Allow `\|\|` in an expression that also has `&&`. |
| `ignoreBooleanCoercion` | `false` | Allow `\|\|` inside a `Boolean(...)` call. |
| `ignorePrimitives` | `{}` | Allow `\|\|` when the left side can be one of these: `{ string, number, boolean, bigint }`, each `true` or `false`. `true` means all four. |
| `allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing` | `false` | Without `strictNullChecks`, the rule can't tell what can be `null`, and it reports that once for each file. Set this to `true` to turn that report off. |

The test of an `if` is allowed by default:

{/* good */}
```ts
function show(title: string | undefined, subtitle: string) {
  if (title || subtitle) {
    console.log(title, subtitle);
  }
}
```

With `ignoreConditionalTests: false` it's reported:

{/* bad {"options": [{"ignoreConditionalTests": false}]} */}
```ts
function show(title: string | undefined, subtitle: string) {
  if (title || subtitle) {
    console.log(title, subtitle);
  }
}
```

Use `ignorePrimitives: { string: true }` if you want an empty string to get the default too:

{/* good {"options": [{"ignorePrimitives": {"string": true}}]} */}
```ts
function greet(name: string | undefined) {
  return "Hello, " + (name || "stranger");
}
```

A number is still reported with that setting:

{/* bad {"options": [{"ignorePrimitives": {"string": true}}]} */}
```ts
function retries(count: number | undefined) {
  return count || 3;
}
```

`ignoreMixedLogicalExpressions` allows the first line, and `ignoreBooleanCoercion` allows the second:

{/* good {"options": [{"ignoreMixedLogicalExpressions": true, "ignoreBooleanCoercion": true}]} */}
```ts
function ready(user: { name: string } | null, guest: { name: string } | null, open: boolean) {
  const allowed = user || (guest && open);
  return Boolean(user || guest) && allowed;
}
```
