├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ ├── nodejs-master.yml │ └── nodejs-pr.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── api-extractor.json ├── docs ├── index.md ├── types.asyncmethodreturns.md ├── types.constructorargs.md ├── types.deeppartial.md ├── types.deferred._constructor_.md ├── types.deferred.md ├── types.deferred.promise.md ├── types.deferred.promiseconstructor.md ├── types.deferred.reject.md ├── types.deferred.resolve.md ├── types.dict.md ├── types.extractargs.md ├── types.extractpropertynamesoftype.md ├── types.isdefined.md ├── types.isnonnull.md ├── types.ispresent.md ├── types.md ├── types.optionalpropertynamesof.md ├── types.optionalprops.md ├── types.requiredpropertynamesof.md └── types.requiredprops.md ├── etc └── types.api.md ├── package.json ├── renovate.json ├── scripts ├── build │ ├── commonjs.sh │ ├── es6.sh │ └── types.sh ├── clean.sh ├── pretest.sh └── test │ ├── ts.sh │ └── types.sh ├── src ├── async.ts ├── classes.ts ├── dict.ts ├── functions.ts ├── guards.ts ├── index.ts └── objects.ts ├── test ├── async-method-returns.test.ts ├── constructor-args.test.ts ├── deferred.test.ts ├── object-utils.test.ts └── tsconfig.json ├── tsconfig.json ├── type-tests ├── index.d.ts ├── object.test.ts ├── tsconfig.json └── tslint.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | temp/ 3 | docs/ 4 | build/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'eslint:recommended', 4 | 'plugin:@typescript-eslint/eslint-recommended', 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:prettier/recommended', 7 | 'plugin:promise/recommended', 8 | 'plugin:@typescript-eslint/recommended-requiring-type-checking', 9 | 'plugin:import/errors', 10 | 'plugin:import/warnings', 11 | 'plugin:import/typescript' 12 | ], 13 | parser: '@typescript-eslint/parser', 14 | parserOptions: { 15 | project: 'tsconfig.json' 16 | }, 17 | env: { 18 | es6: true 19 | }, 20 | plugins: ['prettier', 'node', 'promise', '@typescript-eslint'], 21 | rules: { 22 | '@typescript-eslint/explicit-member-accessibility': 2, 23 | '@typescript-eslint/camelcase': 0, 24 | '@typescript-eslint/no-explicit-any': 0, 25 | '@typescript-eslint/no-unused-vars': 0 26 | }, 27 | overrides: [ 28 | { 29 | files: ['test/**/*.ts'], 30 | parserOptions: { 31 | project: 'test/tsconfig.json' 32 | }, 33 | env: { 34 | qunit: true, 35 | node: true 36 | }, 37 | rules: { 38 | '@typescript-eslint/explicit-function-return-type': 0, 39 | '@typescript-eslint/explicit-member-accessibility': 0, 40 | 'import/no-unresolved': 0, 41 | '@typescript-eslint/no-misused-promises': 0 42 | } 43 | }, 44 | { 45 | files: ['type-tests/**/*.ts'], 46 | parserOptions: { 47 | project: 'type-tests/tsconfig.json' 48 | }, 49 | env: { 50 | qunit: true, 51 | node: true 52 | }, 53 | rules: { 54 | 'prefer-const': 0, 55 | '@typescript-eslint/no-misused-promises': 0 56 | } 57 | } 58 | ] 59 | }; 60 | -------------------------------------------------------------------------------- /.github/workflows/nodejs-master.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI (master) 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | env: 9 | CI: true 10 | 11 | jobs: 12 | build_12: 13 | name: build 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [12.x] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - run: | 27 | yarn 28 | yarn build 29 | mkdir ../sync 30 | tar -cf ../sync/build.tar . 31 | - name: Upload build 32 | uses: actions/upload-artifact@v1 33 | with: 34 | name: build_${{ matrix.node-version }} 35 | path: ../sync 36 | build: 37 | name: build 38 | runs-on: ubuntu-latest 39 | needs: [build_12, lint] 40 | 41 | strategy: 42 | matrix: 43 | node-version: [8.11.3, 8.x, 10.x, 13.x] 44 | 45 | steps: 46 | - uses: actions/checkout@v2 47 | - name: Use Node.js ${{ matrix.node-version }} 48 | uses: actions/setup-node@v1 49 | with: 50 | node-version: ${{ matrix.node-version }} 51 | - run: yarn --ignore-optional 52 | - run: yarn build 53 | - run: | 54 | mkdir ../sync 55 | tar -cf ../sync/build.tar . 56 | - name: Upload build 57 | uses: actions/upload-artifact@v1 58 | with: 59 | name: build_${{ matrix.node-version }} 60 | path: ../sync 61 | commit_lint: 62 | name: CommitLint 63 | needs: build_12 64 | runs-on: ubuntu-latest 65 | steps: 66 | - uses: actions/checkout@v2 67 | with: 68 | fetch-depth: 0 69 | - name: Commit Linter 70 | uses: wagoid/commitlint-github-action@v1.4.0 71 | env: 72 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 73 | lint: 74 | name: ESLint 75 | needs: build_12 76 | runs-on: ubuntu-latest 77 | steps: 78 | - name: Download build 79 | uses: actions/download-artifact@v1 80 | with: 81 | name: build_12.x 82 | path: ../sync 83 | - run: tar -xf ../sync/build.tar . 84 | - run: yarn lint 85 | updated_api_report: 86 | name: API Report up-to-date 87 | needs: build_12 88 | runs-on: ubuntu-latest 89 | steps: 90 | - uses: actions/checkout@v2 91 | - name: Download build 92 | uses: actions/download-artifact@v1 93 | with: 94 | name: build_12.x 95 | path: ../sync 96 | - run: tar -xf ../sync/build.tar . 97 | - run: | 98 | echo "API reports that are out of date: " && git diff --exit-code --name-only HEAD 'packages/*/etc/*.md' && echo "NONE: this PR is ready for review\!" 99 | - run: git diff -s --exit-code HEAD -- 'packages/*/etc/*.md' 100 | updated_docs: 101 | name: Docs up-to-date 102 | needs: build_12 103 | runs-on: ubuntu-latest 104 | steps: 105 | - uses: actions/checkout@v2 106 | - name: Download build 107 | uses: actions/download-artifact@v1 108 | with: 109 | name: build_12.x 110 | path: ../sync 111 | - run: tar -xf ../sync/build.tar . 112 | - run: | 113 | echo "Documentation files that are out of date: " && git diff --exit-code --name-only HEAD 'docs/**/*.md' && echo "NONE: this PR is ready for review\!" 114 | - run: git diff -s --exit-code HEAD -- 'docs/**/*.md' 115 | basic_test: 116 | strategy: 117 | matrix: 118 | node-version: [12.x] 119 | name: node tests 120 | needs: [build_12] 121 | runs-on: ubuntu-latest 122 | steps: 123 | - name: Download build 124 | uses: actions/download-artifact@v1 125 | with: 126 | name: build_${{ matrix.node-version }} 127 | path: ../sync 128 | - run: tar -xf ../sync/build.tar . 129 | - run: yarn test 130 | compat_test: 131 | strategy: 132 | matrix: 133 | node-version: [8.11.3, 8.x, 10.x, 13.x] 134 | name: node tests 135 | needs: 136 | [build, commit_lint, lint, basic_test, updated_docs, updated_api_report] 137 | runs-on: ubuntu-latest 138 | steps: 139 | - name: Download build 140 | uses: actions/download-artifact@v1 141 | with: 142 | name: build_${{ matrix.node-version }} 143 | path: ../sync 144 | - run: tar -xf ../sync/build.tar . 145 | - run: yarn test 146 | # release: 147 | # name: Publish 148 | # runs-on: ubuntu-18.04 149 | # needs: [compat_test] 150 | # steps: 151 | # - name: Checkout 152 | # uses: actions/checkout@v1 153 | # - name: Setup Node.js 154 | # uses: actions/setup-node@v1 155 | # with: 156 | # node-version: 12 157 | # - name: Install dependencies 158 | # run: yarn 159 | # - name: Build 160 | # run: yarn build 161 | # - name: Test 162 | # run: yarn test 163 | # - name: Release 164 | # env: 165 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 166 | # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 167 | # run: npx semantic-release 168 | -------------------------------------------------------------------------------- /.github/workflows/nodejs-pr.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - master 7 | pull_request: 8 | 9 | env: 10 | CI: true 11 | 12 | jobs: 13 | build_12: 14 | name: build 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [12.x] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - run: | 28 | yarn 29 | yarn build 30 | mkdir ../sync 31 | tar -cf ../sync/build.tar . 32 | - name: Upload build 33 | uses: actions/upload-artifact@v1 34 | with: 35 | name: build_${{ matrix.node-version }} 36 | path: ../sync 37 | build: 38 | name: build 39 | runs-on: ubuntu-latest 40 | needs: [build_12, lint] 41 | 42 | strategy: 43 | matrix: 44 | node-version: [8.11.3, 8.x, 10.x, 13.x] 45 | 46 | steps: 47 | - uses: actions/checkout@v2 48 | - name: Use Node.js ${{ matrix.node-version }} 49 | uses: actions/setup-node@v1 50 | with: 51 | node-version: ${{ matrix.node-version }} 52 | - run: yarn --ignore-optional 53 | - run: yarn build 54 | - run: | 55 | mkdir ../sync 56 | tar -cf ../sync/build.tar . 57 | - name: Upload build 58 | uses: actions/upload-artifact@v1 59 | with: 60 | name: build_${{ matrix.node-version }} 61 | path: ../sync 62 | commit_lint: 63 | name: CommitLint 64 | needs: build_12 65 | runs-on: ubuntu-latest 66 | steps: 67 | - uses: actions/checkout@v2 68 | with: 69 | fetch-depth: 0 70 | - name: Commit Linter 71 | uses: wagoid/commitlint-github-action@v1.4.0 72 | env: 73 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 74 | lint: 75 | name: ESLint 76 | needs: build_12 77 | runs-on: ubuntu-latest 78 | steps: 79 | - name: Download build 80 | uses: actions/download-artifact@v1 81 | with: 82 | name: build_12.x 83 | path: ../sync 84 | - run: tar -xf ../sync/build.tar . 85 | - run: yarn lint 86 | updated_api_report: 87 | name: API Report up-to-date 88 | needs: build_12 89 | runs-on: ubuntu-latest 90 | steps: 91 | - uses: actions/checkout@v2 92 | - name: Download build 93 | uses: actions/download-artifact@v1 94 | with: 95 | name: build_12.x 96 | path: ../sync 97 | - run: tar -xf ../sync/build.tar . 98 | - run: | 99 | echo "API reports that are out of date: " && git diff --exit-code --name-only HEAD 'packages/*/etc/*.md' && echo "NONE: this PR is ready for review\!" 100 | - run: git diff -s --exit-code HEAD -- 'packages/*/etc/*.md' 101 | updated_docs: 102 | name: Docs up-to-date 103 | needs: build_12 104 | runs-on: ubuntu-latest 105 | steps: 106 | - uses: actions/checkout@v2 107 | - name: Download build 108 | uses: actions/download-artifact@v1 109 | with: 110 | name: build_12.x 111 | path: ../sync 112 | - run: tar -xf ../sync/build.tar . 113 | - run: | 114 | echo "Documentation files that are out of date: " && git diff --exit-code --name-only HEAD 'docs/**/*.md' && echo "NONE: this PR is ready for review\!" 115 | - run: git diff -s --exit-code HEAD -- 'docs/**/*.md' 116 | basic_test: 117 | strategy: 118 | matrix: 119 | node-version: [12.x] 120 | name: node tests 121 | needs: [build_12] 122 | runs-on: ubuntu-latest 123 | steps: 124 | - name: Download build 125 | uses: actions/download-artifact@v1 126 | with: 127 | name: build_${{ matrix.node-version }} 128 | path: ../sync 129 | - run: tar -xf ../sync/build.tar . 130 | - run: yarn test 131 | compat_test: 132 | strategy: 133 | matrix: 134 | node-version: [8.11.3, 8.x, 10.x, 13.x] 135 | name: node tests 136 | needs: 137 | [build, commit_lint, lint, basic_test, updated_docs, updated_api_report] 138 | runs-on: ubuntu-latest 139 | steps: 140 | - name: Download build 141 | uses: actions/download-artifact@v1 142 | with: 143 | name: build_${{ matrix.node-version }} 144 | path: ../sync 145 | - run: tar -xf ../sync/build.tar . 146 | - run: yarn test 147 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | tmp 4 | *.log 5 | package-lock.json# Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules/ 46 | jspm_packages/ 47 | 48 | # TypeScript v1 declaration files 49 | typings/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variables file 76 | .env 77 | .env.test 78 | 79 | # parcel-bundler cache (https://parceljs.org/) 80 | .cache 81 | 82 | # Next.js build output 83 | .next 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 | # API extractor 114 | .compiled-types 115 | temp 116 | .test-js -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .travis.yml 3 | dist/**/test 4 | dist/**/node_modules 5 | scripts 6 | test 7 | testem.js 8 | tmp 9 | tsconfig.json 10 | tslint.json 11 | .compiled-types 12 | .test-js 13 | temp -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "printWidth": 80 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Run Tests", 11 | "preLaunchTask": "Build Tests", 12 | "program": "${workspaceRoot}/node_modules/qunit/bin/qunit", 13 | "args": [ 14 | "dist/commonjs/test/**/*-test.js" 15 | ], 16 | "outFiles": ["${workspaceRoot}/dist/commonjs/**/*.js"], 17 | "internalConsoleOptions": "openOnSessionStart" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/.DS_Store": true, 5 | "tmp": true 6 | }, 7 | "typescript.tsdk": "node_modules/typescript/lib", 8 | "files.associations": { 9 | "*.json": "jsonc" 10 | }, 11 | "eslint.enable": true 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Type Check", 8 | "type": "npm", 9 | "script": "problems", 10 | "problemMatcher": "$tsc", 11 | "presentation": { 12 | "echo": false, 13 | "reveal": "never", 14 | "focus": false, 15 | "panel": "shared" 16 | }, 17 | "group": { 18 | "kind": "build", 19 | "isDefault": true 20 | } 21 | }, 22 | { 23 | "label": "Full Build", 24 | "type": "npm", 25 | "script": "build", 26 | "group": "build" 27 | }, 28 | { 29 | "label": "Build Tests", 30 | "type": "npm", 31 | "script": "build-tests", 32 | "group": "build" 33 | }, 34 | { 35 | "label": "TDD", 36 | "type": "npm", 37 | "script": "tdd", 38 | "isBackground": true, 39 | "group": { 40 | "kind": "test", 41 | "isDefault": true 42 | } 43 | }, 44 | { 45 | "label": "Run Tests", 46 | "type": "npm", 47 | "script": "test", 48 | "group": "test" 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.2.1](https://github.com/mike-north/types/compare/v1.2.0...v1.2.1) (2020-02-02) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * build and test infrastructure refactor ([4c71370](https://github.com/mike-north/types/commit/4c713706ee8fdc81630e018f21a0dcdf160e5ba9)) 7 | * fixes to linting and type extraction ([cd2af5b](https://github.com/mike-north/types/commit/cd2af5bf5533d5697c4edfd030c24be6c6a74a48)) 8 | 9 | # [1.2.0](https://github.com/mike-north/types/compare/v1.1.0...v1.2.0) (2019-02-25) 10 | 11 | 12 | ### Features 13 | 14 | * **object:** optional and required property name extraction ([0e5dc1b](https://github.com/mike-north/types/commit/0e5dc1b)) 15 | 16 | # [1.1.0](https://github.com/mike-north/types/compare/v1.0.7...v1.1.0) (2019-01-14) 17 | 18 | 19 | ### Bug Fixes 20 | 21 | * explicit re-exports ([445680f](https://github.com/mike-north/types/commit/445680f)) 22 | * release automation modernization ([c232afc](https://github.com/mike-north/types/commit/c232afc)) 23 | * shared semantic-release and renovate config ([e2f1163](https://github.com/mike-north/types/commit/e2f1163)) 24 | 25 | 26 | ### Features 27 | 28 | * add Dict ([62bdda3](https://github.com/mike-north/types/commit/62bdda3)) 29 | 30 | ## [1.0.7](https://github.com/mike-north/types/compare/v1.0.6...v1.0.7) (2018-11-04) 31 | 32 | 33 | ### Bug Fixes 34 | 35 | * detect problems with TS3 instead of TS2 ([7250142](https://github.com/mike-north/types/commit/7250142)) 36 | 37 | ## [1.0.6](https://github.com/mike-north/types/compare/v1.0.5...v1.0.6) (2018-08-03) 38 | 39 | 40 | ### Bug Fixes 41 | 42 | * AsyncMethodReturns no longer wraps promise return types in additional promises ([68b8239](https://github.com/mike-north/types/commit/68b8239)) 43 | 44 | ## [1.0.5](https://github.com/mike-north/types/compare/v1.0.4...v1.0.5) (2018-08-02) 45 | 46 | 47 | ### Bug Fixes 48 | 49 | * comments and tests ([98da744](https://github.com/mike-north/types/commit/98da744)) 50 | * readme updates ([e205ede](https://github.com/mike-north/types/commit/e205ede)) 51 | * test against node 8, 10 ([94f09b9](https://github.com/mike-north/types/commit/94f09b9)) 52 | * update readme ([ec20a63](https://github.com/mike-north/types/commit/ec20a63)) 53 | 54 | ## [1.0.4](https://github.com/mike-north/types/compare/v1.0.3...v1.0.4) (2018-07-30) 55 | 56 | 57 | ### Bug Fixes 58 | 59 | * publish changelog ([f49de1a](https://github.com/mike-north/types/commit/f49de1a)) 60 | * publish changelog ([bd04b3c](https://github.com/mike-north/types/commit/bd04b3c)) 61 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @mike-north/types 2 | 3 | ![Node.js CI (master)](https://github.com/mike-north/types/workflows/Node.js%20CI%20(master)/badge.svg) 4 | [![Version](https://img.shields.io/npm/v/@mike-north/types.svg)](https://www.npmjs.com/package/@mike-north/types) 5 | 6 | TypeScript `type`s, `interface`s and `class`es I often use. 7 | 8 | ## Types 9 | 10 | - **[`Deferred`](https://github.com/mike-north/types/blob/master/src/async.ts)** - An abstraction of "work in progress". An inverted `Promise` 11 | - **[`ConstructorArgs`](https://github.com/mike-north/types/blob/master/src/classes.ts)** - Extract the arguments from a class constructor 12 | - **[`AsyncMethodReturns`](https://github.com/mike-north/types/blob/master/src/functions.ts)** - Promisify the return values of all methods on a type 13 | - **[`ExtractPropertyNamesOfType`](https://github.com/mike-north/types/blob/master/src/objects.ts)** - Create a string literal type, representing the names of all properties on a type T whose values are assignable to S 14 | - **[`RequiredProps`](https://github.com/mike-north/types/blob/master/src/objects.ts)** - Make properties whose names are assignable to S on object T required 15 | - **[`OptionalProps`](https://github.com/mike-north/types/blob/master/src/objecst.ts)** - Make properties whose names are assignable to S on object T optional 16 | - **[`OptionalPropertyNamesOf`](https://github.com/mike-north/types/blob/master/src/objects.ts)** - Get the names of optional properties of T 17 | - **[`RequiredPropertyNamesOf`](https://github.com/mike-north/types/blob/master/src/objects.ts)** - Get the names of required properties of T 18 | 19 | (c) 2018 Mike North 20 | -------------------------------------------------------------------------------- /api-extractor.json: -------------------------------------------------------------------------------- 1 | /** 2 | * Config file for API Extractor. For more info, please visit: https://api-extractor.com 3 | */ 4 | { 5 | "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", 6 | 7 | /** 8 | * Optionally specifies another JSON config file that this file extends from. This provides a way for 9 | * standard settings to be shared across multiple projects. 10 | * 11 | * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains 12 | * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be 13 | * resolved using NodeJS require(). 14 | * 15 | * SUPPORTED TOKENS: none 16 | * DEFAULT VALUE: "" 17 | */ 18 | // "extends": "./shared/api-extractor-base.json" 19 | // "extends": "my-package/include/api-extractor-base.json" 20 | 21 | /** 22 | * Determines the "" token that can be used with other config file settings. The project folder 23 | * typically contains the tsconfig.json and package.json config files, but the path is user-defined. 24 | * 25 | * The path is resolved relative to the folder of the config file that contains the setting. 26 | * 27 | * The default value for "projectFolder" is the token "", which means the folder is determined by traversing 28 | * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder 29 | * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error 30 | * will be reported. 31 | * 32 | * SUPPORTED TOKENS: 33 | * DEFAULT VALUE: "" 34 | */ 35 | // "projectFolder": "..", 36 | 37 | /** 38 | * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor 39 | * analyzes the symbols exported by this module. 40 | * 41 | * The file extension must be ".d.ts" and not ".ts". 42 | * 43 | * The path is resolved relative to the folder of the config file that contains the setting; to change this, 44 | * prepend a folder token such as "". 45 | * 46 | * SUPPORTED TOKENS: , , 47 | */ 48 | "mainEntryPointFilePath": "/.compiled-types/src/index.d.ts", 49 | 50 | /** 51 | * A list of NPM package names whose exports should be treated as part of this package. 52 | * 53 | * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1", 54 | * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part 55 | * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly 56 | * imports library2. To avoid this, we can specify: 57 | * 58 | * "bundledPackages": [ "library2" ], 59 | * 60 | * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been 61 | * local files for library1. 62 | */ 63 | "bundledPackages": [], 64 | 65 | /** 66 | * Determines how the TypeScript compiler engine will be invoked by API Extractor. 67 | */ 68 | "compiler": { 69 | /** 70 | * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. 71 | * 72 | * The path is resolved relative to the folder of the config file that contains the setting; to change this, 73 | * prepend a folder token such as "". 74 | * 75 | * Note: This setting will be ignored if "overrideTsconfig" is used. 76 | * 77 | * SUPPORTED TOKENS: , , 78 | * DEFAULT VALUE: "/tsconfig.json" 79 | */ 80 | // "tsconfigFilePath": "/tsconfig.json", 81 | /** 82 | * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. 83 | * The object must conform to the TypeScript tsconfig schema: 84 | * 85 | * http://json.schemastore.org/tsconfig 86 | * 87 | * If omitted, then the tsconfig.json file will be read from the "projectFolder". 88 | * 89 | * DEFAULT VALUE: no overrideTsconfig section 90 | */ 91 | // "overrideTsconfig": { 92 | // . . . 93 | // } 94 | /** 95 | * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended 96 | * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when 97 | * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses 98 | * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck. 99 | * 100 | * DEFAULT VALUE: false 101 | */ 102 | // "skipLibCheck": true, 103 | }, 104 | 105 | /** 106 | * Configures how the API report file (*.api.md) will be generated. 107 | */ 108 | "apiReport": { 109 | /** 110 | * (REQUIRED) Whether to generate an API report. 111 | */ 112 | "enabled": true 113 | 114 | /** 115 | * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce 116 | * a full file path. 117 | * 118 | * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". 119 | * 120 | * SUPPORTED TOKENS: , 121 | * DEFAULT VALUE: ".api.md" 122 | */ 123 | // "reportFileName": ".api.md", 124 | 125 | /** 126 | * Specifies the folder where the API report file is written. The file name portion is determined by 127 | * the "reportFileName" setting. 128 | * 129 | * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, 130 | * e.g. for an API review. 131 | * 132 | * The path is resolved relative to the folder of the config file that contains the setting; to change this, 133 | * prepend a folder token such as "". 134 | * 135 | * SUPPORTED TOKENS: , , 136 | * DEFAULT VALUE: "/etc/" 137 | */ 138 | // "reportFolder": "/etc/", 139 | 140 | /** 141 | * Specifies the folder where the temporary report file is written. The file name portion is determined by 142 | * the "reportFileName" setting. 143 | * 144 | * After the temporary file is written to disk, it is compared with the file in the "reportFolder". 145 | * If they are different, a production build will fail. 146 | * 147 | * The path is resolved relative to the folder of the config file that contains the setting; to change this, 148 | * prepend a folder token such as "". 149 | * 150 | * SUPPORTED TOKENS: , , 151 | * DEFAULT VALUE: "/temp/" 152 | */ 153 | // "reportTempFolder": "/temp/" 154 | }, 155 | 156 | /** 157 | * Configures how the doc model file (*.api.json) will be generated. 158 | */ 159 | "docModel": { 160 | /** 161 | * (REQUIRED) Whether to generate a doc model file. 162 | */ 163 | "enabled": true 164 | 165 | /** 166 | * The output path for the doc model file. The file extension should be ".api.json". 167 | * 168 | * The path is resolved relative to the folder of the config file that contains the setting; to change this, 169 | * prepend a folder token such as "". 170 | * 171 | * SUPPORTED TOKENS: , , 172 | * DEFAULT VALUE: "/temp/.api.json" 173 | */ 174 | // "apiJsonFilePath": "/temp/.api.json" 175 | }, 176 | 177 | /** 178 | * Configures how the .d.ts rollup file will be generated. 179 | */ 180 | "dtsRollup": { 181 | /** 182 | * (REQUIRED) Whether to generate the .d.ts rollup file. 183 | */ 184 | "enabled": true, 185 | 186 | /** 187 | * Specifies the output path for a .d.ts rollup file to be generated without any trimming. 188 | * This file will include all declarations that are exported by the main entry point. 189 | * 190 | * If the path is an empty string, then this file will not be written. 191 | * 192 | * The path is resolved relative to the folder of the config file that contains the setting; to change this, 193 | * prepend a folder token such as "". 194 | * 195 | * SUPPORTED TOKENS: , , 196 | * DEFAULT VALUE: "/dist/.d.ts" 197 | */ 198 | "untrimmedFilePath": "/dist/types/-private.d.ts", 199 | 200 | /** 201 | * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. 202 | * This file will include only declarations that are marked as "@public" or "@beta". 203 | * 204 | * The path is resolved relative to the folder of the config file that contains the setting; to change this, 205 | * prepend a folder token such as "". 206 | * 207 | * SUPPORTED TOKENS: , , 208 | * DEFAULT VALUE: "" 209 | */ 210 | "betaTrimmedFilePath": "/dist/types/-beta.d.ts", 211 | 212 | /** 213 | * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. 214 | * This file will include only declarations that are marked as "@public". 215 | * 216 | * If the path is an empty string, then this file will not be written. 217 | * 218 | * The path is resolved relative to the folder of the config file that contains the setting; to change this, 219 | * prepend a folder token such as "". 220 | * 221 | * SUPPORTED TOKENS: , , 222 | * DEFAULT VALUE: "" 223 | */ 224 | "publicTrimmedFilePath": "/dist/types/.d.ts", 225 | 226 | /** 227 | * When a declaration is trimmed, by default it will be replaced by a code comment such as 228 | * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the 229 | * declaration completely. 230 | * 231 | * DEFAULT VALUE: false 232 | */ 233 | "omitTrimmingComments": true 234 | }, 235 | 236 | /** 237 | * Configures how the tsdoc-metadata.json file will be generated. 238 | */ 239 | "tsdocMetadata": { 240 | /** 241 | * Whether to generate the tsdoc-metadata.json file. 242 | * 243 | * DEFAULT VALUE: true 244 | */ 245 | // "enabled": true, 246 | /** 247 | * Specifies where the TSDoc metadata file should be written. 248 | * 249 | * The path is resolved relative to the folder of the config file that contains the setting; to change this, 250 | * prepend a folder token such as "". 251 | * 252 | * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata", 253 | * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup 254 | * falls back to "tsdoc-metadata.json" in the package folder. 255 | * 256 | * SUPPORTED TOKENS: , , 257 | * DEFAULT VALUE: "" 258 | */ 259 | "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" 260 | }, 261 | 262 | /** 263 | * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files 264 | * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead. 265 | * To use the OS's default newline kind, specify "os". 266 | * 267 | * DEFAULT VALUE: "crlf" 268 | */ 269 | // "newlineKind": "crlf", 270 | 271 | /** 272 | * Configures how API Extractor reports error and warning messages produced during analysis. 273 | * 274 | * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages. 275 | */ 276 | "messages": { 277 | /** 278 | * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing 279 | * the input .d.ts files. 280 | * 281 | * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" 282 | * 283 | * DEFAULT VALUE: A single "default" entry with logLevel=warning. 284 | */ 285 | "compilerMessageReporting": { 286 | /** 287 | * Configures the default routing for messages that don't match an explicit rule in this table. 288 | */ 289 | "default": { 290 | /** 291 | * Specifies whether the message should be written to the the tool's output log. Note that 292 | * the "addToApiReportFile" property may supersede this option. 293 | * 294 | * Possible values: "error", "warning", "none" 295 | * 296 | * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail 297 | * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes 298 | * the "--local" option), the warning is displayed but the build will not fail. 299 | * 300 | * DEFAULT VALUE: "warning" 301 | */ 302 | "logLevel": "warning" 303 | 304 | /** 305 | * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), 306 | * then the message will be written inside that file; otherwise, the message is instead logged according to 307 | * the "logLevel" option. 308 | * 309 | * DEFAULT VALUE: false 310 | */ 311 | // "addToApiReportFile": false 312 | } 313 | 314 | // "TS2551": { 315 | // "logLevel": "warning", 316 | // "addToApiReportFile": true 317 | // }, 318 | // 319 | // . . . 320 | }, 321 | 322 | /** 323 | * Configures handling of messages reported by API Extractor during its analysis. 324 | * 325 | * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag" 326 | * 327 | * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings 328 | */ 329 | "extractorMessageReporting": { 330 | "default": { 331 | "logLevel": "warning" 332 | // "addToApiReportFile": false 333 | } 334 | 335 | // "ae-extra-release-tag": { 336 | // "logLevel": "warning", 337 | // "addToApiReportFile": true 338 | // }, 339 | // 340 | // . . . 341 | }, 342 | 343 | /** 344 | * Configures handling of messages reported by the TSDoc parser when analyzing code comments. 345 | * 346 | * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text" 347 | * 348 | * DEFAULT VALUE: A single "default" entry with logLevel=warning. 349 | */ 350 | "tsdocMessageReporting": { 351 | "default": { 352 | "logLevel": "warning" 353 | // "addToApiReportFile": false 354 | } 355 | 356 | // "tsdoc-link-tag-unescaped-text": { 357 | // "logLevel": "warning", 358 | // "addToApiReportFile": true 359 | // }, 360 | // 361 | // . . . 362 | } 363 | } 364 | } 365 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) 4 | 5 | ## API Reference 6 | 7 | ## Packages 8 | 9 | | Package | Description | 10 | | --- | --- | 11 | | [@mike-north/types](./types.md) | | 12 | 13 | -------------------------------------------------------------------------------- /docs/types.asyncmethodreturns.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [AsyncMethodReturns](./types.asyncmethodreturns.md) 4 | 5 | ## AsyncMethodReturns type 6 | 7 | Given a type of object with methods, make some (or all) of the return values "async" (i.e., returning a `string` becomes returning a `Promise`). 8 | 9 | All non-function properties are excluded from the resultant type 10 | 11 | Signature: 12 | 13 | ```typescript 14 | export declare type AsyncMethodReturns = { 15 | [KK in K]: T[KK] extends (...args: any[]) => PromiseLike ? T[KK] : T[KK] extends (...args: infer A) => infer R ? (...args: A) => Promise : T[KK]; 16 | }; 17 | ``` 18 | 19 | ## Example 20 | 21 | 22 | ```ts 23 | 24 | interface User { 25 | isAdmin: boolean; // will not be included 26 | login(): boolean; 27 | resetPassword(): string; 28 | sendEmail(body: string): boolean; 29 | } 30 | const x: AsyncMethodReturns ...; // { 31 | // login(): Promise, 32 | // resetPassword(): Promise 33 | // } 34 | 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /docs/types.constructorargs.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [ConstructorArgs](./types.constructorargs.md) 4 | 5 | ## ConstructorArgs type 6 | 7 | Extract the arguments from a class constructor 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare type ConstructorArgs any> = K extends new () => any ? never[] : K extends new (a: infer A) => any ? [A] : K extends new (a: infer A, b: infer B) => any ? [A, B] : K extends new (a: infer A, b: infer B, c: infer C) => any ? [A, B, C] : K extends new (a: infer A, b: infer B, c: infer C, d: infer D) => any ? [A, B, C, D] : K extends new (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E) => any ? [A, B, C, D, E] : never; 13 | ``` 14 | 15 | ## Example 16 | 17 | 18 | ```ts 19 | class Foo { 20 | constructor(a: string, b: number[], c: Promise) {} 21 | } 22 | const x: ConstructorArgs // [string, number[], Promise] 23 | = ['hello world', [1, 2, 3], Promise.resolve(false) ]; 24 | 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /docs/types.deeppartial.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [DeepPartial](./types.deeppartial.md) 4 | 5 | ## DeepPartial type 6 | 7 | > Warning: This API is now obsolete. 8 | > 9 | > Use of this type is not recommended 10 | > 11 | 12 | Signature: 13 | 14 | ```typescript 15 | export declare type DeepPartial = O extends string | Function | number | boolean ? O : { 16 | [K in keyof O]?: DeepPartial; 17 | }; 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/types.deferred._constructor_.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [Deferred](./types.deferred.md) > [(constructor)](./types.deferred._constructor_.md) 4 | 5 | ## Deferred.(constructor) 6 | 7 | Constructs a new instance of the `Deferred` class 8 | 9 | Signature: 10 | 11 | ```typescript 12 | constructor(); 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/types.deferred.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [Deferred](./types.deferred.md) 4 | 5 | ## Deferred class 6 | 7 | A deferred represents some asynchronous work that is not yet finished, which may or may not culminate in a value. 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare class Deferred 13 | ``` 14 | 15 | ## Example 16 | 17 | 18 | ```ts 19 | // The Deferred represents some work to be done 20 | const d = new Deferred(); 21 | 22 | // in this case, we're accumulating timestamps 23 | const timestamps: Date[] = []; 24 | 25 | // ever 26 | const task = setInterval(() => { 27 | timestamps.push(new Date()); 28 | }, 100); 29 | 30 | d.promise.then(val => { 31 | console.log('work is complete!', val) 32 | }); 33 | 34 | ``` 35 | 36 | ## Constructors 37 | 38 | | Constructor | Modifiers | Description | 39 | | --- | --- | --- | 40 | | [(constructor)()](./types.deferred._constructor_.md) | | Constructs a new instance of the Deferred class | 41 | 42 | ## Properties 43 | 44 | | Property | Modifiers | Type | Description | 45 | | --- | --- | --- | --- | 46 | | [promise](./types.deferred.promise.md) | | PromiseLike<T> | The eventual value that the Deferred's work will eventually calculate; | 47 | | [promiseConstructor](./types.deferred.promiseconstructor.md) | static | PromiseConstructor | The promise constructor to use when instantiating Deferreds. | 48 | | [reject](./types.deferred.reject.md) | | (reason?: any) => any | Indicate the unsuccessful completion (i.e., an error) of whatever work this Deferred represents | 49 | | [resolve](./types.deferred.resolve.md) | | (value?: T \| PromiseLike<T>) => void | Indiate the successful completion of whatever work this Deferred represents | 50 | 51 | -------------------------------------------------------------------------------- /docs/types.deferred.promise.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [Deferred](./types.deferred.md) > [promise](./types.deferred.promise.md) 4 | 5 | ## Deferred.promise property 6 | 7 | The eventual value that the Deferred's work will eventually calculate; 8 | 9 | Signature: 10 | 11 | ```typescript 12 | readonly promise: PromiseLike; 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/types.deferred.promiseconstructor.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [Deferred](./types.deferred.md) > [promiseConstructor](./types.deferred.promiseconstructor.md) 4 | 5 | ## Deferred.promiseConstructor property 6 | 7 | The promise constructor to use when instantiating Deferreds. 8 | 9 | Signature: 10 | 11 | ```typescript 12 | static promiseConstructor: PromiseConstructor; 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/types.deferred.reject.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [Deferred](./types.deferred.md) > [reject](./types.deferred.reject.md) 4 | 5 | ## Deferred.reject property 6 | 7 | Indicate the unsuccessful completion (i.e., an error) of whatever work this Deferred represents 8 | 9 | Signature: 10 | 11 | ```typescript 12 | readonly reject: (reason?: any) => any; 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/types.deferred.resolve.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [Deferred](./types.deferred.md) > [resolve](./types.deferred.resolve.md) 4 | 5 | ## Deferred.resolve property 6 | 7 | Indiate the successful completion of whatever work this Deferred represents 8 | 9 | Signature: 10 | 11 | ```typescript 12 | readonly resolve: (value?: T | PromiseLike) => void; 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/types.dict.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [Dict](./types.dict.md) 4 | 5 | ## Dict interface 6 | 7 | Dictionary 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export interface Dict 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/types.extractargs.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [ExtractArgs](./types.extractargs.md) 4 | 5 | ## ExtractArgs type 6 | 7 | Extract the arguments from a function type, and emit them as a tuple 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare type ExtractArgs = F extends (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E) => any ? [A, B, C, D, E] : F extends (a: infer A, b: infer B, c: infer C, d: infer D) => any ? [A, B, C, D] : F extends (a: infer A, b: infer B, c: infer C) => any ? [A, B, C] : F extends (a: infer A, b: infer B) => any ? [A, B] : F extends (a: infer A) => any ? [A] : F extends () => any ? [] : never; 13 | ``` 14 | 15 | ## Remarks 16 | 17 | Supports up to five arguments, otherwise fails via emitting a `never` 18 | 19 | ## Example 20 | 21 | 22 | ```ts 23 | function foo(a: string, b: number): void { } 24 | type FooArgs = ExtractArgs; // [string, number] 25 | type FooFirstArg = FooArgs[0] // string 26 | 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /docs/types.extractpropertynamesoftype.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [ExtractPropertyNamesOfType](./types.extractpropertynamesoftype.md) 4 | 5 | ## ExtractPropertyNamesOfType type 6 | 7 | Given an object type T, return a type of property names whose values are assignable to type S 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare type ExtractPropertyNamesOfType = { 13 | [K in keyof T]: T[K] extends S ? K : never; 14 | }[keyof T]; 15 | ``` 16 | 17 | ## Example 1 18 | 19 | 20 | ```ts 21 | interface Foo { 22 | a: string; 23 | b: boolean; 24 | c: number[]; 25 | d: Array>; 26 | } 27 | 28 | const stringProps: ExtractPropertyNamesOfType // type: 'a' 29 | = 'a'; 30 | 31 | const arrayProps: ExtractPropertyNamesOfType // type: 'c' | 'd' 32 | = 'c'; 33 | 34 | const notArrayProps: Exclude> // type: 'a' | 'b' 35 | = 'a'; 36 | 37 | ``` 38 | 39 | ## Example 2 40 | 41 | This can be very useful when used in combination with TypeScript's `Pick` utility type 42 | 43 | ```ts 44 | interface Foo { 45 | a: string; 46 | b(): boolean; 47 | c: number[]; 48 | d: Array>; 49 | } 50 | 51 | // Extract from Foo, an object containing only properties with array values 52 | let x: Pick> 53 | = { c: 42, d: [] as Array> }; 54 | 55 | // Get a type with only Foo's methods 56 | let fooMethods: Pick any>> 57 | = { b() { return true; } }; 58 | 59 | ``` 60 | 61 | -------------------------------------------------------------------------------- /docs/types.isdefined.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [isDefined](./types.isdefined.md) 4 | 5 | ## isDefined() function 6 | 7 | Test whether an argument is non-undefined 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare function isDefined(arg: T | undefined): arg is T; 13 | ``` 14 | 15 | ## Parameters 16 | 17 | | Parameter | Type | Description | 18 | | --- | --- | --- | 19 | | arg | T \| undefined | argument to test | 20 | 21 | Returns: 22 | 23 | arg is T 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/types.isnonnull.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [isNonNull](./types.isnonnull.md) 4 | 5 | ## isNonNull() function 6 | 7 | Test whether an argument is non-null 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare function isNonNull(arg: T | null): arg is T; 13 | ``` 14 | 15 | ## Parameters 16 | 17 | | Parameter | Type | Description | 18 | | --- | --- | --- | 19 | | arg | T \| null | argument to test | 20 | 21 | Returns: 22 | 23 | arg is T 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/types.ispresent.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [isPresent](./types.ispresent.md) 4 | 5 | ## isPresent() function 6 | 7 | Test whether an argument is neither null, nor undefined 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare function isPresent(arg: T | null | undefined): arg is T; 13 | ``` 14 | 15 | ## Parameters 16 | 17 | | Parameter | Type | Description | 18 | | --- | --- | --- | 19 | | arg | T \| null \| undefined | argument to test | 20 | 21 | Returns: 22 | 23 | arg is T 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/types.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) 4 | 5 | ## types package 6 | 7 | ## Classes 8 | 9 | | Class | Description | 10 | | --- | --- | 11 | | [Deferred](./types.deferred.md) | A deferred represents some asynchronous work that is not yet finished, which may or may not culminate in a value. | 12 | 13 | ## Functions 14 | 15 | | Function | Description | 16 | | --- | --- | 17 | | [isDefined(arg)](./types.isdefined.md) | Test whether an argument is non-undefined | 18 | | [isNonNull(arg)](./types.isnonnull.md) | Test whether an argument is non-null | 19 | | [isPresent(arg)](./types.ispresent.md) | Test whether an argument is neither null, nor undefined | 20 | 21 | ## Interfaces 22 | 23 | | Interface | Description | 24 | | --- | --- | 25 | | [Dict](./types.dict.md) | Dictionary | 26 | 27 | ## Type Aliases 28 | 29 | | Type Alias | Description | 30 | | --- | --- | 31 | | [AsyncMethodReturns](./types.asyncmethodreturns.md) | Given a type of object with methods, make some (or all) of the return values "async" (i.e., returning a string becomes returning a Promise<string>).All non-function properties are excluded from the resultant type | 32 | | [ConstructorArgs](./types.constructorargs.md) | Extract the arguments from a class constructor | 33 | | [DeepPartial](./types.deeppartial.md) | | 34 | | [ExtractArgs](./types.extractargs.md) | Extract the arguments from a function type, and emit them as a tuple | 35 | | [ExtractPropertyNamesOfType](./types.extractpropertynamesoftype.md) | Given an object type T, return a type of property names whose values are assignable to type S | 36 | | [OptionalPropertyNamesOf](./types.optionalpropertynamesof.md) | Extract the property names of an object type that are optional | 37 | | [OptionalProps](./types.optionalprops.md) | Given an object type, make one or more properties optional | 38 | | [RequiredPropertyNamesOf](./types.requiredpropertynamesof.md) | Extract the property names of an object type that are required | 39 | | [RequiredProps](./types.requiredprops.md) | Given an object type, make one or more properties non-optional | 40 | 41 | -------------------------------------------------------------------------------- /docs/types.optionalpropertynamesof.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [OptionalPropertyNamesOf](./types.optionalpropertynamesof.md) 4 | 5 | ## OptionalPropertyNamesOf type 6 | 7 | Extract the property names of an object type that are optional 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare type OptionalPropertyNamesOf = Exclude<{ 13 | [K in keyof T]: T extends Record ? never : K; 14 | }[keyof T], undefined>; 15 | ``` 16 | 17 | ## Example 18 | 19 | 20 | ```ts 21 | const x: OptionalPropertyOf<{ a: string; b?: number }>; // 'b' 22 | 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /docs/types.optionalprops.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [OptionalProps](./types.optionalprops.md) 4 | 5 | ## OptionalProps type 6 | 7 | Given an object type, make one or more properties optional 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare type OptionalProps = { 13 | [L in K]?: T[L]; 14 | } & { 15 | [M in Exclude]: T[M]; 16 | }; 17 | ``` 18 | 19 | ## Example 20 | 21 | 22 | ```ts 23 | interface Foo { 24 | a: string; 25 | b: boolean; 26 | c: number[]; 27 | } 28 | 29 | const x: OptionalProps = { 30 | a: 'hello world', // still required 31 | b: true // still required 32 | c: [1, 2, 3] // now optional 33 | }; 34 | 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /docs/types.requiredpropertynamesof.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [RequiredPropertyNamesOf](./types.requiredpropertynamesof.md) 4 | 5 | ## RequiredPropertyNamesOf type 6 | 7 | Extract the property names of an object type that are required 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare type RequiredPropertyNamesOf = Exclude<{ 13 | [K in keyof T]: T extends Record ? K : never; 14 | }[keyof T], undefined>; 15 | ``` 16 | 17 | ## Example 18 | 19 | 20 | ```ts 21 | const y: RequiredPropertyOf<{ a: string; b?: number }>; // 'a' 22 | 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /docs/types.requiredprops.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Home](./index.md) > [@mike-north/types](./types.md) > [RequiredProps](./types.requiredprops.md) 4 | 5 | ## RequiredProps type 6 | 7 | Given an object type, make one or more properties non-optional 8 | 9 | Signature: 10 | 11 | ```typescript 12 | export declare type RequiredProps = T & { 13 | [L in K]-?: T[K]; 14 | }; 15 | ``` 16 | 17 | ## Example 18 | 19 | 20 | ```ts 21 | interface Foo { 22 | a?: string; 23 | b?: boolean; 24 | c?: number[]; 25 | } 26 | 27 | const x: RequiredProps = { 28 | a: 'hello world', // now required 29 | b: true // now required 30 | c: [1, 2, 3] // still optional 31 | }; 32 | 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /etc/types.api.md: -------------------------------------------------------------------------------- 1 | ## API Report File for "@mike-north/types" 2 | 3 | > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). 4 | 5 | ```ts 6 | 7 | // @public 8 | export type AsyncMethodReturns = { 9 | [KK in K]: T[KK] extends (...args: any[]) => PromiseLike ? T[KK] : T[KK] extends (...args: infer A) => infer R ? (...args: A) => Promise : T[KK]; 10 | }; 11 | 12 | // @public 13 | export type ConstructorArgs any> = K extends new () => any ? never[] : K extends new (a: infer A) => any ? [A] : K extends new (a: infer A, b: infer B) => any ? [A, B] : K extends new (a: infer A, b: infer B, c: infer C) => any ? [A, B, C] : K extends new (a: infer A, b: infer B, c: infer C, d: infer D) => any ? [A, B, C, D] : K extends new (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E) => any ? [A, B, C, D, E] : never; 14 | 15 | // @public @deprecated (undocumented) 16 | export type DeepPartial = O extends string | Function | number | boolean ? O : { 17 | [K in keyof O]?: DeepPartial; 18 | }; 19 | 20 | // @public 21 | export class Deferred { 22 | constructor(); 23 | readonly promise: PromiseLike; 24 | static promiseConstructor: PromiseConstructor; 25 | readonly reject: (reason?: any) => any; 26 | readonly resolve: (value?: T | PromiseLike) => void; 27 | } 28 | 29 | // @public 30 | export interface Dict { 31 | // (undocumented) 32 | [k: string]: T | undefined; 33 | } 34 | 35 | // @public 36 | export type ExtractArgs = F extends (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E) => any ? [A, B, C, D, E] : F extends (a: infer A, b: infer B, c: infer C, d: infer D) => any ? [A, B, C, D] : F extends (a: infer A, b: infer B, c: infer C) => any ? [A, B, C] : F extends (a: infer A, b: infer B) => any ? [A, B] : F extends (a: infer A) => any ? [A] : F extends () => any ? [] : never; 37 | 38 | // @public 39 | export type ExtractPropertyNamesOfType = { 40 | [K in keyof T]: T[K] extends S ? K : never; 41 | }[keyof T]; 42 | 43 | // @public 44 | export function isDefined(arg: T | undefined): arg is T; 45 | 46 | // @public 47 | export function isNonNull(arg: T | null): arg is T; 48 | 49 | // @public 50 | export function isPresent(arg: T | null | undefined): arg is T; 51 | 52 | // @public 53 | export type OptionalPropertyNamesOf = Exclude<{ 54 | [K in keyof T]: T extends Record ? never : K; 55 | }[keyof T], undefined>; 56 | 57 | // @public 58 | export type OptionalProps = { 59 | [L in K]?: T[L]; 60 | } & { 61 | [M in Exclude]: T[M]; 62 | }; 63 | 64 | // @public 65 | export type RequiredPropertyNamesOf = Exclude<{ 66 | [K in keyof T]: T extends Record ? K : never; 67 | }[keyof T], undefined>; 68 | 69 | // @public 70 | export type RequiredProps = T & { 71 | [L in K]-?: T[K]; 72 | }; 73 | 74 | 75 | // (No @packageDocumentation comment for this package) 76 | 77 | ``` 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mike-north/types", 3 | "version": "1.4.0", 4 | "description": "TypeScript types/interfaces I often use for small libraries", 5 | "main": "dist/commonjs/src/index.js", 6 | "module": "dist/modules/src/index.js", 7 | "typings": "dist/types/types.d.ts", 8 | "scripts": { 9 | "prepublishOnly": "yarn clean && yarn build", 10 | "preversion": "yarn test", 11 | "clean": "scripty", 12 | "lint": "yarn eslint -c ./.eslintrc.js --ext .ts src test type-tests", 13 | "pretest": "scripty", 14 | "test": "scripty", 15 | "build": "SCRIPTY_PARALLEL=true scripty", 16 | "travis-deploy-once": "travis-deploy-once", 17 | "semantic-release": "semantic-release" 18 | }, 19 | "license": "MIT", 20 | "devDependencies": { 21 | "@commitlint/cli": "8.3.5", 22 | "@commitlint/config-conventional": "8.3.4", 23 | "@microsoft/api-documenter": "7.8.17", 24 | "@microsoft/api-extractor": "7.9.0", 25 | "@mike-north/js-lib-renovate-config": "1.3.1", 26 | "@types/qunit": "2.9.1", 27 | "@typescript-eslint/eslint-plugin": "2.30.0", 28 | "@typescript-eslint/parser": "2.30.0", 29 | "dtslint": "1.0.3", 30 | "eslint": "6.8.0", 31 | "eslint-config-prettier": "6.11.0", 32 | "eslint-plugin-import": "2.21.1", 33 | "eslint-plugin-node": "11.1.0", 34 | "eslint-plugin-prettier": "3.3.1", 35 | "eslint-plugin-promise": "4.3.1", 36 | "husky": "3.1.0", 37 | "prettier": "1.19.1", 38 | "qunit": "2.9.3", 39 | "qunit-decorators": "1.1.5", 40 | "rimraf": "3.0.2", 41 | "scripty": "1.9.1", 42 | "typescript": "3.7.5" 43 | }, 44 | "repository": { 45 | "type": "git", 46 | "url": "https://github.com/mike-north/types.git" 47 | }, 48 | "plublishConfig": { 49 | "access": "public", 50 | "tag": "next" 51 | }, 52 | "commitlint": { 53 | "extends": [ 54 | "@commitlint/config-conventional" 55 | ] 56 | }, 57 | "husky": { 58 | "hooks": { 59 | "commit-msg": "./node_modules/.bin/commitlint -e $HUSKY_GIT_PARAMS" 60 | } 61 | }, 62 | "engines": { 63 | "node": "8.11 - 8.17 || 10.* || >= 12" 64 | }, 65 | "volta": { 66 | "node": "14.17.1", 67 | "yarn": "1.22.10" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@mike-north/js-lib-renovate-config"] 3 | } 4 | -------------------------------------------------------------------------------- /scripts/build/commonjs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yarn tsc -p . -------------------------------------------------------------------------------- /scripts/build/es6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yarn tsc -p . --module esnext --outdir dist/modules -------------------------------------------------------------------------------- /scripts/build/types.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yarn rimraf .compiled-types temp && \ 3 | yarn tsc -p . --declaration true --declarationMap true --outdir .compiled-types && \ 4 | yarn api-extractor run --verbose && \ 5 | yarn api-documenter markdown -i temp -o docs -------------------------------------------------------------------------------- /scripts/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yarn rimraf dist .compiled-types .test-js -------------------------------------------------------------------------------- /scripts/pretest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yarn lint && yarn tsc -p test -------------------------------------------------------------------------------- /scripts/test/ts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yarn qunit .test-js/**/*.test.js -------------------------------------------------------------------------------- /scripts/test/types.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yarn dtslint type-tests -------------------------------------------------------------------------------- /src/async.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A deferred represents some asynchronous work that is not yet finished, which 3 | * may or may not culminate in a value. 4 | * 5 | * @public 6 | * @example 7 | * ```ts 8 | * // The Deferred represents some work to be done 9 | * const d = new Deferred(); 10 | * 11 | * // in this case, we're accumulating timestamps 12 | * const timestamps: Date[] = []; 13 | * 14 | * // ever 15 | * const task = setInterval(() => { 16 | * timestamps.push(new Date()); 17 | * }, 100); 18 | * 19 | * d.promise.then(val => { 20 | * console.log('work is complete!', val) 21 | * }); 22 | * ``` 23 | */ 24 | export class Deferred { 25 | /** 26 | * The promise constructor to use when instantiating Deferreds. 27 | */ 28 | public static promiseConstructor: PromiseConstructor = Promise; 29 | /** 30 | * The eventual value that the Deferred's work will eventually calculate; 31 | */ 32 | public readonly promise!: PromiseLike; 33 | /** 34 | * Indiate the successful completion of whatever work this Deferred represents 35 | * 36 | * @param value - the value that this Deferred's promise will resolve to 37 | * 38 | */ 39 | public readonly resolve!: (value?: T | PromiseLike) => void; 40 | /** 41 | * Indicate the unsuccessful completion (i.e., an error) of whatever work this Deferred represents 42 | * 43 | * @param reason - information about the reason for failure 44 | */ 45 | public readonly reject!: (reason?: any) => any; 46 | public constructor() { 47 | (this as any).promise = new Deferred.promiseConstructor((res, rej) => { 48 | (this as any).resolve = res; 49 | (this as any).reject = rej; 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/classes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Extract the arguments from a class constructor 3 | * 4 | * @public 5 | * @example 6 | * ```ts 7 | * class Foo { 8 | * constructor(a: string, b: number[], c: Promise) {} 9 | * } 10 | * const x: ConstructorArgs // [string, number[], Promise] 11 | * = ['hello world', [1, 2, 3], Promise.resolve(false) ]; 12 | * ``` 13 | */ 14 | export type ConstructorArgs< 15 | K extends new (...args: any[]) => any 16 | > = K extends new () => any 17 | ? never[] 18 | : K extends new (a: infer A) => any 19 | ? [A] 20 | : K extends new (a: infer A, b: infer B) => any 21 | ? [A, B] 22 | : K extends new (a: infer A, b: infer B, c: infer C) => any 23 | ? [A, B, C] 24 | : K extends new (a: infer A, b: infer B, c: infer C, d: infer D) => any 25 | ? [A, B, C, D] 26 | : K extends new ( 27 | a: infer A, 28 | b: infer B, 29 | c: infer C, 30 | d: infer D, 31 | e: infer E 32 | ) => any 33 | ? [A, B, C, D, E] 34 | : never; 35 | -------------------------------------------------------------------------------- /src/dict.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Dictionary 3 | * @public 4 | */ 5 | export interface Dict { 6 | [k: string]: T | undefined; 7 | } 8 | -------------------------------------------------------------------------------- /src/functions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Given a type of object with methods, make some (or all) of the return values 3 | * "async" (i.e., returning a `string` becomes returning a `Promise`). 4 | * 5 | * All non-function properties are excluded from the resultant type 6 | * 7 | * @public 8 | * @example 9 | * ```ts 10 | * 11 | * interface User { 12 | * isAdmin: boolean; // will not be included 13 | * login(): boolean; 14 | * resetPassword(): string; 15 | * sendEmail(body: string): boolean; 16 | * } 17 | * const x: AsyncMethodReturns ...; // { 18 | * // login(): Promise, 19 | * // resetPassword(): Promise 20 | * // } 21 | * ``` 22 | * 23 | */ 24 | export type AsyncMethodReturns = { 25 | [KK in K]: T[KK] extends (...args: any[]) => PromiseLike 26 | ? T[KK] 27 | : T[KK] extends (...args: infer A) => infer R 28 | ? (...args: A) => Promise 29 | : T[KK]; 30 | }; 31 | 32 | /** 33 | * Extract the arguments from a function type, and emit them as a tuple 34 | * @public 35 | * 36 | * @remarks 37 | * Supports up to five arguments, otherwise fails via emitting a `never` 38 | * 39 | * @example 40 | * ```ts 41 | * function foo(a: string, b: number): void { } 42 | * type FooArgs = ExtractArgs; // [string, number] 43 | * type FooFirstArg = FooArgs[0] // string 44 | * ``` 45 | */ 46 | export declare type ExtractArgs = F extends ( 47 | a: infer A, 48 | b: infer B, 49 | c: infer C, 50 | d: infer D, 51 | e: infer E 52 | ) => any 53 | ? [A, B, C, D, E] 54 | : F extends (a: infer A, b: infer B, c: infer C, d: infer D) => any 55 | ? [A, B, C, D] 56 | : F extends (a: infer A, b: infer B, c: infer C) => any 57 | ? [A, B, C] 58 | : F extends (a: infer A, b: infer B) => any 59 | ? [A, B] 60 | : F extends (a: infer A) => any 61 | ? [A] 62 | : F extends () => any 63 | ? [] 64 | : never; 65 | -------------------------------------------------------------------------------- /src/guards.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Test whether an argument is non-undefined 3 | * @param arg - argument to test 4 | * @returns 5 | * 6 | * @public 7 | */ 8 | export function isDefined(arg: T | undefined): arg is T { 9 | return typeof arg !== 'undefined'; 10 | } 11 | /** 12 | * Test whether an argument is non-null 13 | * @param arg - argument to test 14 | * @returns 15 | * 16 | * @public 17 | */ 18 | export function isNonNull(arg: T | null): arg is T { 19 | return arg !== null; 20 | } 21 | /** 22 | * Test whether an argument is neither null, nor undefined 23 | * @param arg - argument to test 24 | * @returns 25 | * 26 | * @public 27 | */ 28 | export function isPresent(arg: T | null | undefined): arg is T { 29 | return !isDefined(arg) && !isNonNull(arg); 30 | } 31 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { isDefined, isNonNull, isPresent } from './guards'; 2 | export { Dict } from './dict'; 3 | export { 4 | ExtractPropertyNamesOfType, 5 | OptionalProps, 6 | RequiredProps, 7 | OptionalPropertyNamesOf, 8 | RequiredPropertyNamesOf, 9 | DeepPartial 10 | } from './objects'; 11 | export { Deferred } from './async'; 12 | export { AsyncMethodReturns, ExtractArgs } from './functions'; 13 | export { ConstructorArgs } from './classes'; 14 | -------------------------------------------------------------------------------- /src/objects.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Given an object type, make one or more properties non-optional 3 | * 4 | * @public 5 | * @example 6 | * 7 | * ```ts 8 | * interface Foo { 9 | * a?: string; 10 | * b?: boolean; 11 | * c?: number[]; 12 | * } 13 | * 14 | * const x: RequiredProps = { 15 | * a: 'hello world', // now required 16 | * b: true // now required 17 | * c: [1, 2, 3] // still optional 18 | * }; 19 | * ``` 20 | */ 21 | export type RequiredProps = T & { [L in K]-?: T[K] }; 22 | 23 | /** 24 | * Given an object type, make one or more properties optional 25 | * 26 | * @public 27 | * @example 28 | * ```ts 29 | * interface Foo { 30 | * a: string; 31 | * b: boolean; 32 | * c: number[]; 33 | * } 34 | * 35 | * const x: OptionalProps = { 36 | * a: 'hello world', // still required 37 | * b: true // still required 38 | * c: [1, 2, 3] // now optional 39 | * }; 40 | * ``` 41 | * 42 | */ 43 | export type OptionalProps = { [L in K]?: T[L] } & 44 | { [M in Exclude]: T[M] }; 45 | 46 | /** 47 | * Given an object type T, return a type of property names whose values are assignable to type S 48 | * 49 | * @public 50 | * @example 51 | * ```ts 52 | * interface Foo { 53 | * a: string; 54 | * b: boolean; 55 | * c: number[]; 56 | * d: Array>; 57 | * } 58 | * 59 | * const stringProps: ExtractPropertyNamesOfType // type: 'a' 60 | * = 'a'; 61 | * 62 | * const arrayProps: ExtractPropertyNamesOfType // type: 'c' | 'd' 63 | * = 'c'; 64 | * 65 | * const notArrayProps: Exclude> // type: 'a' | 'b' 66 | * = 'a'; 67 | * ``` 68 | * 69 | * 70 | * @example 71 | * This can be very useful when used in combination with TypeScript's `Pick` utility type 72 | * ```ts 73 | * interface Foo { 74 | * a: string; 75 | * b(): boolean; 76 | * c: number[]; 77 | * d: Array>; 78 | * } 79 | * 80 | * // Extract from Foo, an object containing only properties with array values 81 | * let x: Pick> 82 | * = { c: 42, d: [] as Array> }; 83 | * 84 | * // Get a type with only Foo's methods 85 | * let fooMethods: Pick any>> 86 | * = { b() { return true; } }; 87 | * ``` 88 | */ 89 | export type ExtractPropertyNamesOfType = { 90 | [K in keyof T]: T[K] extends S ? K : never; 91 | }[keyof T]; 92 | 93 | /** 94 | * Extract the property names of an object type that are optional 95 | * @public 96 | * @example 97 | * ```ts 98 | * const x: OptionalPropertyOf<{ a: string; b?: number }>; // 'b' 99 | * ``` 100 | * 101 | */ 102 | export type OptionalPropertyNamesOf = Exclude< 103 | { [K in keyof T]: T extends Record ? never : K }[keyof T], 104 | undefined 105 | >; 106 | 107 | /** 108 | * Extract the property names of an object type that are required 109 | * @public 110 | * @example 111 | * ```ts 112 | * const y: RequiredPropertyOf<{ a: string; b?: number }>; // 'a' 113 | * ``` 114 | */ 115 | export type RequiredPropertyNamesOf = Exclude< 116 | { [K in keyof T]: T extends Record ? K : never }[keyof T], 117 | undefined 118 | >; 119 | 120 | /** 121 | * @public 122 | * @deprecated 123 | * Use of this type is not recommended 124 | */ 125 | export declare type DeepPartial = O extends 126 | | string 127 | | Function 128 | | number 129 | | boolean 130 | ? O 131 | : { 132 | [K in keyof O]?: DeepPartial; 133 | }; 134 | -------------------------------------------------------------------------------- /test/async-method-returns.test.ts: -------------------------------------------------------------------------------- 1 | import { suite, test } from 'qunit-decorators'; 2 | import { AsyncMethodReturns } from '..'; 3 | 4 | @suite 5 | export class AsyncMethodReturnsTests { 6 | @test 'zero-argument constructor case'(assert: Assert) { 7 | class C { 8 | foo() { 9 | return ''; 10 | } 11 | bar() { 12 | return 61; 13 | } 14 | } 15 | const x: AsyncMethodReturns = { 16 | foo() { 17 | return Promise.resolve(''); 18 | }, 19 | bar() { 20 | return Promise.resolve(99); 21 | } 22 | }; 23 | assert.ok(x); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/constructor-args.test.ts: -------------------------------------------------------------------------------- 1 | import { suite, test } from 'qunit-decorators'; 2 | import { ConstructorArgs } from '..'; 3 | 4 | @suite 5 | export class ConstructorArgsTests { 6 | @test 'zero-argument constructor case'(assert: Assert) { 7 | class C { 8 | // eslint-disable-next-line @typescript-eslint/no-empty-function 9 | constructor() {} 10 | } 11 | const x: ConstructorArgs = []; 12 | const y: never[] = x; 13 | assert.ok(x); 14 | assert.ok(y); 15 | } 16 | @test 'one-argument constructor case'(assert: Assert) { 17 | class C { 18 | // eslint-disable-next-line @typescript-eslint/no-empty-function 19 | constructor(_a: string) {} 20 | } 21 | const x: ConstructorArgs = ['hello']; 22 | const y: [string] = x; 23 | assert.ok(x); 24 | assert.ok(y); 25 | } 26 | @test 'multi-argument constructor case'(assert: Assert) { 27 | class C { 28 | // eslint-disable-next-line @typescript-eslint/no-empty-function 29 | constructor(_a: string, _b: number[], _c: boolean) {} 30 | } 31 | const x: ConstructorArgs = ['hello', [42, 42], true]; 32 | const y: [string, number[], boolean] = x; 33 | assert.ok(x); 34 | assert.ok(y); 35 | } 36 | 37 | // // Doesn't work yet due to TS limitation 38 | // @test 'overloaded constructor case'(assert: Assert) { 39 | // class C { 40 | // x!: boolean; 41 | // constructor(a: string, b: number, c: boolean); 42 | // constructor(a: number, b: string, c: boolean); 43 | // constructor(a: any, b: any, c: any) {} 44 | // } 45 | // let x: ConstructorArgs = [41, 'hello', true]; 46 | // x = ['hello', 41, true]; 47 | // // const y: [string, number[], boolean] = x; 48 | // assert.expect(0); 49 | // } 50 | } 51 | -------------------------------------------------------------------------------- /test/deferred.test.ts: -------------------------------------------------------------------------------- 1 | import { Deferred } from '..'; 2 | import { suite, test } from 'qunit-decorators'; 3 | 4 | @suite 5 | export class DeferredTests { 6 | @test public 'Constructor does not error'(assert: Assert) { 7 | const d = new Deferred(); 8 | assert.ok(d, 'instance is defined'); 9 | assert.equal( 10 | typeof d.resolve, 11 | 'function', 12 | 'resolve property is a function' 13 | ); 14 | assert.equal(typeof d.reject, 'function', 'reject property is a function'); 15 | assert.equal( 16 | typeof d.promise.then, 17 | 'function', 18 | 'promise property looks like a promise' 19 | ); 20 | } 21 | @test public async 'promise resolves when Deferred#resolve() is called'( 22 | assert: Assert 23 | ) { 24 | assert.expect(2); 25 | const d = new Deferred(); 26 | setTimeout(() => { 27 | d.resolve(42); 28 | assert.ok(true); 29 | }, 30); 30 | const val = await d.promise; 31 | assert.equal(val, 42, 'value is correct'); 32 | } 33 | @test public async 'promise rejects when Deferred#reject() is called'( 34 | assert: Assert 35 | ) { 36 | assert.expect(3); 37 | const d = new Deferred(); 38 | setTimeout(() => { 39 | assert.ok(true); 40 | d.reject(-42); 41 | }, 30); 42 | try { 43 | await d.promise; 44 | assert.ok(false); // should never reach this line 45 | } catch (e) { 46 | assert.equal(e, -42, 'value is correct'); 47 | } finally { 48 | assert.ok(true); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/object-utils.test.ts: -------------------------------------------------------------------------------- 1 | import { suite, test } from 'qunit-decorators'; 2 | import { 3 | Dict, 4 | OptionalPropertyNamesOf, 5 | OptionalProps, 6 | RequiredPropertyNamesOf, 7 | RequiredProps 8 | } from '..'; 9 | 10 | @suite 11 | export class ObjectUtilsTest { 12 | @test public RequiredProps(assert: Assert): void { 13 | interface A { 14 | a?: number; 15 | b?: string; 16 | } 17 | type Arequired = RequiredProps; 18 | let x: Arequired = { a: 51 }; 19 | x = { a: 22, b: 'foo' }; 20 | assert.ok(x); 21 | } 22 | @test public OptionalProps(assert: Assert): void { 23 | interface A { 24 | a: number; 25 | b: string; 26 | } 27 | type Aoptional = OptionalProps; 28 | let x: Aoptional = { b: '51' }; 29 | x = { a: 22, b: 'foo' }; 30 | assert.ok(x); 31 | } 32 | @test 'Dict tests'(assert: Assert) { 33 | interface A { 34 | a: number; 35 | b: string; 36 | } 37 | const aDict: Dict = {}; 38 | aDict.foo = { a: 22, b: 'abc' }; 39 | assert.ok(aDict.foo); 40 | } 41 | 42 | @test 'OptionalPropertyNamesOf tests'(assert: Assert) { 43 | const x: OptionalPropertyNamesOf<{ a: string; b?: number }> = 'b'; 44 | // eslint-disable-next-line @typescript-eslint/no-empty-function 45 | function foo(_arg: 'b') {} 46 | foo(x); 47 | assert.ok(x); 48 | } 49 | 50 | @test 'RequiredPropertyNamesOf tests'(assert: Assert) { 51 | const y: RequiredPropertyNamesOf<{ a: string; b?: number }> = 'a'; 52 | // eslint-disable-next-line @typescript-eslint/no-empty-function 53 | function foo(_arg: 'a') {} 54 | foo(y); 55 | assert.ok(y); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2017", 5 | "outDir": "../.test-js", 6 | "strict": true, 7 | "types": ["qunit"], 8 | "experimentalDecorators": true, 9 | "baseUrl": ".", 10 | "paths": { 11 | "@mike-north/types": [".."] 12 | } 13 | }, 14 | "references": [{ "path": ".." }], 15 | "include": ["."] 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "target": "es2017", 5 | "stripInternal": true, 6 | "strict": true, 7 | "module": "CommonJS", 8 | "outDir": "dist/commonjs", 9 | "noImplicitAny": true, 10 | "strictNullChecks": true, 11 | "noImplicitThis": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "moduleResolution": "node", 17 | "baseUrl": ".", 18 | "types": [], 19 | "sourceRoot": ".", 20 | "rootDir": ".", 21 | "inlineSourceMap": true, 22 | "inlineSources": true, 23 | "experimentalDecorators": true 24 | }, 25 | 26 | "include": ["src"] 27 | } 28 | -------------------------------------------------------------------------------- /type-tests/index.d.ts: -------------------------------------------------------------------------------- 1 | // TypeScript Version: 3.0 2 | export * from '..'; 3 | -------------------------------------------------------------------------------- /type-tests/object.test.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-unresolved 2 | import { DeepPartial } from '@mike-north/types'; 3 | 4 | function makeDeepPartial(arg: T): DeepPartial { 5 | return {} as any; 6 | } 7 | const val = 3231 as 3231; 8 | makeDeepPartial({ a: 1, b: 'abc' }); // $ExpectType { a?: number | undefined; b?: string | undefined; } 9 | makeDeepPartial({ a: val, b: 'abc' }); // $ExpectType { a?: 3231 | undefined; b?: string | undefined; } 10 | -------------------------------------------------------------------------------- /type-tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "lib": ["es6"], 5 | "noImplicitAny": true, 6 | "noImplicitThis": true, 7 | "strictNullChecks": true, 8 | "strictFunctionTypes": true, 9 | "noEmit": true, 10 | 11 | // If the library is an external module (uses `export`), this allows your test file to import "mylib" instead of "./index". 12 | // If the library is global (cannot be imported via `import` or `require`), leave this out. 13 | "baseUrl": ".", 14 | "paths": { "@mike-north/types": ["../dist/types/types.d.ts"] } 15 | }, 16 | "include": ["."] 17 | } 18 | -------------------------------------------------------------------------------- /type-tests/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "dtslint/dtslint.json", // Or "dtslint/dt.json" if on DefinitelyTyped 3 | "rules": { 4 | "semicolon": false, 5 | "strict-export-declare-modifiers": false 6 | } 7 | } 8 | --------------------------------------------------------------------------------