diff --git a/.changeset/witty-donuts-jog.md b/.changeset/witty-donuts-jog.md
new file mode 100644
index 000000000..680a059f4
--- /dev/null
+++ b/.changeset/witty-donuts-jog.md
@@ -0,0 +1,5 @@
+---
+"eslint-plugin-svelte": minor
+---
+
+Added the require-event-dispatcher-types rule
diff --git a/README.md b/README.md
index 5fb32658c..48cfa6ed0 100644
--- a/README.md
+++ b/README.md
@@ -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 | |
diff --git a/docs/rules.md b/docs/rules.md
index 59e794afc..b3d5e24b3 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -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 | |
diff --git a/docs/rules/require-event-dispatcher-types.md b/docs/rules/require-event-dispatcher-types.md
new file mode 100644
index 000000000..344e1dfa5
--- /dev/null
+++ b/docs/rules/require-event-dispatcher-types.md
@@ -0,0 +1,50 @@
+---
+pageClass: "rule-details"
+sidebarDepth: 0
+title: "svelte/require-event-dispatcher-types"
+description: "require type parameters for createEventDispatcher"
+---
+
+# 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).
+
+
+
+
+
+```svelte
+
+```
+
+
+
+## :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)
diff --git a/src/rules/reference-helpers/svelte-createEventDispatcher.ts b/src/rules/reference-helpers/svelte-createEventDispatcher.ts
new file mode 100644
index 000000000..523f64e10
--- /dev/null
+++ b/src/rules/reference-helpers/svelte-createEventDispatcher.ts
@@ -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 {
+ 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
+ }
+}
diff --git a/src/rules/require-event-dispatcher-types.ts b/src/rules/require-event-dispatcher-types.ts
new file mode 100644
index 000000000..6c27f7101
--- /dev/null
+++ b/src/rules/require-event-dispatcher-types.ts
@@ -0,0 +1,39 @@
+import { createRule } from "../utils"
+import { getLangValue } from "../utils/ast-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) {
+ let isTs = false
+ return {
+ SvelteScriptElement(node) {
+ const lang = getLangValue(node)?.toLowerCase()
+ if (lang === "ts" || lang === "typescript") {
+ isTs = true
+ }
+ },
+ "Program:exit"() {
+ if (!isTs) {
+ return
+ }
+ for (const node of extractCreateEventDispatcherReferences(context)) {
+ if (node.typeParameters === undefined) {
+ context.report({ node, messageId: "missingTypeParameter" })
+ }
+ }
+ },
+ }
+ },
+})
diff --git a/src/utils/rules.ts b/src/utils/rules.ts
index 5a9a8224e..ceba1f76b 100644
--- a/src/utils/rules.ts
+++ b/src/utils/rules.ts
@@ -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"
@@ -86,6 +87,7 @@ export const rules = [
preferClassDirective,
preferDestructuredStoreProps,
preferStyleDirective,
+ requireEventDispatcherTypes,
requireOptimizedStyleAttribute,
requireStoreCallbacksUseSetParam,
requireStoreReactiveAccess,
diff --git a/tests/fixtures/rules/require-event-dispatcher-types/invalid/import-alias01-errors.yaml b/tests/fixtures/rules/require-event-dispatcher-types/invalid/import-alias01-errors.yaml
new file mode 100644
index 000000000..50e84479d
--- /dev/null
+++ b/tests/fixtures/rules/require-event-dispatcher-types/invalid/import-alias01-errors.yaml
@@ -0,0 +1,4 @@
+- message: Type parameters missing for the createEventDispatcher function call.
+ line: 4
+ column: 20
+ suggestions: null
diff --git a/tests/fixtures/rules/require-event-dispatcher-types/invalid/import-alias01-input.svelte b/tests/fixtures/rules/require-event-dispatcher-types/invalid/import-alias01-input.svelte
new file mode 100644
index 000000000..6c57eeba5
--- /dev/null
+++ b/tests/fixtures/rules/require-event-dispatcher-types/invalid/import-alias01-input.svelte
@@ -0,0 +1,5 @@
+
diff --git a/tests/fixtures/rules/require-event-dispatcher-types/invalid/no-types01-errors.yaml b/tests/fixtures/rules/require-event-dispatcher-types/invalid/no-types01-errors.yaml
new file mode 100644
index 000000000..50e84479d
--- /dev/null
+++ b/tests/fixtures/rules/require-event-dispatcher-types/invalid/no-types01-errors.yaml
@@ -0,0 +1,4 @@
+- message: Type parameters missing for the createEventDispatcher function call.
+ line: 4
+ column: 20
+ suggestions: null
diff --git a/tests/fixtures/rules/require-event-dispatcher-types/invalid/no-types01-input.svelte b/tests/fixtures/rules/require-event-dispatcher-types/invalid/no-types01-input.svelte
new file mode 100644
index 000000000..64c45eb98
--- /dev/null
+++ b/tests/fixtures/rules/require-event-dispatcher-types/invalid/no-types01-input.svelte
@@ -0,0 +1,5 @@
+
diff --git a/tests/fixtures/rules/require-event-dispatcher-types/valid/has-types01-input.svelte b/tests/fixtures/rules/require-event-dispatcher-types/valid/has-types01-input.svelte
new file mode 100644
index 000000000..167bfde74
--- /dev/null
+++ b/tests/fixtures/rules/require-event-dispatcher-types/valid/has-types01-input.svelte
@@ -0,0 +1,8 @@
+
diff --git a/tests/fixtures/rules/require-event-dispatcher-types/valid/no-typescript01-input.svelte b/tests/fixtures/rules/require-event-dispatcher-types/valid/no-typescript01-input.svelte
new file mode 100644
index 000000000..957318ec3
--- /dev/null
+++ b/tests/fixtures/rules/require-event-dispatcher-types/valid/no-typescript01-input.svelte
@@ -0,0 +1,5 @@
+
diff --git a/tests/fixtures/rules/require-event-dispatcher-types/valid/non-svelte-dispatcher01-input.svelte b/tests/fixtures/rules/require-event-dispatcher-types/valid/non-svelte-dispatcher01-input.svelte
new file mode 100644
index 000000000..e025c70a4
--- /dev/null
+++ b/tests/fixtures/rules/require-event-dispatcher-types/valid/non-svelte-dispatcher01-input.svelte
@@ -0,0 +1,5 @@
+
diff --git a/tests/src/rules/require-event-dispatcher-types.ts b/tests/src/rules/require-event-dispatcher-types.ts
new file mode 100644
index 000000000..a9ea97e41
--- /dev/null
+++ b/tests/src/rules/require-event-dispatcher-types.ts
@@ -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"),
+)