Skip to content

Added the require-event-dispatcher-types rule #354

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
merged 9 commits into from
Feb 4, 2023
5 changes: 5 additions & 0 deletions .changeset/witty-donuts-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-svelte": minor
---

Added the require-event-dispatcher-types rule
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ These rules relate to better ways of doing things to help you avoid problems:
| [svelte/no-unused-svelte-ignore](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-unused-svelte-ignore/) | disallow unused svelte-ignore comments | :star: |
| [svelte/no-useless-mustaches](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-useless-mustaches/) | disallow unnecessary mustache interpolations | :wrench: |
| [svelte/prefer-destructured-store-props](https://ota-meshi.github.io/eslint-plugin-svelte/rules/prefer-destructured-store-props/) | destructure values from object stores for better change tracking & fewer redraws | :bulb: |
| [svelte/require-event-dispatcher-types](https://ota-meshi.github.io/eslint-plugin-svelte/rules/require-event-dispatcher-types/) | require type parameters for createEventDispatcher | |
| [svelte/require-optimized-style-attribute](https://ota-meshi.github.io/eslint-plugin-svelte/rules/require-optimized-style-attribute/) | require style attributes that can be optimized | |
| [svelte/require-stores-init](https://ota-meshi.github.io/eslint-plugin-svelte/rules/require-stores-init/) | require initial value in store | |

Expand Down
1 change: 1 addition & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ These rules relate to better ways of doing things to help you avoid problems:
| [svelte/no-unused-svelte-ignore](./rules/no-unused-svelte-ignore.md) | disallow unused svelte-ignore comments | :star: |
| [svelte/no-useless-mustaches](./rules/no-useless-mustaches.md) | disallow unnecessary mustache interpolations | :wrench: |
| [svelte/prefer-destructured-store-props](./rules/prefer-destructured-store-props.md) | destructure values from object stores for better change tracking & fewer redraws | :bulb: |
| [svelte/require-event-dispatcher-types](./rules/require-event-dispatcher-types.md) | require type parameters for createEventDispatcher | |
| [svelte/require-optimized-style-attribute](./rules/require-optimized-style-attribute.md) | require style attributes that can be optimized | |
| [svelte/require-stores-init](./rules/require-stores-init.md) | require initial value in store | |

Expand Down
51 changes: 51 additions & 0 deletions docs/rules/require-event-dispatcher-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
pageClass: "rule-details"
sidebarDepth: 0
title: "svelte/require-event-dispatcher-types"
description: "require type parameters for createEventDispatcher"
since: "v2.16.0"
---

# svelte/require-event-dispatcher-types

> require type parameters for createEventDispatcher

## :book: Rule Details

This rule is aimed to enforce type parameters when calling `createEventDispatcher`. Adding types makes all `dispatch` calls as well as all event listeners typechecked. For more information, see the [svelte docs](https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#typing-component-events).

<ESLintCodeBlock language="javascript">

<!--eslint-skip-->

```svelte
<script lang="ts">
/* eslint svelte/require-event-dispatcher-types: "error" */

import { createEventDispatcher } from "svelte"

/* ✓ GOOD */
const dispatch1 = createEventDispatcher<{ one: never; two: number }>()
const dispatch2 = createEventDispatcher<Record<string, never>>()
const dispatch3 = createEventDispatcher<any>()
const dispatch4 = createEventDispatcher<unknown>()

/* ✗ BAD */
const dispatch5 = createEventDispatcher()
</script>
```

</ESLintCodeBlock>

## :wrench: Options

Nothing.

## :rocket: Version

This rule was introduced in eslint-plugin-svelte v2.16.0

## :mag: Implementation

- [Rule source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/src/rules/require-event-dispatcher-types.ts)
- [Test source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/tests/src/rules/require-event-dispatcher-types.ts)
20 changes: 20 additions & 0 deletions src/rules/reference-helpers/svelte-createEventDispatcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { TSESTree } from "@typescript-eslint/types"
import { ReferenceTracker } from "eslint-utils"
import type { RuleContext } from "../../types"

/** Extract 'svelte createEventDispatcher' references */
export function* extractCreateEventDispatcherReferences(
context: RuleContext,
): Generator<TSESTree.CallExpression, void> {
const referenceTracker = new ReferenceTracker(context.getScope())
for (const { node } of referenceTracker.iterateEsmReferences({
svelte: {
[ReferenceTracker.ESM]: true,
createEventDispatcher: {
[ReferenceTracker.CALL]: true,
},
},
})) {
yield node as TSESTree.CallExpression
}
}
28 changes: 28 additions & 0 deletions src/rules/require-event-dispatcher-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createRule } from "../utils"
import { extractCreateEventDispatcherReferences } from "./reference-helpers/svelte-createEventDispatcher"

export default createRule("require-event-dispatcher-types", {
meta: {
docs: {
description: "require type parameters for createEventDispatcher",
category: "Best Practices",
recommended: false,
},
schema: [],
messages: {
missingTypeParameter: `Type parameters missing for the createEventDispatcher function call.`,
},
type: "suggestion",
},
create(context) {
return {
Program() {
for (const node of extractCreateEventDispatcherReferences(context)) {
if (node.typeParameters === undefined) {
context.report({ node, messageId: "missingTypeParameter" })
}
}
},
}
},
})
2 changes: 2 additions & 0 deletions src/utils/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import noUselessMustaches from "../rules/no-useless-mustaches"
import preferClassDirective from "../rules/prefer-class-directive"
import preferDestructuredStoreProps from "../rules/prefer-destructured-store-props"
import preferStyleDirective from "../rules/prefer-style-directive"
import requireEventDispatcherTypes from "../rules/require-event-dispatcher-types"
import requireOptimizedStyleAttribute from "../rules/require-optimized-style-attribute"
import requireStoreCallbacksUseSetParam from "../rules/require-store-callbacks-use-set-param"
import requireStoreReactiveAccess from "../rules/require-store-reactive-access"
Expand Down Expand Up @@ -86,6 +87,7 @@ export const rules = [
preferClassDirective,
preferDestructuredStoreProps,
preferStyleDirective,
requireEventDispatcherTypes,
requireOptimizedStyleAttribute,
requireStoreCallbacksUseSetParam,
requireStoreReactiveAccess,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Type parameters missing for the createEventDispatcher function call.
line: 4
column: 20
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from "svelte"

const dispatch = createEventDispatcher()
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script lang="ts">
import { createEventDispatcher } from "svelte"

const dispatch1 = createEventDispatcher<{ one: never; two: number }>()
const dispatch2 = createEventDispatcher<Record<string, never>>()
const dispatch3 = createEventDispatcher<any>()
const dispatch4 = createEventDispatcher<unknown>()
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from "./unknown"

const dispatch = createEventDispatcher()
</script>
16 changes: 16 additions & 0 deletions tests/src/rules/require-event-dispatcher-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { RuleTester } from "eslint"
import rule from "../../../src/rules/require-event-dispatcher-types"
import { loadTestCases } from "../../utils/utils"

const tester = new RuleTester({
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
},
})

tester.run(
"require-event-dispatcher-types",
rule as any,
loadTestCases("require-event-dispatcher-types"),
)