diff --git a/docs/rules/define-emits-declaration.md b/docs/rules/define-emits-declaration.md
index 2fd4b478f..7a11524c5 100644
--- a/docs/rules/define-emits-declaration.md
+++ b/docs/rules/define-emits-declaration.md
@@ -5,13 +5,15 @@ title: vue/define-emits-declaration
description: enforce declaration style of `defineEmits`
since: v9.5.0
---
+
# vue/define-emits-declaration
> enforce declaration style of `defineEmits`
## :book: Rule Details
-This rule enforces `defineEmits` typing style which you should use `type-based` or `runtime` declaration.
+This rule enforces `defineEmits` typing style which you should use `type-based`, strict `type-literal`
+(introduced in Vue 3.3), or `runtime` declaration.
This rule only works in setup script and `lang="ts"`.
@@ -25,6 +27,12 @@ const emit = defineEmits<{
(e: 'update', value: string): void
}>()
+/* ✓ GOOD */
+const emit = defineEmits<{
+ change: [id: number]
+ update: [value: string]
+}>()
+
/* ✗ BAD */
const emit = defineEmits({
change: (id) => typeof id == 'number',
@@ -41,10 +49,11 @@ const emit = defineEmits(['change', 'update'])
## :wrench: Options
```json
- "vue/define-emits-declaration": ["error", "type-based" | "runtime"]
+ "vue/define-emits-declaration": ["error", "type-based" | "type-literal" | "runtime"]
```
-- `type-based` (default) enforces type-based declaration
+- `type-based` (default) enforces type based declaration
+- `type-literal` enforces strict "type literal" type based declaration
- `runtime` enforces runtime declaration
### `runtime`
@@ -72,6 +81,37 @@ const emit = defineEmits(['change', 'update'])
+### `type-literal`
+
+
+
+```vue
+
+```
+
+
+
## :couple: Related Rules
- [vue/define-props-declaration](./define-props-declaration.md)
diff --git a/lib/rules/define-emits-declaration.js b/lib/rules/define-emits-declaration.js
index 478e1d840..d17e76537 100644
--- a/lib/rules/define-emits-declaration.js
+++ b/lib/rules/define-emits-declaration.js
@@ -6,6 +6,11 @@
const utils = require('../utils')
+/**
+ * @typedef {import('@typescript-eslint/types').TSESTree.TSTypeLiteral} TSTypeLiteral
+ *
+ */
+
module.exports = {
meta: {
type: 'suggestion',
@@ -17,12 +22,14 @@ module.exports = {
fixable: null,
schema: [
{
- enum: ['type-based', 'runtime']
+ enum: ['type-based', 'type-literal', 'runtime']
}
],
messages: {
- hasArg: 'Use type-based declaration instead of runtime declaration.',
- hasTypeArg: 'Use runtime declaration instead of type-based declaration.'
+ hasArg: 'Use type based declaration instead of runtime declaration.',
+ hasTypeArg: 'Use runtime declaration instead of type based declaration.',
+ hasTypeCallArg:
+ 'Use new type literal declaration instead of the old call signature declaration.'
}
},
/** @param {RuleContext} context */
@@ -46,6 +53,28 @@ module.exports = {
break
}
+ case 'type-literal': {
+ if (node.arguments.length > 0) {
+ context.report({
+ node,
+ messageId: 'hasArg'
+ })
+ return
+ }
+
+ const typeArguments = node.typeArguments || node.typeParameters
+ const param = /** @type {TSTypeLiteral} */ (typeArguments.params[0])
+ for (const memberNode of param.members) {
+ if (memberNode.type !== 'TSPropertySignature') {
+ context.report({
+ node: memberNode,
+ messageId: 'hasTypeCallArg'
+ })
+ }
+ }
+ break
+ }
+
case 'runtime': {
const typeArguments = node.typeArguments || node.typeParameters
if (typeArguments && typeArguments.params.length > 0) {
diff --git a/tests/lib/rules/define-emits-declaration.js b/tests/lib/rules/define-emits-declaration.js
index 372fa1a4c..43ecb385b 100644
--- a/tests/lib/rules/define-emits-declaration.js
+++ b/tests/lib/rules/define-emits-declaration.js
@@ -63,6 +63,36 @@ tester.run('define-emits-declaration', rule, {
`,
options: ['runtime']
},
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ options: ['type-based'],
+ parserOptions: {
+ parser: require.resolve('@typescript-eslint/parser')
+ }
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ options: ['type-literal'],
+ parserOptions: {
+ parser: require.resolve('@typescript-eslint/parser')
+ }
+ },
{
filename: 'test.vue',
// ignore code without defineEmits
@@ -82,7 +112,7 @@ tester.run('define-emits-declaration', rule, {
code: `
+ `,
+ options: ['type-literal'],
+ parserOptions: {
+ parser: require.resolve('@typescript-eslint/parser')
+ },
+ errors: [
+ {
+ message: 'Use type based declaration instead of runtime declaration.',
line: 3
}
]
@@ -142,10 +190,59 @@ tester.run('define-emits-declaration', rule, {
},
errors: [
{
- message: 'Use runtime declaration instead of type-based declaration.',
+ message: 'Use runtime declaration instead of type based declaration.',
line: 3
}
]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ options: ['type-literal'],
+ parserOptions: {
+ parser: require.resolve('@typescript-eslint/parser')
+ },
+ errors: [
+ {
+ message:
+ 'Use new type literal declaration instead of the old call signature declaration.',
+ line: 4
+ },
+ {
+ message:
+ 'Use new type literal declaration instead of the old call signature declaration.',
+ line: 5
+ }
+ ]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ options: ['type-literal'],
+ parserOptions: {
+ parser: require.resolve('@typescript-eslint/parser')
+ },
+ errors: [
+ {
+ message:
+ 'Use new type literal declaration instead of the old call signature declaration.',
+ line: 5
+ }
+ ]
}
]
})