Skip to content

Commit

Permalink
docs: refreshed docs and onboarded eslint-doc-generator (#67)
Browse files Browse the repository at this point in the history
* docs: refreshed docs and onboarded eslint-doc-generator

* Fixed up test types

* Update docs

* Fixed formatting in README.md
  • Loading branch information
JoshuaKGoldberg authored Dec 5, 2022
1 parent e905f93 commit 168298d
Show file tree
Hide file tree
Showing 12 changed files with 4,104 additions and 3,667 deletions.
4 changes: 4 additions & 0 deletions .eslint-doc-generatorrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('eslint-doc-generator').GenerateOptions} */
module.exports = {
ruleDocTitleFormat: 'prefix-name',
};
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
coverage
dist
27 changes: 19 additions & 8 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
{
"extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
"env": {
"node": true
},
"extends": ["eslint:recommended", "prettier"],
"overrides": [
{
"extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
"files": ["**/*.{ts,tsx}"],
"parserOptions": {
"project": ["./tsconfig.json", "./tests/tsconfig.json"]
},
"rules": {
"@typescript-eslint/no-non-null-assertion": "off"
}
}
],
"plugins": ["@typescript-eslint", "@typescript-eslint/eslint-plugin", "prettier"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"root": true,
"rules": {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-non-null-assertion": "off"
"no-case-declarations": "off",
"no-constant-condition": "off"
}
}
4 changes: 4 additions & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"no-inline-html": false,
"line-length": false
}
1 change: 1 addition & 0 deletions .markdownlintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
142 changes: 34 additions & 108 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# eslint-plugin-expect-type

ESLint plugin with $ExpectType and $ExpectError type assertions
> ESLint plugin with `^?` Twoslash, `$ExpectError`, and `$ExpectType` type assertions. ✨
```ts
9001;
// ^? number

// $ExpectError
const value: string = 9001;

// $ExpectType number
9001;
```

## Installation

