From f66b4e9a3f135b5674fb0f6b2f7c401bf6e67ace Mon Sep 17 00:00:00 2001 From: Eric Elliott Date: Thu, 27 Jul 2023 18:01:13 -0700 Subject: [PATCH 1/6] Update no-explicit-any.md Fix potentially misleading statement about explicit `any` - which is sometimes required for functional code. Provide an example of when explicit `any` may be needed, and how to disable the rule on an as-needed basis. --- .../docs/rules/no-explicit-any.md | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index efec50113734..467481c2ad97 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -6,8 +6,8 @@ description: 'Disallow the `any` type.' > > See **https://typescript-eslint.io/rules/no-explicit-any** for documentation. -The `any` type in TypeScript is a dangerous "escape hatch" from the type system. -Using `any` disables many type checking rules and is generally best used only as a last resort or when prototyping code. +The `any` type in TypeScript is a potentially dangerous "escape hatch" from the type system. +Using `any` disables many type checking rules and is generally best used only when it's required or when prototyping code. This rule reports on explicit uses of the `any` keyword as a type annotation. > TypeScript's `--noImplicitAny` compiler option prevents an implied `any`, but doesn't prevent `any` from being explicitly used the way this rule does. @@ -158,7 +158,24 @@ interface Garply { ## When Not To Use It -If an unknown type or a library without typings is used +**Higher Order Functions**. If you're typing a higher order function such as `compose`, `pipe`, etc, you may need `any` because TypeScript types are not fully co-expressive with idiomatic functional JavaScript. Such functions are intentionally generic, and you can assign explicit types later to the returned functions, e.g.: + +```TypeScript +// eslint-disable-next-line no-explicit-any +type a2a = (x: any) => any; +type compose = (...fns: a2a[]) => a2a; +const pipe: compose = (...fns) => x => fns.reduce((y, f) => f(y), x); +const compose: compose = (...fns) => x => fns.reduceRight((y, f) => f(y), x); + +type n2n = (n: number) => number; +const g: n2n = n => n + 1; +const f: n2n = n => n * 2; + +const h: n2n = pipe(g, f); +const j: n2n = compose(f, g); +``` + +**Unknown Types**. If an unknown type or a library without typings is used and you want to be able to specify `any`. ## Related To From 2960616177a8f1a059ddd04855e3447c6aaec312 Mon Sep 17 00:00:00 2001 From: Eric Elliott Date: Fri, 28 Jul 2023 10:40:12 -0700 Subject: [PATCH 2/6] Update no-explicit-any.md --- packages/eslint-plugin/docs/rules/no-explicit-any.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index 467481c2ad97..c4454d461881 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -7,7 +7,7 @@ description: 'Disallow the `any` type.' > See **https://typescript-eslint.io/rules/no-explicit-any** for documentation. The `any` type in TypeScript is a potentially dangerous "escape hatch" from the type system. -Using `any` disables many type checking rules and is generally best used only when it's required or when prototyping code. +Using `any` disables many type checking rules and is generally best used only as a last resort or when prototyping code. This rule reports on explicit uses of the `any` keyword as a type annotation. > TypeScript's `--noImplicitAny` compiler option prevents an implied `any`, but doesn't prevent `any` from being explicitly used the way this rule does. From fb7adc9fc8e2827798275f07b176cfbc5ce1ab1e Mon Sep 17 00:00:00 2001 From: Eric Elliott Date: Fri, 28 Jul 2023 10:47:57 -0700 Subject: [PATCH 3/6] Update no-explicit-any.md Clarify the need for `any` by making use of `compose` and `pipe` to compose functions with mismatched type signatures. --- .../eslint-plugin/docs/rules/no-explicit-any.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index c4454d461881..731348fc512a 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -158,21 +158,23 @@ interface Garply { ## When Not To Use It -**Higher Order Functions**. If you're typing a higher order function such as `compose`, `pipe`, etc, you may need `any` because TypeScript types are not fully co-expressive with idiomatic functional JavaScript. Such functions are intentionally generic, and you can assign explicit types later to the returned functions, e.g.: +**Higher Order Functions**. If you're typing a higher order function such as `compose`, `pipe`, etc, you may need `any` because TypeScript types can't always fully represent functional JavaScript patterns. For example, functions like `compose` and `pipe` compose many different functions with many different types which TypeScript can't accurately represent. Instead, you can assign explicit types later to the returned functions, e.g.: ```TypeScript -// eslint-disable-next-line no-explicit-any +// eslint-disable no-explicit-any type a2a = (x: any) => any; -type compose = (...fns: a2a[]) => a2a; -const pipe: compose = (...fns) => x => fns.reduce((y, f) => f(y), x); -const compose: compose = (...fns) => x => fns.reduceRight((y, f) => f(y), x); +const pipe = (...fns: a2a[]) => (x: any) => fns.reduce((y, f) => f(y), x); +const compose = (...fns: a2a[]) => (x: any) => fns.reduceRight((y, f) => f(y), x); +// eslint-enable no-explicit-any type n2n = (n: number) => number; const g: n2n = n => n + 1; const f: n2n = n => n * 2; +type n2s = (n: number) => string; +const exclaim:n2s = (n) => `${n}!`; -const h: n2n = pipe(g, f); -const j: n2n = compose(f, g); +const h: n2s = pipe(g, f, exclaim); +const j: n2s = compose(exclaim, f, g); ``` **Unknown Types**. If an unknown type or a library without typings is used From 71bcdd946c5c2aa18ccf9138f62b76cd751a196a Mon Sep 17 00:00:00 2001 From: Eric Elliott Date: Fri, 28 Jul 2023 11:08:54 -0700 Subject: [PATCH 4/6] Update no-explicit-any.md Improve wording for the compose/pipe example. --- packages/eslint-plugin/docs/rules/no-explicit-any.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index 731348fc512a..d0663619aaa2 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -158,7 +158,8 @@ interface Garply { ## When Not To Use It -**Higher Order Functions**. If you're typing a higher order function such as `compose`, `pipe`, etc, you may need `any` because TypeScript types can't always fully represent functional JavaScript patterns. For example, functions like `compose` and `pipe` compose many different functions with many different types which TypeScript can't accurately represent. Instead, you can assign explicit types later to the returned functions, e.g.: +**Difficult-to-represent TypeScript types**. +Some code patterns can be difficult to represent exactly in the TypeScript type system, and/or expose legitimate edge cases for using `any`. For example, functional programming concepts such as composing and piping sometimes necessitate using `any`. ```TypeScript // eslint-disable no-explicit-any From 30eabba1a264cc3349d631df290f2184938f4695 Mon Sep 17 00:00:00 2001 From: Eric Elliott Date: Sat, 29 Jul 2023 20:27:02 -0700 Subject: [PATCH 5/6] Update packages/eslint-plugin/docs/rules/no-explicit-any.md Co-authored-by: Joshua Chen --- packages/eslint-plugin/docs/rules/no-explicit-any.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index d0663619aaa2..fc7ee2fca6e1 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -159,7 +159,7 @@ interface Garply { ## When Not To Use It **Difficult-to-represent TypeScript types**. -Some code patterns can be difficult to represent exactly in the TypeScript type system, and/or expose legitimate edge cases for using `any`. For example, functional programming concepts such as composing and piping sometimes necessitate using `any`. +Some code patterns can be difficult to represent exactly in the TypeScript type system. For example, functional programming concepts such as composing and piping sometimes necessitate using `any`. ```TypeScript // eslint-disable no-explicit-any From 4907378defeea1e21c5f74535679851582824500 Mon Sep 17 00:00:00 2001 From: Eric Elliott Date: Sat, 29 Jul 2023 20:27:28 -0700 Subject: [PATCH 6/6] Update packages/eslint-plugin/docs/rules/no-explicit-any.md Co-authored-by: Joshua Chen --- packages/eslint-plugin/docs/rules/no-explicit-any.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index fc7ee2fca6e1..693700d13912 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -161,7 +161,7 @@ interface Garply { **Difficult-to-represent TypeScript types**. Some code patterns can be difficult to represent exactly in the TypeScript type system. For example, functional programming concepts such as composing and piping sometimes necessitate using `any`. -```TypeScript +```ts // eslint-disable no-explicit-any type a2a = (x: any) => any; const pipe = (...fns: a2a[]) => (x: any) => fns.reduce((y, f) => f(y), x);