├── .eslintrc ├── .github └── workflows │ └── nodejs.yml ├── .gitignore ├── .node-version ├── .npmignore ├── .vscode └── settings.json ├── README.ja.md ├── README.md ├── __tests__ └── index.spec.ts ├── jest.config.js ├── package.json ├── src └── index.ts ├── tsconfig.json └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "plugin:@typescript-eslint/recommended", 4 | "plugin:import/typescript", 5 | "prettier" 6 | ], 7 | "plugins": ["@typescript-eslint", "jest", "prettier"], 8 | "parserOptions": { 9 | "parser": "@typescript-eslint/parser" 10 | }, 11 | "env": { 12 | "browser": true, 13 | "jest/globals": true 14 | }, 15 | "rules": { 16 | "@typescript-eslint/ban-types": "off", 17 | "no-plusplus": 0, 18 | "prettier/prettier": ["error", { 19 | "arrowParens": "always", 20 | "printWidth": 140, 21 | "singleQuote": true, 22 | "trailingComma": "all", 23 | "semi": false 24 | }], 25 | "import/prefer-default-export": "off", 26 | "object-shorthand": ["error", "properties"], 27 | "prefer-destructuring": ["error", { 28 | "array": false, 29 | "object": true 30 | }, { 31 | "enforceForRenamedProperties": false 32 | }], 33 | "@typescript-eslint/no-unused-vars": ["error", { 34 | "vars": "all", 35 | "args": "after-used", 36 | "ignoreRestSiblings": false 37 | }], 38 | "@typescript-eslint/explicit-function-return-type": "off", 39 | "@typescript-eslint/no-var-requires": "off", 40 | "@typescript-eslint/camelcase": "off", 41 | "@typescript-eslint/member-delimiter-style": ["error", { 42 | "multiline": { 43 | "delimiter": "none", 44 | "requireLast": false 45 | }, 46 | "singleline": { 47 | "delimiter": "semi", 48 | "requireLast": false 49 | } 50 | }], 51 | "no-underscore-dangle": ["error", { 52 | "allowAfterThis": true 53 | }], 54 | "@typescript-eslint/no-explicit-any": 0 55 | }, 56 | "overrides": [{ 57 | "files": ["*.ts", "*.tsx"], 58 | "rules": { 59 | "@typescript-eslint/no-var-requires": ["error"], 60 | "@typescript-eslint/no-useless-constructor": [ 61 | "error" 62 | ] 63 | } 64 | }] 65 | } 66 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node-version: [12.x] 11 | steps: 12 | - uses: actions/checkout@v1 13 | - name: Use Node.js ${{ matrix.node-version }} 14 | uses: actions/setup-node@v1 15 | with: 16 | node-version: ${{ matrix.node-version }} 17 | - name: npm install, lint 18 | run: | 19 | yarn install 20 | yarn lint 21 | env: 22 | CI: true 23 | 24 | build: 25 | runs-on: ubuntu-latest 26 | strategy: 27 | matrix: 28 | node-version: [12.x] 29 | steps: 30 | - uses: actions/checkout@v1 31 | - name: Use Node.js ${{ matrix.node-version }} 32 | uses: actions/setup-node@v1 33 | with: 34 | node-version: ${{ matrix.node-version }} 35 | - name: npm install, build 36 | run: | 37 | yarn install 38 | yarn build 39 | env: 40 | CI: true 41 | 42 | test: 43 | runs-on: ubuntu-latest 44 | strategy: 45 | matrix: 46 | node-version: [12.x] 47 | steps: 48 | - uses: actions/checkout@v1 49 | - name: Use Node.js ${{ matrix.node-version }} 50 | uses: actions/setup-node@v1 51 | with: 52 | node-version: ${{ matrix.node-version }} 53 | - name: npm install, test 54 | run: | 55 | yarn install 56 | yarn test 57 | env: 58 | CI: true 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/f9291de89f5f7dc0d3d87f9eb111b839f81d5dbc/Global/macOS.gitignore 2 | 3 | # General 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | 31 | 32 | ### https://raw.github.com/github/gitignore/f9291de89f5f7dc0d3d87f9eb111b839f81d5dbc/Node.gitignore 33 | 34 | # Logs 35 | logs 36 | *.log 37 | npm-debug.log* 38 | yarn-debug.log* 39 | yarn-error.log* 40 | lerna-debug.log* 41 | 42 | # Diagnostic reports (https://nodejs.org/api/report.html) 43 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 44 | 45 | # Runtime data 46 | pids 47 | *.pid 48 | *.seed 49 | *.pid.lock 50 | 51 | # Directory for instrumented libs generated by jscoverage/JSCover 52 | lib-cov 53 | 54 | # Coverage directory used by tools like istanbul 55 | coverage 56 | *.lcov 57 | 58 | # nyc test coverage 59 | .nyc_output 60 | 61 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 62 | .grunt 63 | 64 | # Bower dependency directory (https://bower.io/) 65 | bower_components 66 | 67 | # node-waf configuration 68 | .lock-wscript 69 | 70 | # Compiled binary addons (https://nodejs.org/api/addons.html) 71 | build/Release 72 | 73 | # Dependency directories 74 | node_modules/ 75 | jspm_packages/ 76 | 77 | # TypeScript v1 declaration files 78 | typings/ 79 | 80 | # TypeScript cache 81 | *.tsbuildinfo 82 | 83 | # Optional npm cache directory 84 | .npm 85 | 86 | # Optional eslint cache 87 | .eslintcache 88 | 89 | # Optional REPL history 90 | .node_repl_history 91 | 92 | # Output of 'npm pack' 93 | *.tgz 94 | 95 | # Yarn Integrity file 96 | .yarn-integrity 97 | 98 | # dotenv environment variables file 99 | .env 100 | .env.test 101 | 102 | # parcel-bundler cache (https://parceljs.org/) 103 | .cache 104 | 105 | # next.js build output 106 | .next 107 | 108 | # nuxt.js build output 109 | .nuxt 110 | 111 | # vuepress build output 112 | .vuepress/dist 113 | 114 | # Serverless directories 115 | .serverless/ 116 | 117 | # FuseBox cache 118 | .fusebox/ 119 | 120 | # DynamoDB Local files 121 | .dynamodb/ 122 | 123 | lib/ 124 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 12.7.0 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | __tests__ 2 | src 3 | .github 4 | .vscode 5 | .eslintrc 6 | .node-version 7 | jest.config.js 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } 4 | -------------------------------------------------------------------------------- /README.ja.md: -------------------------------------------------------------------------------- 1 | # Vue Props Type 2 | 3 | `Vue Props Type`は`Vue.js`の`props`の型定義を助けます. 4 | 5 | ## Why 6 | 7 | composition-apiを利用したコードを書く場合、以下のように書く必要があります. 8 | 9 | ```typescript 10 | import { defineComponent } from '@vue/composition-api' 11 | 12 | export type HogeHogeProps = { 13 | A: 'github' | 'qiita' | 'facebook' 14 | B: 0 | 1 | Date 15 | C: { label: string, value: string } 16 | D: string[] 17 | E: string | number 18 | F: (key: string, value: string) => void 19 | } 20 | 21 | export default defineComponent({ 22 | name: 'HogeHoge', 23 | props: { 24 | A: { 25 | type: String, 26 | default: () => 'github' 27 | }, 28 | B: { 29 | type: [Number, Date], 30 | required: true, 31 | }, 32 | C: { 33 | type: Object, 34 | required: true, 35 | }, 36 | D: { 37 | type: Array, 38 | required: true, 39 | }, 40 | E: [String, Number], 41 | F: Function, 42 | }, 43 | setup(props) { 44 | // props is type safe 45 | }, 46 | }) 47 | ``` 48 | 49 | `Option`に渡す`props object`と型定義の`Props type`は別々で定義されおり、素直に書く場合は、人の手により両方をメンテナンスする必用があります. 50 | これには課題があり、もし`props object`のコードを変更し、`Props type`の修正を忘れた場合、`HogeHogeProps type`又は`props object`は嘘をつくことになります. 51 | 人によっては`props object`の項目が多い場合、`Props type`の型定義をサボりたくなるでしょう. 52 | 人によっては`setup`内でアクセスしている`props object`の項目の型定義しか書かない可能性もあります. 53 | 以下がその例です. 54 | 55 | ```typescript 56 | import { defineComponent } from '@vue/composition-api' 57 | 58 | export type HogeHogeProps = { 59 | A: 'github' | 'qiita' | 'facebook' 60 | } 61 | 62 | export default defineComponent({ 63 | name: 'HogeHoge', 64 | props: { 65 | A: { 66 | type: String, 67 | default: () => 'github' 68 | }, 69 | B: { 70 | type: [Number, Date], 71 | required: true, 72 | }, 73 | C: { 74 | type: Object, 75 | required: true, 76 | }, 77 | D: { 78 | type: Array, 79 | required: true, 80 | }, 81 | E: [String, Number], 82 | F: Function, 83 | }, 84 | setup(props) { 85 | // Props type is { A: string } 86 | console.log(props.A) 87 | }, 88 | }) 89 | ``` 90 | 91 | しかもこの例では少なくとも`D`と`E`と`F`がどんな模様の型なのか一切わかりません. 92 | `template`の中でどのようにアクセスされているのでしょうか? 93 | 我々がその模様を知りたい場合、そこから読み解く必用があります. 94 | 我々の気合による推論で消費する時間は多いのに対して、型定義でサボって得られる時間はごくわずかです. 95 | しかも我々の推論結果が実装者の意図とただしくない可能性があります. 96 | 97 | また、サボった場合は、`Typescript`のエコシステムの恩恵を正しく受けれなくなるリスクがあります. (例: `template`の型検査等 98 | `Vue Props Type`はTypeScriptの力によって、このような課題の解決をシンプル且つ簡単に解決することを目指します. 99 | 以下が`Vue Props Type`を使ったサンプルです. 100 | 101 | ```typescript 102 | import { defineComponent } from '@vue/composition-api' 103 | import { InsidePropsType, OutsidePropsType, PropType } from '@icare-jp/vue-props-type' 104 | 105 | const propsType = { 106 | A: { 107 | type: String as PropType<'github' | 'qiita' | 'facebook'>, 108 | default: () => 'github' 109 | }, 110 | B: { 111 | type: [Number, Date] as PropType<0 | 1 | Date>, 112 | required: true, 113 | }, 114 | C: { 115 | type: Object as PropType<{ label: string, value: string }>, 116 | required: true, 117 | }, 118 | D: { 119 | type: Array as PropType, 120 | required: true, 121 | }, 122 | E: [String, Number], 123 | F: Function as (key: string, value: string) => void 124 | } as const 125 | 126 | export type HogeHogeProps = OutsidePropsType 127 | // { 128 | // A?: string | undefined; 129 | // B: 0 | Date | 1; 130 | // C: Readonly<{ 131 | // label: string; 132 | // value: string; 133 | // }>; 134 | // D: string[]; 135 | // E?: string | number | undefined; 136 | // F?: ((key: string, value: string) => void) | undefined; 137 | // } 138 | 139 | type InsideHogeHogeProps = InsidePropsType 140 | // { 141 | // readonly A: string; 142 | // readonly B: 0 | Date | 1; 143 | // readonly C: Readonly<{ 144 | // label: string; 145 | // value: string; 146 | // }>; 147 | // readonly D: readonly string[]; 148 | // readonly E: string | number | undefined; 149 | // readonly F: ((key: string, value: string) => void) | undefined; 150 | // } 151 | 152 | export default defineComponent({ 153 | name: 'HogeHoge', 154 | props: propsType, 155 | setup(props) { 156 | // props is type safe 157 | }, 158 | }) 159 | ``` 160 | 161 | `InsidePropsType` を使う事により、 `props` の管理を楽にし、型定義を書くストレスを軽減します. 162 | また、 `Vue.js` は `props` へ変更を加える操作を禁止しています. 163 | そのため、 `props` を標準で `readonly` にしています. 164 | もし `readonly` にすることにより何かしらの問題が起こる場合は `UnsafePropsType` を利用してください. 165 | また、 `required: true` と `default: () => any` も無い場合、 `undefined` を混ぜています. 166 | また、 `default: () => any` がある場合は戻り値を抽出し、混ぜています. 167 | それにより、より実行結果に近い、つまり真実に近い型を得られます. 168 | 169 | また、用意されたコンポーネントを利用する側がtype safeに`props`を用意したい場合、以下のようなコードを手動で書き、用意しなければなりません. 170 | 171 | ```typescript 172 | export type HogeHogeProps = { 173 | A?: string | undefined; 174 | B: 0 | Date | 1; 175 | C: Readonly<{ 176 | label: string; 177 | value: string; 178 | }>; 179 | D: string[]; 180 | E?: string | number | undefined; 181 | F?: ((key: string, value: string) => void) | undefined; 182 | } 183 | ``` 184 | 185 | `InsideHogeHogeProps`と全く同じ様に`OutsidePropsType`を利用すれば、この型を自動で生成でき、型定義を書くストレスを軽減します. 186 | 些細な意見でも結構ですので、なにかありましたら気軽にissueを立てて申し立ててくださると幸いです. 187 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue Props Type (Translated by DeepL 2 | 3 | The `Vue Props Type` helps to define the `props` type in `Vue.js`. 4 | 5 | ## Why 6 | 7 | If you want to use composition-api, you need to write the following code. 8 | 9 | ```typescript 10 | import { defineComponent } from '@vue/composition-api' 11 | 12 | export type HogeHogeProps = { 13 | A: 'github' | 'qiita' | 'facebook' 14 | B: 0 | 1 | Date 15 | C: { label: string, value: string } 16 | D: string[] 17 | E: string | number 18 | F: (key: string, value: string) => void 19 | } 20 | 21 | export default defineComponent({ 22 | name: 'HogeHoge', 23 | props: { 24 | A: { 25 | type: String, 26 | default: () => 'github' 27 | }, 28 | B: { 29 | type: [Number, Date], 30 | required: true, 31 | }, 32 | C: { 33 | type: Object, 34 | required: true, 35 | }, 36 | D: { 37 | type: Array, 38 | required: true, 39 | }, 40 | E: [String, Number], 41 | F: Function, 42 | }, 43 | setup(props) { 44 | // props is type safe 45 | }, 46 | }) 47 | ``` 48 | 49 | The `props object` passed to the `Option` and the `props type` of the type definition are defined separately, and they need to be maintained by hand if they are to be written honestly. 50 | The challenge with this is that if you change the code of the `props object` and forget to modify the `props type`, the `HogeHogeProps type` or `props object` will lie. 51 | Some people may be tempted to skip the `props type` type definition if there are too many items in the `props object`. 52 | Some people may only write the type definition of the `props object` item they are accessing in the `setup`. 53 | Here is an example. 54 | 55 | ```typescript 56 | import { defineComponent } from '@vue/composition-api' 57 | 58 | export type HogeHogeProps = { 59 | A: 'github' | 'qiita' | 'facebook' 60 | } 61 | 62 | export default defineComponent({ 63 | name: 'HogeHoge', 64 | props: { 65 | A: { 66 | type: String, 67 | default: () => 'github' 68 | }, 69 | B: { 70 | type: [Number, Date], 71 | required: true, 72 | }, 73 | C: { 74 | type: Object, 75 | required: true, 76 | }, 77 | D: { 78 | type: Array, 79 | required: true, 80 | }, 81 | E: [String, Number], 82 | F: Function, 83 | }, 84 | setup(props) { 85 | // Props type is { A: string } 86 | console.log(props.A) 87 | }, 88 | }) 89 | ``` 90 | 91 | Moreover, in this example at least, we don't know what type of pattern `D`, `E` and `F` are. 92 | How are they being accessed in the `template`? 93 | If we want to know the pattern, we need to decipher it from there. 94 | While our spirited reasoning consumes a lot of time, we get very little time by skipping out on type definitions. 95 | Moreover, our results may not be consistent with the implementer's intentions. 96 | 97 | Also, if you skip it, you will not be able to properly benefit from the `Typescript` ecosystem, and you will not get the benefit of the `Typescript` ecosystem. (e.g. `template` type checking, etc.). (e.g., type checking of `template`. 98 | `Vue Props Type` aims to solve such problems simply and easily with the power of TypeScript. 99 | Here's a sample using `Vue Props Type`. 100 | 101 | 102 | ```typescript 103 | import { defineComponent } from '@vue/composition-api' 104 | import { InsidePropsType, OutsidePropsType, PropType } from '@icare-jp/vue-props-type' 105 | 106 | const propsType = { 107 | A: { 108 | type: String as PropType<'github' | 'qiita' | 'facebook'>, 109 | default: () => 'github' 110 | }, 111 | B: { 112 | type: [Number, Date] as PropType<0 | 1 | Date>, 113 | required: true, 114 | }, 115 | C: { 116 | type: Object as PropType<{ label: string, value: string }>, 117 | required: true, 118 | }, 119 | D: { 120 | type: Array as PropType, 121 | required: true, 122 | }, 123 | E: [String, Number], 124 | F: Function as (key: string, value: string) => void 125 | } as const 126 | 127 | export type HogeHogeProps = OutsidePropsType 128 | // { 129 | // A?: string | undefined; 130 | // B: 0 | Date | 1; 131 | // C: Readonly<{ 132 | // label: string; 133 | // value: string; 134 | // }>; 135 | // D: string[]; 136 | // E?: string | number | undefined; 137 | // F?: ((key: string, value: string) => void) | undefined; 138 | // } 139 | 140 | type InsideHogeHogeProps = InsidePropsType 141 | // { 142 | // readonly A: string; 143 | // readonly B: 0 | Date | 1; 144 | // readonly C: Readonly<{ 145 | // label: string; 146 | // value: string; 147 | // }>; 148 | // readonly D: readonly string[]; 149 | // readonly E: string | number | undefined; 150 | // readonly F: ((key: string, value: string) => void) | undefined; 151 | // } 152 | 153 | export default defineComponent({ 154 | name: 'HogeHoge', 155 | props: propsType, 156 | setup(props) { 157 | // props is type safe 158 | }, 159 | }) 160 | ``` 161 | 162 | The `InsidePropsType` eases the management of `props` and allows you to define the type to ease the stress of writing a `Vue.js'. 163 | Also, Vue.js forbids any modification to the `props`, so `props` is set to `readonly` by default. 164 | For this reason, `props` is set to `readonly` by default. 165 | If you have some problems with `readonly`, please try to use the `UnsafePropsType`. 166 | Also, if neither `required: true` nor `default: () => any` are present, then ` undefined` is mixed in. 167 | Also, if `default: () => any` is present, the return value is extracted and mixed in. 168 | It gives a closer approximation to the execution result, and therefore to the truth. 169 | 170 | Also, the user of the prepared components can set the type safe to `props` and use the `props` as the return value for the If you want to, you have to write and prepare the following code manually. 171 | 172 | ```typescript 173 | export type HogeHogeProps = { 174 | A?: string | undefined; 175 | B: 0 | Date | 1; 176 | C: Readonly<{ 177 | label: string; 178 | value: string; 179 | }>; 180 | D: string[]; 181 | E?: string | number | undefined; 182 | F?: ((key: string, value: string) => void) | undefined; 183 | } 184 | ``` 185 | 186 | Using `OutsidePropsType` in exactly the same way as `InsideHogeHogeProps`, you can generate this type automatically and reduce the stress of writing type definitions. 187 | Please feel free to raise an issue if you have any comments, even if they are trivial. 188 | -------------------------------------------------------------------------------- /__tests__/index.spec.ts: -------------------------------------------------------------------------------- 1 | test('helloworld', () => { 2 | expect('helloworld').toBe('helloworld') 3 | }) 4 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | modulePathIgnorePatterns: ['/lib/'], 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": false, 3 | "name": "@icare-jp/vue-props-type", 4 | "version": "0.0.22", 5 | "scripts": { 6 | "build": "tsc --emitDeclarationOnly", 7 | "prepare": "npm run build", 8 | "lint": "eslint --ext .tsx,.ts", 9 | "lintfix": "prettier --write '**/*.{ts,tsx}' && eslint --ext .tsx,.ts --fix .", 10 | "publish": "npm publish --access public", 11 | "test": "npx jest" 12 | }, 13 | "description": "vue-props-type", 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/icare-jp-oss/vue-props-type.git" 17 | }, 18 | "keywords": [], 19 | "author": "kahirokunn", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/icare-jp-oss/vue-props-type/issues" 23 | }, 24 | "main": "lib/index.d.ts", 25 | "types": "lib/index.d.ts", 26 | "husky": { 27 | "hooks": { 28 | "pre-commit": "lint-staged" 29 | } 30 | }, 31 | "lint-staged": { 32 | "*.{ts,tsx}": [ 33 | "prettier --write", 34 | "eslint --fix" 35 | ], 36 | "*.json": [ 37 | "prettier --write" 38 | ] 39 | }, 40 | "devDependencies": { 41 | "@types/jest": "^26.0.3", 42 | "@typescript-eslint/eslint-plugin": "^3.5.0", 43 | "@typescript-eslint/parser": "^3.5.0", 44 | "eslint": "^7.3.1", 45 | "eslint-config-prettier": "^6.11.0", 46 | "eslint-plugin-import": "^2.22.0", 47 | "eslint-plugin-jest": "^23.17.1", 48 | "eslint-plugin-prettier": "^3.1.4", 49 | "husky": "^4.2.5", 50 | "jest": "^26.1.0", 51 | "lint-staged": "^10.2.11", 52 | "prettier": "^2.0.5", 53 | "ts-jest": "^26.1.1", 54 | "typescript": "^3.9.5" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | type FunctionalConstructor = (...args: any) => T 2 | type Constructor = new (...args: any) => T 3 | type ClassConstructor = Constructor 4 | type Callback = (...args: any) => unknown 5 | 6 | type ValidType = ClassConstructor | Callback | Promise 7 | 8 | type Type1 = { 9 | type: ValidType | ValidType[] | readonly ValidType[] 10 | default?: unknown 11 | required?: boolean 12 | validator?(value: unknown): boolean 13 | } 14 | 15 | type Type2 = Type1['type'] 16 | 17 | export type VueProps = { 18 | [propsName: string]: Type1 | Type2 19 | } 20 | 21 | type ToPrimitiveOrReturn = T extends object 22 | ? T extends String 23 | ? string 24 | : T extends Number 25 | ? number 26 | : T extends Boolean 27 | ? boolean 28 | : T 29 | : T 30 | 31 | type ToPrimitive = T extends Promise 32 | ? T 33 | : T extends ClassConstructor 34 | ? ToPrimitiveOrReturn> 35 | : T extends Callback 36 | ? T 37 | : never 38 | 39 | type Map2Primitive = ToPrimitive | unknown[] ? T[number] : T> 40 | 41 | type GetParams = { [K in keyof T]: T[K] } 42 | type OverrideConstructor, U extends Constructor> = GetParams & Constructor & FunctionalConstructor 43 | 44 | type ReadonlyFunctionalConstructor = (...args: any) => Readonly 45 | type ReadonlyConstructor = new (...args: any) => Readonly 46 | type ReadonlyArrayConstructor = GetParams & ReadonlyConstructor & ReadonlyFunctionalConstructor 47 | 48 | export type InsideUnsafePropsType = { 49 | [K in keyof Props]: Props[K] extends { 50 | default: FunctionalConstructor 51 | } 52 | ? U | Map2Primitive 53 | : Props[K] extends { 54 | default: infer U 55 | } 56 | ? U | Map2Primitive 57 | : Props[K] extends { required: true } 58 | ? Map2Primitive 59 | : Map2Primitive | undefined 60 | } 61 | export type InsidePropsType = Readonly> 62 | type _InsidePropsTypePropType = T extends Array 63 | ? OverrideConstructor 64 | : T extends ReadonlyArray 65 | ? OverrideConstructor 66 | : T extends Date 67 | ? GetParams & Constructor 68 | : T extends symbol 69 | ? GetParams & FunctionalConstructor 70 | : T extends BigInt 71 | ? GetParams & FunctionalConstructor 72 | : T extends Record 73 | ? OverrideConstructor 74 | : T extends string 75 | ? OverrideConstructor 76 | : T extends number 77 | ? OverrideConstructor 78 | : T extends boolean 79 | ? OverrideConstructor 80 | : Constructor & FunctionalConstructor 81 | export type PropType = _InsidePropsTypePropType | _InsidePropsTypePropType[] 82 | 83 | type PickKeys = { [P in keyof T]: T[P] extends U ? P : never }[keyof T] 84 | type FilterKeys = { [P in keyof T]: T[P] extends U ? never : P }[keyof T] 85 | 86 | type _OutsidePropsType = { 87 | [K in keyof Props]: Map2Primitive 88 | } 89 | type Clean = { 90 | [K in keyof T]: T[K] 91 | } 92 | export type OutsidePropsType = Clean< 93 | _OutsidePropsType>> & 94 | Partial<_OutsidePropsType>>> 95 | > 96 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "strict": true, 5 | "strictBindCallApply": true, 6 | "strictFunctionTypes": true, 7 | "strictNullChecks": true, 8 | "strictPropertyInitialization": true, 9 | "outDir": "lib", 10 | "esModuleInterop": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "emitDecoratorMetadata": true, 14 | "experimentalDecorators": true, 15 | "lib": ["esnext", "esnext.asynciterable", "dom", "dom.iterable"], 16 | "moduleResolution": "node", 17 | "baseUrl": ".", 18 | "typeRoots": ["./node_modules/@types/"], 19 | "sourceMap": true, 20 | "target": "es5" 21 | }, 22 | "exclude": ["node_modules", "vendor", "public", "lib", "__tests__"], 23 | "compileOnSave": false 24 | } 25 | --------------------------------------------------------------------------------