Expand All @@ -10,129 +21,44 @@ Make sure you have TypeScript and @typescript-eslint/parser installed, then inst
npm i -D eslint-plugin-expect-type
```

Please also make sure the following packages are also installed:

```sh
npm i -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
```
> See [typescript-eslint's Getting Started docs](https://typescript-eslint.io/docs) for how to run ESLint on TypeScript files.
## Usage

Please add the following options to your `.eslintrc`

```json
{
"extends": ["plugin:eslint-plugin-expect-type/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": ["eslint-plugin-expect-type"],
"root": true
}
```

Rule severity could be configured as follows
Add the following options to your [ESLint configuration file](https://eslint.org/docs/latest/user-guide/configuring/configuration-files):

```json
{
"rules": {
"expect-type/expect": "error"
}
"extends": ["plugin:expect-type/recommended"],
"plugins": ["eslint-plugin-expect-type"]
}
```

To skip Snapshot update when eslint is run with `--fix` could be configured as follows:

```json
{
"rules": {
"expect-type/expect": ["error", { "disableExpectTypeSnapshotFix": true }]
}
}
```

**Note: Make sure to use `eslint --ext .js,.ts` since by [default](https://eslint.org/docs/user-guide/command-line-interface#--ext) `eslint` will only search for .js files.**

## Adding $ExpectType and $ExpectError type assertions

> A test file should be a piece of sample code that tests using the library. Tests are type-checked, but not run. To assert that an expression is of a given type, use $ExpectType. To assert that an expression causes a compile error, use $ExpectError. (Assertions will be checked by the expect lint rule.)
(https://github.com/Microsoft/dtslint#write-tests)

```ts
import foo from 'lib-to-test'; // foo is (n: number) => void

// $ExpectType void
foo(1);

// Can also write the assertion on the same line.
foo(2); // $ExpectType void

// $ExpectError
foo('bar');
```

## Adding \$ExpectTypeSnapshot

Uses snapshot saved in file as expected type for expression.

Example:

**foo.test.ts**

```ts
// $ExpectTypeSnapshot MyFooSnapshot
const Foo = {
a: 1,
n: 17,
} as const;
```

By running `eslint --fix` the following file will be created in the folder of `foo.test.ts`:
Then, you'll be able to use `^?`, `$ExpectError`, `$ExpectType`, and `$ExpectTypeSnapshot` comments in code assert on types.

```plaintext
__type-snapshots__/foo.test.ts.snap.json
```

By running `eslint` snapshot type will be matched with actual type and Error will be emitted in case types don't match.
<!-- prettier-ignore-start -->
<!-- begin auto-generated rules list -->

### To create/update snapshots
💼 Configurations enabled in.\
✅ Set in the `recommended` configuration.\
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
💭 Requires type information.

```sh
eslint --fix
```
| Name | Description | 💼 | 🔧 | 💭 |
| :----------------------------- | :----------------------------------------- | :- | :- | :- |
| [expect](docs/rules/expect.md) | Expects type error, type snapshot or type. || 🔧 | 💭 |

## Twoslash syntax (^?)

This plugin also supports twoslash annotations, which is a comment line that starts with two slashes (`// `) and the `^?` identifier to annotate the symbol you're interested in:

```ts
const square = (x: number) => x * x;
const four = square(2);
// ^? const four: number
```

Multiline type annotations are also supported:

```ts
const vector = {
x: 3,
y: 4,
};
vector;
// ^? const vector: {
// x: number;
// y: number;
// }
```
<!-- end auto-generated rules list -->
<!-- prettier-ignore-end -->

## References

1. https://github.com/gcanti/dtslint
2. https://github.com/Microsoft/dtslint
3. https://github.com/SamVerschueren/tsd
You might consider using other popular type assertion libraries in the TypeScript ecosystem:

- **[expect-type](https://github.com/mmkal/expect-type)**: Provides functions that return assorted generic type assertion methods, such as `expectTypeOf('abc').toMatchTypeOf<string>()`.
- **[ts-expect](https://github.com/mmkal/expect-type)**: Provides generic type assertion function, used like `expectType<string>('abc')()`.
- **[tsd](https://github.com/SamVerschueren/tsd)**: Allows writing tests specifically for `.d.ts` definition files.

## Appreciation

Many thanks to @ibezkrovnyi for creating the initial version and core infrastructure of this package! 💖
Many thanks to [@ibezkrovnyi](https://github.com/ibezkrovnyi) for creating the initial version and core infrastructure of this package! 💖
146 changes: 146 additions & 0 deletions docs/rules/expect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# expect-type/expect

💼 This rule is enabled in the ✅ `recommended` config.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

💭 This rule requires type information.

<!-- end auto-generated rule header -->

Enforces that types indicated in special comments match the types of code values.

## Comment Types

The following kinds of comments are supported:

<!-- Markdownlint doesn't seem to understand the heading IDs... -->
<!-- markdownlint-disable link-fragments -->

- [`^?` (Twoslash Syntax)](#twoslash-syntax)
- [`$ExpectError`](#expecterror)
- [`$ExpectType`](#expecttype)
- [`$ExpectTypeSnapshot`](#expecttypesnapshot)

<!-- markdownlint-enable link-fragments -->

### Twoslash Syntax (`^?`)

Twoslash annotations are comment lines that start with two slashes (// ) and the ^? identifier to annotate a type below a value in code.
For example:

```ts
declare const getTextLength: (text: string) => number;

getTextLength('abc');
// ^? number

getTextLength;
// ^? (text: string) => number
```

Mismatching the type will cause a lint report:

```ts
'abc';
// ^? number
```

```plaintext
Expected type to be: number, got: string
```

Multiline type annotations are also supported:

```ts
const vector = {
x: 3,
y: 4,
};
vector;
// ^? const vector: {
// x: number;
// y: number;
// }
```

### `$ExpectError`

Place this above a line of code to assert that it causes a TypeScript type error.

For example:

```ts
// $ExpectError
const value: number = 'abc';
```

> ⚠️ `$ExpectError` does not suppress TypeScript type errors.
> Only TypeScript comment directives such as `// @ts-expect-error` may do that.
> See [#65](https://github.com/JoshuaKGoldberg/eslint-plugin-expect-type/issues/65).
### `$ExpectType`

A comment containing `// $ExpectType` and a type, placed above or on a line of code.
It asserts that the value of the line of code is of that type.

For example:

```ts
declare const getTextLength: (text: string) => number;

// $ExpectType number
getTextLength('abc');

// $ExpectType (text: string) => number
getTextLength;
```

Mismatching the type will cause a lint report:

```ts
// $ExpectType number
'abc';
```

```plaintext
Expected type to be: number, got: string
```

### `$ExpectTypeSnapshot`

Similar to `$ExpectType`, but instead of a type, takes in a unique ID for a snapshot.
The snapshot will then be saved in a `__type-snapshots__/*.snap.json` file alongside the original `*`-named source file.

For example, given a `file.ts`:

```ts
declare const getTextLength: (text: string) => number;

// $ExpectTypeSnapshot FunctionCallExpression
getTextLength('abc');

// $ExpectTypeSnapshot FunctionIdentifier
getTextLength;
```

...a `__type-snapshots__/file.ts.snap.json` file will be created containing:

```json
{
"FunctionCallExpression": "number",
"FunctionIdentifier": "(text: string) => number"
}
```

These snapshots will automatically update whenever `eslint --fix` is run.

> ⛔️ [#14](https://github.com/JoshuaKGoldberg/eslint-plugin-expect-type/issues/14): There is currently a bug where the snapshots will _always_ update unless the later `disableExpectTypeSnapshotFix` option is set.
> Help wanted!
## Options

### `disableExpectTypeSnapshotFix`

Whether to disable `$ExpectTypeSnapshot` auto-fixing.
Defaults to `false`.
Loading

0 comments on commit 168298d

Please sign in to comment.