Skip to content

Commit

Permalink
Enable @typescript-eslint/no-unnecessary-condition
Browse files Browse the repository at this point in the history
Workarounds:

- `false as boolean` to avoid TypeScript saying something is `false`
  (never `true`) where it doesn’t know that mutation elsewhere can set
  it back to `true`.
- Ignore “unnecessary” `switch` on unions with only one variant – so
  far.
- Ignore places where I do weird gymnastics with untrusted objects
  (where the types are more constrained than reality).
  • Loading branch information
lydell committed Oct 17, 2024
1 parent 271953c commit 622b843
Show file tree
Hide file tree
Showing 11 changed files with 26 additions and 14 deletions.
3 changes: 3 additions & 0 deletions client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
// Support Web Workers, where `window` does not exist.
const window = globalThis as unknown as Window;

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const IS_WEB_WORKER = window.window === undefined;

// These used to be separate properties on `window`, like
Expand Down Expand Up @@ -159,6 +160,7 @@ const DEFAULT_ELM_WATCH: __ELM_WATCH = {

let { __ELM_WATCH } = window;

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (typeof __ELM_WATCH !== "object" || __ELM_WATCH === null) {
// Each property is added later below.
__ELM_WATCH = {} as unknown as __ELM_WATCH;
Expand All @@ -168,6 +170,7 @@ if (typeof __ELM_WATCH !== "object" || __ELM_WATCH === null) {
}

for (const [key, value] of Object.entries(DEFAULT_ELM_WATCH)) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (__ELM_WATCH[key as keyof __ELM_WATCH] === undefined) {
(__ELM_WATCH as Record<string, unknown>)[key] = value;
}
Expand Down
1 change: 1 addition & 0 deletions client/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ error.elmWatchProxy = true;

const existing = window.Elm;
const existingObject =
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
typeof existing === "object" && existing !== null ? existing : undefined;

const elmProxy = new Proxy(existingObject ?? {}, {
Expand Down
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export default typescriptEslint.config(
"@typescript-eslint/no-shadow": error,
"@typescript-eslint/no-this-alias": warn,
"@typescript-eslint/no-unnecessary-boolean-literal-compare": warn,
"@typescript-eslint/no-unnecessary-condition": error,
"@typescript-eslint/no-unnecessary-parameter-property-assignment": warn,
"@typescript-eslint/no-unnecessary-template-expression": error,
"@typescript-eslint/no-unnecessary-type-arguments": warn,
Expand Down
7 changes: 3 additions & 4 deletions src/Compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function installDependencies(
);

// Avoid printing `loadingMessage` if there’s nothing to download.
let didWriteLoadingMessage = false;
let didWriteLoadingMessage = false as boolean;
const timeoutId = setTimeout(() => {
logger.write(loadingMessage);
didWriteLoadingMessage = true;
Expand Down Expand Up @@ -691,7 +691,7 @@ async function compileOneOutput({

// Watcher events that happen while waiting for `elm make` and
// postprocessing can flip `dirty` back to `true`.
outputState.dirty = false;
outputState.dirty = false as boolean;

const { promise, kill } = SpawnElm.make({
elmJsonPath,
Expand Down Expand Up @@ -1630,8 +1630,7 @@ function targetNameEmojiTweak(
return { targetName, delta: 0 };
}

/* v8 ignore next */
const content = match[0] ?? "";
const content = match[0];

// Avoid emoji on Windows, for example.
if (!loggerConfig.fancy) {
Expand Down
1 change: 1 addition & 0 deletions src/Errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,7 @@ ${text(errorFilePath.content)}

function printUnknownValueAsString(value: UnknownValueAsString): Piece {
switch (value.tag) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
case "UnknownValueAsString":
return text(value.value);
}
Expand Down
1 change: 1 addition & 0 deletions src/Hot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,7 @@ const runCmd =
// Retry writing it.
writeElmWatchStuffJson(mutable);
// If still an error, print it.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (mutable.elmWatchStuffJsonWriteError !== undefined) {
logger.write("");
logger.errorTemplate(
Expand Down
1 change: 1 addition & 0 deletions src/Postprocess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ class PostprocessWorker {

this.worker.on("message", (message: MessageFromWorker) => {
switch (message.tag) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
case "PostprocessDone":
switch (this.status.tag) {
/* v8 ignore start */
Expand Down
1 change: 1 addition & 0 deletions src/PostprocessWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function main(port: PortWrapper): void {

port.on("message", (message: MessageToWorker) => {
switch (message.tag) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
case "StartPostprocess":
elmWatchNode(message.args)
.then((result) => {
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export async function elmWatchCli(
);
} while (result.tag === "Restart");
switch (result.tag) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
case "Exit":
return result.exitCode;
}
Expand Down Expand Up @@ -126,6 +127,7 @@ if (require.main === module) {
// happens it should at least be possible to exit with a simple ctrl+c.
// Note: `.setRawMode` is `undefined` when stdin is not a TTY, but this is
// not reflected in the type definitions.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (process.stdin.setRawMode !== undefined) {
process.stdin.setRawMode(false);
}
Expand Down
1 change: 1 addition & 0 deletions tests/Errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1713,6 +1713,7 @@ describe("errors", () => {
encoding: "utf8",
},
);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!(result.error === undefined || result.error === null)) {
throw result.error;
}
Expand Down
21 changes: 11 additions & 10 deletions tests/HotHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const hotKillManager: HotKillManager = { kill: undefined };
export async function cleanupAfterEachTest(): Promise<void> {
const { currentTestName } = expect.getState();

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (window.__ELM_WATCH?.KILL_MATCHING !== undefined) {
// The idea is that we need no logging here – it’ll just result in double
// logging since there will most likely be a running server as well.
Expand Down Expand Up @@ -528,7 +529,7 @@ export function collapseUi(targetName?: string): void {

function expandUiHelper(wantExpanded: boolean, targetName?: string): void {
withShadowRoot((shadowRoot) => {
const button = shadowRoot?.querySelector(
const button = shadowRoot.querySelector(
`${
targetName === undefined
? "[data-target]"
Expand All @@ -547,7 +548,7 @@ function expandUiHelper(wantExpanded: boolean, targetName?: string): void {

export function showErrors(targetName?: string): void {
withShadowRoot((shadowRoot) => {
const button = shadowRoot?.querySelector(
const button = shadowRoot.querySelector(
`${
targetName === undefined
? "[data-target]"
Expand All @@ -564,7 +565,7 @@ export function showErrors(targetName?: string): void {

export function hideErrors(targetName?: string): void {
withShadowRoot((shadowRoot) => {
const button = shadowRoot?.querySelector(
const button = shadowRoot.querySelector(
`${
targetName === undefined
? "[data-target]"
Expand All @@ -581,7 +582,7 @@ export function hideErrors(targetName?: string): void {

export function closeOverlay(): void {
withShadowRoot((shadowRoot) => {
const button = shadowRoot?.querySelector(
const button = shadowRoot.querySelector(
`[data-test-id="OverlayCloseButton"]`,
);
if (button instanceof HTMLElement) {
Expand All @@ -595,7 +596,7 @@ export function closeOverlay(): void {
export function getOverlay(): string {
let result = "(Overlay not found)";
withShadowRoot((shadowRoot) => {
const overlay = shadowRoot?.querySelector(`[data-test-id="Overlay"]`);
const overlay = shadowRoot.querySelector(`[data-test-id="Overlay"]`);
if (overlay instanceof HTMLElement) {
const children = Array.from(overlay.children, (child, index) => {
const clone = child.cloneNode(true) as HTMLElement;
Expand All @@ -617,7 +618,7 @@ export function getOverlay(): string {

export function clickFirstErrorLocation(): void {
withShadowRoot((shadowRoot) => {
const button = shadowRoot?.querySelector(`[data-test-id="Overlay"] button`);
const button = shadowRoot.querySelector(`[data-test-id="Overlay"] button`);
if (button instanceof HTMLButtonElement) {
button.click();
} else {
Expand All @@ -629,7 +630,7 @@ export function clickFirstErrorLocation(): void {
export function moveUi(position: BrowserUiPosition): void {
expandUi();
withShadowRoot((shadowRoot) => {
const button = shadowRoot?.querySelector(
const button = shadowRoot.querySelector(
`button[data-position="${position}"]`,
);
if (button instanceof HTMLButtonElement) {
Expand All @@ -643,7 +644,7 @@ export function moveUi(position: BrowserUiPosition): void {
export function switchCompilationMode(compilationMode: CompilationMode): void {
expandUi();
withShadowRoot((shadowRoot) => {
const radio = shadowRoot?.querySelector(
const radio = shadowRoot.querySelector(
`input[type="radio"][value="${compilationMode}"]`,
);
if (radio instanceof HTMLInputElement) {
Expand All @@ -657,7 +658,7 @@ export function switchCompilationMode(compilationMode: CompilationMode): void {
export function assertCompilationMode(compilationMode: CompilationMode): void {
expandUi();
withShadowRoot((shadowRoot) => {
const radio = shadowRoot?.querySelector(`input[type="radio"]:checked`);
const radio = shadowRoot.querySelector(`input[type="radio"]:checked`);
if (radio instanceof HTMLInputElement) {
expect(radio.value).toStrictEqual(compilationMode);
} else {
Expand All @@ -671,7 +672,7 @@ export function assertCompilationMode(compilationMode: CompilationMode): void {
export function assertDebugDisabled(): void {
expandUi();
withShadowRoot((shadowRoot) => {
const radio = shadowRoot?.querySelector('input[type="radio"]');
const radio = shadowRoot.querySelector('input[type="radio"]');
if (radio instanceof HTMLInputElement) {
expect(radio.disabled).toBe(true);
} else {
Expand Down

0 comments on commit 622b843

Please sign in to comment.