Skip to content

docs: add dedicated TypeOrValueSpecifier docs page #9875

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@
"words": [
"Airbnb",
"Airbnb's",
"ambiently",
"allowdefaultproject",
"allowdefaultprojectforfiles",
"allowforknownsafecalls",
"allowforknownsafepromises",
"ambiently",
"Arka",
"Armano",
Expand Down Expand Up @@ -102,6 +103,7 @@
"estree",
"extrafileextensions",
"falsiness",
"filespecifier",
"fisker",
"García",
"globby",
Expand All @@ -115,6 +117,7 @@
"joshuakgoldberg",
"Katt",
"kirkwaiblinger",
"libspecifier",
"linebreaks",
"Lundberg",
"lzstring",
Expand All @@ -140,6 +143,7 @@
"OOM",
"OOMs",
"oxlint",
"packagespecifier",
"parameterised",
"performant",
"pluggable",
Expand Down
135 changes: 135 additions & 0 deletions docs/packages/type-utils/TypeOrValueSpecifier.mdx
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
---
id: type-or-value-specifier
title: TypeOrValueSpecifier
---

Some lint rules include options to describe specific _types_ and/or _values_.
These options use a standardized format exported from the `type-utils` package, **`TypeOrValueSpecifier`**.

`TypeOrValueSpecifier` allows three object forms of specifiers:

- [`FileSpecifier`](#filespecifier): for types or values declared in local files
- [`LibSpecifier`](#libspecifier): for types or values declared in TypeScript's built-in lib definitions
- [`PackageSpecifier`](#packagespecifier): for types or values imported from packages

For example, the following configuration of [`@typescript-eslint/no-floating-promises` > `allowForKnownSafeCalls`](/rules/no-floating-promises#allowforknownsafecalls) marks `node:test`'s `it` as safe using a package specifier:

```json
{
"@typescript-eslint/no-floating-promises": [
"error",
{
"allowForKnownSafeCalls": [
{ "from": "package", "name": "it", "package": "node:test" }
]
}
]
}
```

Each object format requires at least:

- `from`: which specifier to use, as `'file' | 'lib' | 'package'`
- `name`: a `string` or `string[]` for type or value name(s) to match on

## FileSpecifier

```ts
interface FileSpecifier {
from: 'file';
name: string[] | string;
path?: string;
}
```

Describes specific types or values declared in local files.

`path` may be used to specify a file the types or values must be declared in.
If omitted, all files will be matched.

### FileSpecifier Examples

Matching all types and values named `Props`:

```json
{ "from": "file", "name": "Props" }
```

Matching all types and values named `Props` in `file.tsx`:

```json
{ "from": "file", "name": "Props", "path": "file.tsx" }
```

## LibSpecifier

```ts
interface LibSpecifier {
from: 'lib';
name: string[] | string;
}
```

Describes specific types or values declared in TypeScript's built-in `lib.*.d.ts` ("lib") types.

Lib types include `lib.dom.d.ts` globals such as `Window` and `lib.es*.ts` globals such as `Array`.

### LibSpecifier Examples

Matching all array-typed values:

```json
{ "from": "lib", "name": "Array" }
```

Matching all `Promise` and `PromiseLike`-typed values:

```json
{ "from": "lib", "name": ["Promise", "PromiseLike"] }
```

## PackageSpecifier

```ts
interface PackageSpecifier {
from: 'package';
name: string[] | string;
package: string;
}
```

Describes specific types or values imported from packages.

`package` must be used to specify the package name.

### PackageSpecifier Examples

Matching the `SafePromise` type from `@reduxjs/toolkit`:

```json
{ "from": "package", "name": "SafePromise", "package": "@reduxjs/toolkit" }
```

Matching the `describe`, `it`, and `test` values from `vitest`:

```json
{ "from": "package", "name": ["describe", "it", "test"], "package": "vitest" }
```

## Universal String Specifiers

`TypeOrValueSpecifier` also allows providing a plain string specifier to match all names regardless of declaration source.
For example, providing `"RegExp"` matches _all_ types and values named `RegExp`.

:::danger
We strongly recommend not using universal string specifiers.
Matching _all_ names without specifying a source file, library, or package can accidentally match other types or values with a coincidentally similar name.

Universal string specifiers will be removed in a future major version of typescript-eslint.
:::

## Rule Options Using This Format

- [`@typescript-eslint/no-floating-promises` > `allowForKnownSafeCalls`](/rules/no-floating-promises#allowforknownsafecalls)
- [`@typescript-eslint/no-floating-promises` > `allowForKnownSafePromises`](/rules/no-floating-promises#allowforknownsafepromises)
- [`@typescript-eslint/prefer-readonly-parameter-types` > `allow`](/rules/prefer-readonly-parameter-types/#allow)
13 changes: 4 additions & 9 deletions packages/eslint-plugin/docs/rules/no-floating-promises.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,9 @@ await (async function () {

### `allowForKnownSafePromises`

This option allows marking specific types as "safe" to be floating. For example, you may need to do this in the case of libraries whose APIs return Promises whose rejections are safely handled by the library.
Specific types to be marked as "safe" to be floating. For example, you may need to do this in the case of libraries whose APIs return Promises whose rejections are safely handled by the library.

This option takes an array of type specifiers to consider safe.
Each item in the array must have one of the following forms:

- A type defined in a file (`{ from: "file", name: "Foo", path: "src/foo-file.ts" }` with `path` being an optional path relative to the project root directory)
- A type from the default library (`{ from: "lib", name: "PromiseLike" }`)
- A type from a package (`{ from: "package", name: "Foo", package: "foo-lib" }`, this also works for types defined in a typings package).
This option takes the shared [`TypeOrValueSpecifier` format](/packages/type-utils/type-or-value-specifier).

Examples of code for this rule with:

Expand Down Expand Up @@ -223,10 +218,10 @@ returnsSafePromise();

### `allowForKnownSafeCalls`

This option allows marking specific functions as "safe" to be called to create floating Promises.
Specific functions to be marked as "safe" to be called to create floating Promises.
For example, you may need to do this in the case of libraries whose APIs may be called without handling the resultant Promises.

This option takes the same array format as [`allowForKnownSafePromises`](#allowForKnownSafePromises).
This option takes the shared [`TypeOrValueSpecifier` format](/packages/type-utils/type-or-value-specifier).

Examples of code for this rule with:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,20 +143,13 @@ interface Foo {
An array of type specifiers to ignore.
Some complex types cannot easily be made readonly, for example the `HTMLElement` type or the `JQueryStatic` type from `@types/jquery`. This option allows you to globally disable reporting of such types.

Each item in the array must have one of the following forms:

- A type defined in a file (`{ from: "file", name: "Foo", path: "src/foo-file.ts" }` with `path` being an optional path relative to the project root directory)
- A type from the default library (`{ from: "lib", name: "Foo" }`)
- A type from a package (`{ from: "package", name: "Foo", package: "foo-lib" }`, this also works for types defined in a typings package).

Additionally, a type may be defined just as a simple string, which then matches the type independently of its origin.
This option takes the shared [`TypeOrValueSpecifier` format](/packages/type-utils/type-or-value-specifier).

Examples of code for this rule with:

```json
{
"allow": [
"$",
{ "from": "file", "name": "Foo" },
{ "from": "lib", "name": "HTMLElement" },
{ "from": "package", "name": "Bar", "package": "bar-lib" }
Expand All @@ -167,7 +160,7 @@ Examples of code for this rule with:
<Tabs>
<TabItem value="❌ Incorrect">

```ts option='{"allow":["$",{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
```ts option='{"allow":[{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
interface ThisIsMutable {
prop: string;
}
Expand All @@ -191,7 +184,7 @@ function fn2(arg: Wrapper) {}
function fn3(arg: WrapperWithOther) {}
```

```ts option='{"allow":["$",{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
```ts option='{"allow":[{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
import { Foo } from 'some-lib';
import { Bar } from 'incorrect-lib';

Expand All @@ -212,7 +205,7 @@ function fn3(arg: Bar) {}
</TabItem>
<TabItem value="✅ Correct">

```ts option='{"allow":["$",{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
```ts option='{"allow":[{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
interface Foo {
prop: string;
}
Expand All @@ -229,7 +222,7 @@ function fn1(arg: Foo) {}
function fn2(arg: Wrapper) {}
```

```ts option='{"allow":["$",{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
```ts option='{"allow":[{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
import { Bar } from 'bar-lib';

interface Foo {
Expand All @@ -246,7 +239,7 @@ function fn2(arg: HTMLElement) {}
function fn3(arg: Bar) {}
```

```ts option='{"allow":["$",{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
```ts option='{"allow":[{"from":"file","name":"Foo"},{"from":"lib","name":"HTMLElement"},{"from":"package","name":"Bar","package":"bar-lib"}]}'
import { Foo } from './foo';

// Works because Foo is still a local type - it has to be in the same package
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions packages/eslint-plugin/tests/rules/no-floating-promises.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,20 @@ promise().then(() => {});
},
],
},
{
code: `
import { it } from 'node:test';

it('...', () => {});
`,
options: [
{
allowForKnownSafeCalls: [
{ from: 'package', name: 'it', package: 'node:test' },
],
},
],
},
{
code: `
interface SafePromise<T> extends Promise<T> {
Expand Down
36 changes: 36 additions & 0 deletions packages/type-utils/src/TypeOrValueSpecifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,59 @@ import { typeDeclaredInFile } from './typeOrValueSpecifiers/typeDeclaredInFile';
import { typeDeclaredInLib } from './typeOrValueSpecifiers/typeDeclaredInLib';
import { typeDeclaredInPackageDeclarationFile } from './typeOrValueSpecifiers/typeDeclaredInPackageDeclarationFile';

/**
* Describes specific types or values declared in local files.
* See [TypeOrValueSpecifier > FileSpecifier](/packages/type-utils/type-or-value-specifier#filespecifier).
*/
export interface FileSpecifier {
from: 'file';

/**
* Type or value name(s) to match on.
*/
name: string[] | string;

/**
* A specific file the types or values must be declared in.
*/
path?: string;
}

/**
* Describes specific types or values declared in TypeScript's built-in lib definitions.
* See [TypeOrValueSpecifier > LibSpecifier](/packages/type-utils/type-or-value-specifier#libspecifier).
*/
export interface LibSpecifier {
from: 'lib';

/**
* Type or value name(s) to match on.
*/
name: string[] | string;
}

/**
* Describes specific types or values imported from packages.
* See [TypeOrValueSpecifier > PackageSpecifier](/packages/type-utils/type-or-value-specifier#packagespecifier).
*/
export interface PackageSpecifier {
from: 'package';

/**
* Type or value name(s) to match on.
*/
name: string[] | string;

/**
* Package name the type or value must be declared in.
*/
package: string;
}

/**
* A centralized format for rule options to describe specific _types_ and/or _values_.
* See [TypeOrValueSpecifier](/packages/type-utils/type-or-value-specifier).
*/
export type TypeOrValueSpecifier =
| FileSpecifier
| LibSpecifier
Expand Down
Loading
Loading