├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── BUG_REPORT_TEMPLATE.md │ ├── DOCS_ISSUE_TEMPLATE.md │ └── FEATURE_REQUEST_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── integrate.yml ├── .gitignore ├── .huskyrc ├── .lintstagedrc ├── .prettierignore ├── .prettierrc ├── .remarkrc ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Makefile ├── README.md ├── commitlint.config.js ├── demo └── index.ts ├── package-lock.json ├── package.json ├── src ├── composition-api-emit.ts ├── index.ts ├── options-api-emit.ts └── private │ ├── events.ts │ └── generic-emit.ts ├── tests └── index.ts ├── tsconfig.json └── tsconfig.test.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [{Makefile,**.mk}] 13 | # Use tabs for indentation (Makefiles require tabs) 14 | indent_size = 4 15 | indent_style = tab 16 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [andrewvasilchuk] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug report 3 | about: Create a bug report to help us improve. 4 | --- 5 | 6 | ### Describe the bug 7 | 8 | A clear and concise description of what the bug is. 9 | 10 | ### Expected behavior 11 | 12 | A clear and concise description of what you expected to happen. 13 | 14 | ### Versions 15 | 16 | **Libraries:** 17 | 18 | - Vue: 2.#.# 19 | 20 | ### Demo link 21 | 22 | If applicable, add a minimal demo link to help explain your problem. Some options for that are [CodePen](https://codepen.io/), [CodeSandbox](https://codesandbox.io/), [JS Bin](https://jsbin.com/) or [JSFiddle](https://jsfiddle.net/). 23 | 24 | ### Additional context 25 | 26 | Add any other context about the bug here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/DOCS_ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 📖 Documentation issue 3 | about: Help improve our docs. 4 | --- 5 | 6 | ### Documentation issue 7 | 8 | 9 | 10 | - [ ] Reporting a typo 11 | - [ ] Reporting a documentation bug 12 | - [ ] Documentation improvement 13 | - [ ] Documentation feedback 14 | 15 | 19 | 20 | ### Additional context or description 21 | 22 | Provide any additional details here as needed. 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature request 3 | about: Suggest an idea for this project. 4 | --- 5 | 6 | ### Is your feature request related to a problem? Please describe... 7 | 8 | A clear and concise description of what the problem is. 9 | 10 | ### Describe the solution you'd like 11 | 12 | A clear and concise description of what you want to happen. 13 | 14 | ### Describe alternatives you've considered 15 | 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | ### Additional context 19 | 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Describe the PR 2 | 3 | A clear and concise description of what the pull request does. 4 | 5 | ### PR checklist 6 | 7 | 8 | 9 | **What kind of change does this PR introduce?** (check at least one) 10 | 11 | - [ ] Bugfix (fixes a boo-boo in the code) - `fix(...)`, requires a patch version update 12 | - [ ] Feature (adds a new feature to `vue-typed-emit`) - `feat(...)`, requires a minor version update 13 | - [ ] Enhancement (augments an existing feature) - `feat(...)`, requires a minor version update 14 | - [ ] Documentation update (improves documentation or typo fixes) - `chore(docs)`, requires a patch version update 15 | - [ ] Other (please describe) 16 | 17 | **Does this PR introduce a breaking change?** (check one) 18 | 19 | - [ ] No 20 | - [ ] Yes (please describe since breaking changes require a major version update) 21 | 22 | **The PR fulfills these requirements:** 23 | 24 | - [ ] It's submitted to the `dev` branch, **not** the `master` branch 25 | - [ ] When resolving a specific issue, it's referenced in the PR's title (i.e. `[...] (fixes #xxx[,#xxx])`, where "xxx" is the issue number) 26 | - [ ] It should address only one issue or feature. If adding multiple features or fixing a bug and adding a new feature, break them into separate PRs if at all possible. 27 | - [ ] The title should follow the [**Conventional Commits**](https://www.conventionalcommits.org/) naming convention (i.e. `fix: message`, `docs: message`, `chore: message`, etc.). **This is very important, as the `CHANGELOG` is generated from these messages, and determines the next version type (patch or minor).** 28 | 29 | **If new features/enhancement/fixes are added or changed:** 30 | 31 | - [ ] Includes documentation updates 32 | - [ ] New/updated tests are included and passing (required for new features and enhancements) 33 | - [ ] Existing test suites are passing 34 | 35 | **If adding a new feature, or changing the functionality of an existing feature, the PR's 36 | description above includes:** 37 | 38 | - [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it) 39 | -------------------------------------------------------------------------------- /.github/workflows/integrate.yml: -------------------------------------------------------------------------------- 1 | name: Integration 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [master, dev] 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | if: "! contains(toJSON(github.event.commits.*.message), '[skip-ci]')" 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-node@v4 15 | with: 16 | node-version: 22 17 | - uses: actions/cache@v4 18 | with: 19 | path: '**/node_modules' 20 | key: ${{ runner.os }}-modules-${{ hashFiles('**/package-lock.json') }} 21 | restore-keys: | 22 | ${{ runner.os }}-build-${{ env.cache-name }}- 23 | ${{ runner.os }}-build- 24 | ${{ runner.os }}- 25 | - name: Install dependencies 26 | run: npm install 27 | - name: Lint 28 | run: npm run lint 29 | - name: Test 30 | run: npm run test 31 | - name: Build 32 | run: npm run build 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # https://github.com/github/gitignore/blob/master/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # Snowpack dependency directory (https://snowpack.dev/) 47 | web_modules/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Microbundle cache 59 | .rpt2_cache/ 60 | .rts2_cache_cjs/ 61 | .rts2_cache_es/ 62 | .rts2_cache_umd/ 63 | 64 | # Optional REPL history 65 | .node_repl_history 66 | 67 | # Output of 'npm pack' 68 | *.tgz 69 | 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | 73 | # dotenv environment variables file 74 | .env 75 | .env.test 76 | 77 | # parcel-bundler cache (https://parceljs.org/) 78 | .cache 79 | .parcel-cache 80 | 81 | # Next.js build output 82 | .next 83 | out 84 | 85 | # Nuxt.js build / generate output 86 | .nuxt 87 | dist 88 | 89 | # Gatsby files 90 | .cache/ 91 | # Comment in the public line in if your project uses Gatsby and not Next.js 92 | # https://nextjs.org/blog/next-9-1#public-directory-support 93 | # public 94 | 95 | # vuepress build output 96 | .vuepress/dist 97 | 98 | # Serverless directories 99 | .serverless/ 100 | 101 | # FuseBox cache 102 | .fusebox/ 103 | 104 | # DynamoDB Local files 105 | .dynamodb/ 106 | 107 | # TernJS port file 108 | .tern-port 109 | 110 | # Stores VSCode versions used for testing VSCode extensions 111 | .vscode-test 112 | 113 | # yarn v2 114 | .yarn/cache 115 | .yarn/unplugged 116 | .yarn/build-state.yml 117 | .yarn/install-state.gz 118 | .pnp.* 119 | 120 | # demo 121 | demo/demo* 122 | 123 | .DS_Store 124 | -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "lint-staged", 4 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", 5 | "pre-push": "npm run lint" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*": ["editorconfig-checker"], 3 | "*.{ts,md}": ["prettier"], 4 | "package.json": ["sort-package-json --check"], 5 | "*.md": ["remark"] 6 | } 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /.remarkrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "remark-preset-lint-recommended", 4 | [ 5 | "remark-lint-no-undefined-references", 6 | { 7 | "allow": [ 8 | " " 9 | ] 10 | } 11 | ] 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at andrew.d.vasilchuk@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Andrew Vasilchuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | npm run build 4 | 5 | .PHONY: test 6 | test: 7 | npm run test 8 | 9 | lint: 10 | npm run lint 11 | 12 | fmt: 13 | npm run fmt 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-typed-emit 2 | 3 | > TypeScript utility type for Vue.js `$emit` 4 | 5 | [![BuildStatus](https://img.shields.io/github/actions/workflow/status/andrewvasilchuk/vue-typed-emit/integrate.yml?branch=master)](https://github.com/andrewvasilchuk/vue-typed-emit/actions/workflows/integrate.yml) 6 | [![Version](https://img.shields.io/npm/v/vue-typed-emit)](https://www.npmjs.com/package/vue-typed-emit) 7 | [![Bundle Size](https://img.shields.io/bundlephobia/minzip/vue-typed-emit)](https://bundlephobia.com/result?p=vue-typed-emit) 8 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/0a12c2d8dbd44f028aacddb254df983d)](https://www.codacy.com/gh/andrewvasilchuk/vue-typed-emit/dashboard?utm_source=github.com&utm_medium=referral&utm_content=andrewvasilchuk/vue-typed-emit&utm_campaign=Badge_Grade) 9 | [![Downloads](https://img.shields.io/npm/dt/vue-typed-emit)](https://www.npmjs.com/package/vue-typed-emit) 10 | [![LastCommit](https://img.shields.io/github/last-commit/andrewvasilchuk/vue-typed-emit)](https://github.com/andrewvasilchuk/vue-typed-emit/commits/master) 11 | [![License](https://img.shields.io/npm/l/vue-typed-emit)](https://github.com/andrewvasilchuk/vue-typed-emit/blob/master/LICENSE) 12 | 13 | > ❗ This library is intended to be used with Vue `<3`. Vue 3 [provided a way to type emits](https://vuejs.org/guide/typescript/composition-api.html#typing-component-emits). 14 | 15 | ## Installation 16 | 17 | ### Via NPM 18 | 19 | ```bash 20 | $ npm i vue-typed-emit -D 21 | ``` 22 | 23 | ### Via Yarn 24 | 25 | ```bash 26 | $ yarn add vue-typed-emit --dev 27 | ``` 28 | 29 | ### Usage 30 | 31 | ### Options API 32 | 33 | ```ts 34 | import Vue from 'vue' 35 | // import type { WithEvents } from 'vue-typed-emit' TypeScript 3.8+ 36 | import { WithEvents } from 'vue-typed-emit' 37 | 38 | interface Events { 39 | foo: string 40 | bar: [string, number] 41 | baz: undefined 42 | } 43 | 44 | export default (Vue as WithEvents).extend({ 45 | name: 'Component', 46 | methods: { 47 | method() { 48 | this.$emit('foo', 'foo') 49 | this.$emit('bar', 0) 50 | this.$emit('baz') 51 | }, 52 | }, 53 | }) 54 | ``` 55 | 56 |
57 | Extending extended components 58 | 59 | ```ts 60 | // YourAwesomeExtendedComponent.vue 61 | // ... 62 | 63 | export default Vue.extend({ 64 | // ... 65 | methods: { 66 | baz() {}, 67 | }, 68 | // ... 69 | }) 70 | ``` 71 | 72 | ```ts 73 | // ... 74 | import YourAwesomeExtendedComponent from 'path/to/your/awewsome/extended/component' 75 | 76 | export default ( 77 | YourAwesomeExtendedComponent as WithEvents< 78 | WithEvents, 79 | typeof YourAwesomeExtendedComponent 80 | > 81 | ).extend({}) 82 | ``` 83 | 84 |
85 | 86 | ### Composition API 87 | 88 | ```ts 89 | import { SetupContext, defineComponent } from '@vue/composition-api' 90 | // import type { CompositionAPIEmit } from 'vue-typed-emit' TypeScript 3.8+ 91 | import { CompositionAPIEmit } from 'vue-typed-emit' 92 | 93 | interface Events { 94 | foo: string 95 | bar: [string, number] 96 | baz: undefined 97 | } 98 | 99 | interface ExtendedSetupContext extends SetupContext { 100 | emit: CompositionAPIEmit 101 | } 102 | 103 | export default defineComponent({ 104 | name: 'Component', 105 | setup(props, { emit }: ExtendedSetupContext) { 106 | emit('foo', 'foo') 107 | emit('bar', 0) 108 | emit('baz') 109 | }, 110 | }) 111 | ``` 112 | 113 | ## Motivation 114 | 115 | If your project is written using TypeScript + Vue.js, likely your components have some "contracts" – props they receive and events they emit. `vue-typed-emit` is aimed to ensure that your components adhere to the contract they claimed when it comes to events emitting and corresponding payloads. 116 | 117 | ## Caveats 118 | 119 | ### Array payload 120 | 121 | If event payload is type of of `Array` it should be defined this way. 122 | 123 | ```ts 124 | interface Events { 125 | foo: [string[]] 126 | } 127 | ``` 128 | 129 | ## Tests 130 | 131 | ```bash 132 | npm run test 133 | ``` 134 | 135 | ## Build 136 | 137 | ```bash 138 | npm run build 139 | ``` 140 | 141 | ## License 142 | 143 | [MIT](http://opensource.org/licenses/MIT) 144 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] } 2 | -------------------------------------------------------------------------------- /demo/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import type { WithEvents } from '../src' 4 | 5 | interface Events { 6 | foo: string 7 | bar: [string, number] 8 | baz: undefined 9 | } 10 | 11 | export default (Vue as WithEvents).extend({ 12 | name: 'Component', 13 | data() { 14 | return { 15 | foo: 'foo', 16 | } 17 | }, 18 | computed: { 19 | bar(): string { 20 | return 'bar' 21 | }, 22 | }, 23 | methods: { 24 | method() { 25 | this.$emit('foo', this.foo) 26 | this.$emit('bar', 'bar', 0) 27 | this.$emit('baz') 28 | }, 29 | }, 30 | }) 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-typed-emit", 3 | "version": "1.2.0", 4 | "private": false, 5 | "description": "TypeScript utility type for Vue.js $emit", 6 | "keywords": [ 7 | "emit", 8 | "types", 9 | "typescript", 10 | "vue" 11 | ], 12 | "homepage": "https://github.com/andrewvasilchuk/vue-typed-emit#readme", 13 | "bugs": { 14 | "url": "https://github.com/andrewvasilchuk/vue-typed-emit/issues" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/andrewvasilchuk/vue-typed-emit.git" 19 | }, 20 | "license": "MIT", 21 | "author": "Andrew Vasilchuk ", 22 | "contributors": [ 23 | { 24 | "name": "Andrew Vasylchuk", 25 | "email": "andrew.d.vasilchuk@gmail.com" 26 | } 27 | ], 28 | "main": "dist/index.js", 29 | "types": "dist/index.d.ts", 30 | "files": [ 31 | "src", 32 | "dist" 33 | ], 34 | "scripts": { 35 | "build": "rimraf .dist/* && tsc ./src/index.ts --outDir ./dist --declaration", 36 | "fmt": "npm run fmt:prettier && npm run fmt:package-json", 37 | "fmt:package-json": "sort-package-json", 38 | "fmt:prettier": "prettier --write ./**/*.{ts,md}", 39 | "lint": "npm run lint:editorconfig && npm run lint:package-json && npm run lint:prettier && npm run lint:remark", 40 | "lint:editorconfig": "editorconfig-checker", 41 | "lint:package-json": "sort-package-json --check", 42 | "lint:prettier": "prettier --check ./**/*.{ts,md}", 43 | "lint:remark": "remark .", 44 | "prepare": "npm run build", 45 | "test": "tsc -p ./tsconfig.test.json" 46 | }, 47 | "devDependencies": { 48 | "@commitlint/cli": "^19.7.1", 49 | "@commitlint/config-conventional": "^19.7.1", 50 | "@types/node": "^22.13.1", 51 | "@vue/composition-api": "^1.1.1", 52 | "editorconfig-checker": "^6.0.1", 53 | "husky": "^9.1.7", 54 | "lint-staged": "^15.4.3", 55 | "prettier": "^3.4.2", 56 | "remark-cli": "^12.0.1", 57 | "remark-lint": "^10.0.1", 58 | "remark-preset-lint-recommended": "^7.0.1", 59 | "rimraf": "^6.0.1", 60 | "sort-package-json": "^2.14.0", 61 | "typescript": "^5.7.3", 62 | "vue": "^2.7.16" 63 | }, 64 | "peerDependencies": { 65 | "@vue/composition-api": "<=1.1.1", 66 | "vue": "<3" 67 | }, 68 | "peerDependenciesMeta": { 69 | "@vue/composition-api": { 70 | "optional": true 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/composition-api-emit.ts: -------------------------------------------------------------------------------- 1 | import type { Events } from './private/events' 2 | import type { GenericEmit } from './private/generic-emit' 3 | 4 | export interface CompositionAPIEmit 5 | extends GenericEmit {} 6 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import type Vue from 'vue' 2 | import type { VueConstructor } from 'vue' 3 | 4 | import type { Events } from './private/events' 5 | import type { OptionsAPIEmit } from './options-api-emit' 6 | 7 | export type WithEvents< 8 | E extends Events, 9 | C extends VueConstructor = VueConstructor, 10 | > = 11 | C extends VueConstructor 12 | ? VueConstructor & { $emit: OptionsAPIEmit }> 13 | : never 14 | 15 | export { CompositionAPIEmit } from './composition-api-emit' 16 | -------------------------------------------------------------------------------- /src/options-api-emit.ts: -------------------------------------------------------------------------------- 1 | import type { Events } from './private/events' 2 | import type { GenericEmit } from './private/generic-emit' 3 | 4 | export interface OptionsAPIEmit 5 | extends GenericEmit {} 6 | -------------------------------------------------------------------------------- /src/private/events.ts: -------------------------------------------------------------------------------- 1 | export type Events = Record 2 | -------------------------------------------------------------------------------- /src/private/generic-emit.ts: -------------------------------------------------------------------------------- 1 | import type Vue from 'vue' 2 | 3 | import type { Events } from './events' 4 | 5 | export interface GenericEmit { 6 | ( 7 | eventName: K, 8 | ...args: T[K] extends undefined 9 | ? [undefined?] 10 | : T[K] extends Array 11 | ? T[K] 12 | : [T[K]] 13 | ): R 14 | } 15 | -------------------------------------------------------------------------------- /tests/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { SetupContext, defineComponent } from '@vue/composition-api' 3 | 4 | import type { WithEvents, CompositionAPIEmit } from '../src' 5 | 6 | interface Events { 7 | foo: string 8 | bar: undefined 9 | baz: [string, number] 10 | } 11 | 12 | export const OptionsAPIComponent = (Vue as WithEvents).extend({ 13 | name: 'OptionsAPIComponent', 14 | props: { 15 | foo: { 16 | type: String, 17 | required: true, 18 | }, 19 | }, 20 | methods: { 21 | method() { 22 | this.$emit('foo', 'foo') 23 | // @ts-expect-error 24 | this.$emit('foo', 1) 25 | this.$emit('bar') 26 | // @ts-expect-error 27 | this.$emit('bar', 'bar') 28 | this.$emit('baz', 'baz', 256) 29 | // @ts-expect-error 30 | this.$emit('baz', true, {}) 31 | }, 32 | }, 33 | }) 34 | 35 | interface ExtendedSetupContext extends SetupContext { 36 | emit: CompositionAPIEmit 37 | } 38 | 39 | interface Props { 40 | foo: string 41 | } 42 | 43 | export const CompositionAPIComponent = defineComponent({ 44 | name: 'CompositionAPIComponent', 45 | props: { 46 | foo: { 47 | type: String, 48 | required: true, 49 | }, 50 | }, 51 | setup(props: Props, { emit }: ExtendedSetupContext) { 52 | emit('foo', 'foo') 53 | // @ts-expect-error 54 | emit('foo', 1) 55 | emit('bar') 56 | // @ts-expect-error 57 | emit('bar', 'bar') 58 | emit('baz', 'baz', 256) 59 | // @ts-expect-error 60 | emit('baz', true, {}) 61 | }, 62 | }) 63 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "moduleResolution": "Node", 5 | "skipLibCheck": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true 5 | }, 6 | "include": ["./tests/**/*.ts"], 7 | "exclude": ["node_modules"] 8 | } 9 | --------------------------------------------------------------------------------