├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md └── workflows │ └── deploy-to-gh-pages.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── commitlint.config.js ├── docs ├── .vuepress │ ├── components │ │ ├── Answer.vue │ │ ├── Editor.vue │ │ └── MySWUpdatePopup.vue │ ├── config.js │ ├── enhanceApp.js │ ├── public │ │ ├── images │ │ │ ├── docs.png │ │ │ └── icons │ │ │ │ ├── icon-128x128.png │ │ │ │ ├── icon-144x144.png │ │ │ │ ├── icon-152x152.png │ │ │ │ ├── icon-192x192.png │ │ │ │ ├── icon-384x384.png │ │ │ │ ├── icon-512x512.png │ │ │ │ ├── icon-72x72.png │ │ │ │ └── icon-96x96.png │ │ ├── logo.png │ │ ├── manifest.json │ │ └── ts-logo.png │ ├── styles │ │ └── index.styl │ └── utils │ │ ├── alias.json │ │ ├── copy.js │ │ ├── nav.js │ │ ├── plugins.js │ │ └── sidebarHelper.js ├── README.md └── zh │ ├── advanced-types │ ├── README.md │ ├── intersection-types │ │ └── README.md │ ├── nullable │ │ └── README.md │ ├── type-guard │ │ └── README.md │ └── union-types │ │ └── README.md │ ├── array │ └── README.md │ ├── basic │ └── README.md │ ├── blog │ └── README.md │ ├── built-in-objects │ └── README.md │ ├── class │ └── README.md │ ├── compile-config │ ├── README.md │ ├── file-inclusion │ │ └── README.md │ ├── module-resolver │ │ └── README.md │ ├── references │ │ └── README.md │ └── tsconfig-module-target │ │ └── README.md │ ├── declaration │ └── README.md │ ├── decorators │ └── README.md │ ├── faqs │ ├── README.md │ └── interface-vs-type.md │ ├── function │ └── README.md │ ├── generics │ └── README.md │ ├── guide │ └── README.md │ ├── interface │ └── README.md │ ├── keyword │ ├── README.md │ ├── as │ │ └── README.md │ ├── extends │ │ └── README.md │ ├── implements │ │ └── README.md │ ├── in │ │ └── README.md │ ├── infer │ │ └── README.md │ ├── instanceof │ │ └── README.md │ ├── is │ │ └── README.md │ ├── keyof │ │ └── README.md │ └── typeof │ │ └── README.md │ ├── operator │ └── README.md │ ├── tips │ ├── README.md │ ├── if-else │ │ └── README.md │ └── spread │ │ └── README.md │ ├── type-assertion │ └── README.md │ ├── utility-types │ ├── README.md │ └── custom-utility-types │ │ └── README.md │ └── what-is-typescript │ ├── README.md │ └── images │ └── 2020-ts-download.png ├── how-to-write-docs.md ├── package-lock.json ├── package.json ├── plop-templates └── README.md.hbs ├── plopfile.js ├── scripts ├── deploy.sh └── remote.sh └── wechat-zhifubao-pay.png /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | # https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties 3 | 4 | # 表示是最顶层的配置文件, 发现设为true时, 才会停止查找.editorconfig文件 5 | root = true 6 | 7 | [*] 8 | # tab space 9 | indent_style = tab 10 | 11 | indent_size = 2 12 | # 设置换行符, 值为lf, cr, crlf 13 | end_of_line = lf 14 | charset = utf-8 15 | 16 | # 用一个整数来设置tab缩进的列数。默认是indent_size 17 | tab_width = indent_size 18 | 19 | #是否删除行尾的空格 20 | trim_trailing_whitespace = true 21 | 22 | #是否在文件的最后插入一个空行 23 | insert_final_newline = true 24 | 25 | [*.md] 26 | indent_size = 2 27 | trim_trailing_whitespace = false 28 | insert_final_newline = true 29 | 30 | [Makefile] 31 | indent_style = tab 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/deploy-to-gh-pages.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Build and Deploy 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | # pull_request: 10 | # branches: [ master ] 11 | 12 | jobs: 13 | 14 | deploy: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout 🛎️ 19 | uses: actions/checkout@master 20 | 21 | - name: Checkout node 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: 16 25 | 26 | - name: Install and Build 🔧 27 | run: | 28 | # npm ci 依赖 package-lock.json 29 | # npm ci 30 | npm install 31 | npm run docs:build 32 | 33 | - name: Deploy 🚀 34 | uses: JamesIves/github-pages-deploy-action@4.1.1 35 | with: 36 | branch: gh-pages 37 | folder: docs/.vuepress/dist 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE & Editor 2 | /.idea/ 3 | 4 | # lock file 5 | *lock 6 | 7 | 8 | # Logs 9 | logs 10 | *.log 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | lerna-debug.log* 15 | 16 | # Diagnostic reports (https://nodejs.org/api/report.html) 17 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 18 | 19 | # Runtime data 20 | pids 21 | *.pid 22 | *.seed 23 | *.pid.lock 24 | 25 | # Directory for instrumented libs generated by jscoverage/JSCover 26 | lib-cov 27 | 28 | # Coverage directory used by tools like istanbul 29 | coverage/ 30 | *.lcov 31 | .coveralls.yml 32 | 33 | # nyc test coverage 34 | .nyc_output 35 | 36 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 37 | .grunt 38 | 39 | # Bower dependency directory (https://bower.io/) 40 | bower_components 41 | 42 | # node-waf configuration 43 | .lock-wscript 44 | 45 | # Compiled binary addons (https://nodejs.org/api/addons.html) 46 | build/Release 47 | 48 | # Dependency directories 49 | node_modules/ 50 | jspm_packages/ 51 | 52 | # TypeScript v1 declaration files 53 | typings/ 54 | 55 | # TypeScript cache 56 | *.tsbuildinfo 57 | 58 | # Optional npm cache directory 59 | .npm 60 | 61 | # Optional eslint cache 62 | .eslintcache 63 | 64 | # Microbundle cache 65 | .rpt2_cache/ 66 | .rts2_cache_cjs/ 67 | .rts2_cache_es/ 68 | .rts2_cache_umd/ 69 | 70 | # Optional REPL history 71 | .node_repl_history 72 | 73 | # Output of 'npm pack' 74 | *.tgz 75 | 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | 79 | # dotenv environment variables file 80 | .env 81 | .env.test 82 | 83 | # parcel-bundler cache (https://parceljs.org/) 84 | .cache 85 | 86 | # Next.js build output 87 | .next 88 | 89 | # Nuxt.js build / generate output 90 | .nuxt 91 | dist 92 | 93 | # Gatsby files 94 | .cache/ 95 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 96 | # https://nextjs.org/blog/next-9-1#public-directory-support 97 | # public 98 | 99 | # vuepress build output 100 | .vuepress/dist 101 | 102 | # Serverless directories 103 | .serverless/ 104 | 105 | # FuseBox cache 106 | .fusebox/ 107 | 108 | # DynamoDB Local files 109 | .dynamodb/ 110 | 111 | # TernJS port file 112 | .tern-port 113 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [1.0.0](https://github.com/Rain120/typescript-guide/compare/0.0.1...1.0.0) (2024-01-16) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * bug about deploy action folder ([57f4fae](https://github.com/Rain120/typescript-guide/commit/57f4fae89f0f478a51f58c5873936a264e6d4b09)) 7 | * bug about deploy action folder(not home ~) ([c4eb45d](https://github.com/Rain120/typescript-guide/commit/c4eb45d079e8fc63ebffd3dca04f5111072da894)) 8 | * bug about github actions deploy branch config error ([bc992c0](https://github.com/Rain120/typescript-guide/commit/bc992c05ee17bfcccca14b3400e0e81e9c16c423)) 9 | * file inclusion references code ([97806cc](https://github.com/Rain120/typescript-guide/commit/97806ccb834cf0741213da1a496292c7fb301e40)) 10 | * github actions deploy bug ([4c64d68](https://github.com/Rain120/typescript-guide/commit/4c64d68ddd17f03a3900219ed06ba453fb25a49f)) 11 | * style about deploy with params at yml file ([a4d5ed3](https://github.com/Rain120/typescript-guide/commit/a4d5ed3924239b6498aae6fde169c162123633e7)) 12 | * style about deploy with params at yml file ([ddbcee6](https://github.com/Rain120/typescript-guide/commit/ddbcee6fb81af41bcb6528d4db884758c310f476)) 13 | * ts operator & chinese anchor bug; type challenges for guide reference ([a441bd5](https://github.com/Rain120/typescript-guide/commit/a441bd541d5a4a33f6228a5c3b50cad51ca8b27f)) 14 | * what is typescript for diff with js ([34b01a7](https://github.com/Rain120/typescript-guide/commit/34b01a71712e54e05a973c4b33b68cb5ec7a0b1e)) 15 | 16 | 17 | ### Features 18 | 19 | * 工具类型 ([afeb366](https://github.com/Rain120/typescript-guide/commit/afeb366af952d750f012e51fb1c5a33b738f37bd)) 20 | * **declaration:** update ([978e800](https://github.com/Rain120/typescript-guide/commit/978e8002c92198ac37a6c09c20c9a6f55bc4145e)) 21 | * **extends:** update ([8cd0fdc](https://github.com/Rain120/typescript-guide/commit/8cd0fdc819baf8178a16e3b3dcc77b3b90c11ec3)) 22 | * **intersection-types:** update ([e5ffe1b](https://github.com/Rain120/typescript-guide/commit/e5ffe1bd61dd154329422a420c9a91f3346e6a90)) 23 | * **keyof:** update usage ([37c61cb](https://github.com/Rain120/typescript-guide/commit/37c61cbf14eb66f5c84c8cd90a27b79183cc0bf7)) 24 | * **utility types:** custom ([50e8703](https://github.com/Rain120/typescript-guide/commit/50e87037bc7ad9b20757efa1ad18734db428f0a5)) 25 | * add Previously at keyword for descript the resource about it ([be81d8e](https://github.com/Rain120/typescript-guide/commit/be81d8e5f2f6d2892852f72143b09607ddc1d78a)) 26 | * blog tips & pdfs & books ([310765f](https://github.com/Rain120/typescript-guide/commit/310765ffd4e95bcde3dc3a33c3ca7115f80d30f1)) 27 | * compile-config about module resolver & flie inclusive; keyword about is ([4b5832d](https://github.com/Rain120/typescript-guide/commit/4b5832df75a82cd75b553463d1ed476f22d20fd1)) 28 | * faqs about tsconfig module target ([d40988c](https://github.com/Rain120/typescript-guide/commit/d40988c26b6c287dc72aac94a4c76b2f07cfa8cf)) 29 | * faqs add interface vs type ([3bf6171](https://github.com/Rain120/typescript-guide/commit/3bf61710c8395d8ba73adfc0ae4eb7a3be0f5021)) 30 | * finished declaration ([b30964d](https://github.com/Rain120/typescript-guide/commit/b30964d056cd2c03bcaa0dd3a19a60215510ec90)) 31 | * tsconfig - references ([ad24a19](https://github.com/Rain120/typescript-guide/commit/ad24a197efd8703ab818458246d141b3adf5f226)) 32 | * tsconfig about file inclision keywords ([c566316](https://github.com/Rain120/typescript-guide/commit/c566316727123cb0998c1f09f6736c2902d1d1c6)) 33 | * tsconfig module target; remove faqs module, target ([48d3e0f](https://github.com/Rain120/typescript-guide/commit/48d3e0f16f0957b08da24352ca73eb1e5770d382)) 34 | 35 | 36 | 37 | ## [0.0.1](https://github.com/Rain120/typescript-guide/compare/77f36499665edfad4f0333d6a55f54a541177f06...0.0.1) (2020-12-30) 38 | 39 | 40 | ### Bug Fixes 41 | 42 | * add deploy folder, remove useless file with deploy.yml ([ae47a15](https://github.com/Rain120/typescript-guide/commit/ae47a15f31d84c749adeac9f4dcb8bd793860223)) 43 | * changelog before commit ([904d7cd](https://github.com/Rain120/typescript-guide/commit/904d7cd67335a1455aade81ae5638d0d85c16016)) 44 | * deploy workflows error ([eb9efce](https://github.com/Rain120/typescript-guide/commit/eb9efcee47d42d8cfd3eae039dc904c71e73fdf1)) 45 | * deploy workflows error ([048dbe1](https://github.com/Rain120/typescript-guide/commit/048dbe1c70e0f0ecb914d8f44a14629938fac157)) 46 | * deploy workflows error ([6aa3dae](https://github.com/Rain120/typescript-guide/commit/6aa3dae982f03588a9b9f69b9f31dcdb67b0d14c)) 47 | * deploy workflows error ([eeb7ab2](https://github.com/Rain120/typescript-guide/commit/eeb7ab2d0d7487b5a43249d0f0181083178961dd)) 48 | * index.styl ([15af71e](https://github.com/Rain120/typescript-guide/commit/15af71e4e0cab90a610166fae201e60cfdf88daa)) 49 | * Invalid workflow filed with deploy yml ([6c0d64a](https://github.com/Rain120/typescript-guide/commit/6c0d64a7dacbb38c8b34adcc4d74fbd56bb1e99c)) 50 | * monaco editor build bug (cannot require async component) ([906f6e8](https://github.com/Rain120/typescript-guide/commit/906f6e8379efe762d76f16381b657e4752be4dd4)) 51 | * monaco editor show normal modal and can edit ([da7a4c9](https://github.com/Rain120/typescript-guide/commit/da7a4c9316b6bf245ceccea93f3518ddaf810f80)) 52 | * nested sub-level directories path ([c6830ac](https://github.com/Rain120/typescript-guide/commit/c6830ac37ada02270874d8d3d7ab00fade02e51d)) 53 | * README OKR path not found ([5d9739d](https://github.com/Rain120/typescript-guide/commit/5d9739d17602787fb8d1ad190d225fc572003920)) 54 | * remove pre-commit changelog ([a8da639](https://github.com/Rain120/typescript-guide/commit/a8da6392c5c11ccb7148803cebe96a2068e873f5)) 55 | * remove pre-commit deploy ([1d5830a](https://github.com/Rain120/typescript-guide/commit/1d5830ae9c4a2e6a6b83a573f9aa51e881b77ca7)) 56 | * resolve advanced types path error ([8458a2c](https://github.com/Rain120/typescript-guide/commit/8458a2c6e2a22c53f387d2b53ba20f2c49e59d70)) 57 | * the math logic description about intersection and union which at advanced types ([9bcc637](https://github.com/Rain120/typescript-guide/commit/9bcc637024767a71b0021c9a1f006fd3392e7ece)) 58 | * update google analysis id ([2e1721b](https://github.com/Rain120/typescript-guide/commit/2e1721b7f5a7b671398f5d6ec2c094194c4229c0)) 59 | * use commands install replace ci, because not package-lock.json ([64cfc90](https://github.com/Rain120/typescript-guide/commit/64cfc9003cb860bbdcb1855c971da4f1df1acc51)) 60 | * utility types Record example error ([51ab092](https://github.com/Rain120/typescript-guide/commit/51ab092a23c030379f42f35920c0211d5f3b4cf2)) 61 | 62 | 63 | ### Features 64 | 65 | * add test & editor at template and docs ([19faa8a](https://github.com/Rain120/typescript-guide/commit/19faa8a69ce121ba3adeaaaa4eefbdba64bf0381)) 66 | * add tips, faqs folder; how to write docs md ([ff42474](https://github.com/Rain120/typescript-guide/commit/ff42474843622fcd2f6bb4ad13ea075934c039bc)) 67 | * advanced types nullable; update union, assertion; others chores ([1b5936a](https://github.com/Rain120/typescript-guide/commit/1b5936aac1fe2c6363c90083231f66779b654a1e)) 68 | * build in objects ([b62cd07](https://github.com/Rain120/typescript-guide/commit/b62cd07384f6423400d485bc3c4b68c6649c0ec2)) 69 | * class ([78ff3cc](https://github.com/Rain120/typescript-guide/commit/78ff3ccf5e321f198777deb8fd20dc487add0bc0)) 70 | * decorators usage ([36be18e](https://github.com/Rain120/typescript-guide/commit/36be18ee8e9f0914b8470e1e12dd9b9474c2f8e0)) 71 | * decorators; plugin with math latex ([4364958](https://github.com/Rain120/typescript-guide/commit/4364958b84092d08a312ea839e730de008d1847e)) 72 | * function ([5dba78c](https://github.com/Rain120/typescript-guide/commit/5dba78cd2eb6d18c70c4524ae328f4514c5eb1dd)) 73 | * github action deploy workflows ([a98f275](https://github.com/Rain120/typescript-guide/commit/a98f27562f0cf7e3a82b46fa95fba8c1f2cd678b)) 74 | * github action deploy workflows ([ae5128e](https://github.com/Rain120/typescript-guide/commit/ae5128e2dd7521698a0b5f11f783f48d41022e12)) 75 | * infer ([ddb4ae9](https://github.com/Rain120/typescript-guide/commit/ddb4ae96a8e669e266f7d76533e6f6c5660d3286)) 76 | * init typscript guide & add guide, introduction, base ([365b637](https://github.com/Rain120/typescript-guide/commit/365b637d872cc92c23a04c09788d50001ee46a73)) 77 | * intersection & union types; utility version; typescripts reference ([06fc3de](https://github.com/Rain120/typescript-guide/commit/06fc3de9cd11890024e172ee69b480924ddad295)) 78 | * keyword with extends, implements ([a784b4e](https://github.com/Rain120/typescript-guide/commit/a784b4e23fd30c6a8cb754244e4fa1a2df6fb9ad)) 79 | * keyword: is, keyof, in, typeof, instanceof; type guard; add vuepress plugin ([81f3b55](https://github.com/Rain120/typescript-guide/commit/81f3b5537f5aca20a4b10219d6cb216df2d51fea)) 80 | * plop auto create docs model ([1f5a2f9](https://github.com/Rain120/typescript-guide/commit/1f5a2f94bbd7a430bbfbb48a09718b8ec9d14190)) 81 | * plop new docs & update alias; update plop template; add docs catalog & folders ([dd5326a](https://github.com/Rain120/typescript-guide/commit/dd5326ac2934069c2cb10238c674e4dc86844274)) 82 | * refactor types(intersection, union, guard) to advanced types ([bde41ab](https://github.com/Rain120/typescript-guide/commit/bde41ab8e61ae59f21c907c7a1a86e932ee71f31)) 83 | * ts basic type; update logo; guide; add editorconfig ([c0b6eb2](https://github.com/Rain120/typescript-guide/commit/c0b6eb272ab4d87706902cdda365230e507b860b)) 84 | * ts operator; compile config; fix: playground frame width bug ([f2bcaa0](https://github.com/Rain120/typescript-guide/commit/f2bcaa05bfdf574037ec54ed3e651ce1d1353b5c)) 85 | * ts operators ([4e009df](https://github.com/Rain120/typescript-guide/commit/4e009dfa98c42be63705d71130af1bfc46861d19)) 86 | * type assertion ([f77f51c](https://github.com/Rain120/typescript-guide/commit/f77f51c574f036d6079742eca8f8affa7b06f617)) 87 | * typescript blog ([13e29c4](https://github.com/Rain120/typescript-guide/commit/13e29c418ed7e351e134e55519f31022785f5681)) 88 | * **heading:** 加入特殊 heading 的处理; ignore IDE 相关的文件 ([5e9070b](https://github.com/Rain120/typescript-guide/commit/5e9070baf3b36cc0e753b9bde3a8aaec58590314)) 89 | * update the okrs about guide ([a762e9c](https://github.com/Rain120/typescript-guide/commit/a762e9cb156ac0bcdbdc64f0b477e41c49fb9e8d)) 90 | * utility types; alias set bottom title; update generics params; ([a306a25](https://github.com/Rain120/typescript-guide/commit/a306a25c512246ef230a445ccb4e292eef8b8a7d)) 91 | * vuepress docs template ([77f3649](https://github.com/Rain120/typescript-guide/commit/77f36499665edfad4f0333d6a55f54a541177f06)) 92 | * wip generics, interface; add okr about the doc ([d2f6397](https://github.com/Rain120/typescript-guide/commit/d2f6397641ec4a590a51f297c1a9d61564500dff)) 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rain120 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Typescript Guide 3 | 4 |

5 | 6 |
7 | 8 | [![GitHub watchers](https://img.shields.io/github/watchers/rain120/typescript-guide?style=social)](https://github.com/Rain120/typescript-guide/watchers) 9 | [![STAR](https://img.shields.io/github/stars/rain120/typescript-guide?style=social)](https://github.com/Rain120/typescript-guide/stargazers) [![FORK](https://img.shields.io/github/forks/rain120/typescript-guide?style=social)](https://github.com/Rain120/typescript-guide/network/members) 10 | 11 | [![ISSUES](https://img.shields.io/github/issues/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/issues) [![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/pulls) [![COMMIT](https://img.shields.io/github/last-commit/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/commits/master) 12 | 13 | ![LANGUAGES](https://img.shields.io/github/languages/top/rain120/typescript-guide?style=flat-square) 14 | [![VERSION](https://img.shields.io/github/package-json/v/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/blob/master/package.json) [![LICENSE](https://img.shields.io/github/license/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/blob/master/LICENSE) 15 | 16 |
17 | 18 | ## 😚 Welcome 19 | 20 | Welcome to the Typescript Guide. 21 | 22 | ## 🎮 TL;DR 23 | 24 | 25 | [Document](https://rain120.github.io/typescript-guide/) 26 | 27 | ## ✍ Why am I doing this? 28 | 29 | Write documents for how to easily use typescript. 30 | ## 🍾 Objective Key Result (OKR) 31 | 32 | ### Objective 33 | 34 | Learning all about the base of Typescript, and practice it 35 | 36 | ### Key Result 37 | 38 | - [x] [Compile Config](./docs/zh/compile-config/README.md) 39 | 40 | - [x] [Basic](./docs/zh/basic/README.md) 41 | 42 | - [x] [Type Assertion](./docs/zh/advanced-types/type-assertion/README.md) 43 | 44 | - [x] [Advanced Types](./docs/zh/advanced-types/README.md) 45 | 46 | - [x] [Intersection Types](./docs/zh/advanced-types/intersection-types/README.md) 47 | 48 | - [x] [Union Types](./docs/zh/advanced-types/union-types/README.md) 49 | 50 | - [x] [Type Guard](./docs/zh/advanced-types/type-guard/README.md) 51 | 52 | - [x] [Nullable](./docs/zh/advanced-types/nullable/README.md) 53 | 54 | - [x] [Array](./docs/zh/array/README.md) 55 | 56 | - [x] [Function](./docs/zh/function/README.md) 57 | 58 | - [ ] [Decorators](./docs/zh/decorators/README.md) 59 | 60 | - [ ] [Class](./docs/zh/class/README.md) 61 | 62 | - [x] [内置对象](./docs/zh/built-in-objects/README.md) 63 | 64 | - [ ] [Interface](./docs/zh/interface/README.md) 65 | 66 | - [ ] [Generics](./docs/zh/generics/README.md) 67 | 68 | - [x] [Operator](./docs/zh/operator/README.md) 69 | 70 | - [x] [Keyword](./docs/zh/keyword/README.md) 71 | 72 | - [x] [is](./docs/zh/is/README.md) 73 | 74 | - [x] [keyof](./docs/zh/keyof/README.md) 75 | 76 | - [x] [in](./docs/zh/in/README.md) 77 | 78 | - [x] [typeof](./docs/zh/typeof/README.md) 79 | 80 | - [x] [instanceof](./docs/zh/instanceof/README.md) 81 | 82 | - [x] [extends](./docs/zh/extends/README.md) 83 | 84 | - [x] [implements](./docs/zh/implements/README.md) 85 | 86 | - [ ] [infer](./docs/zh/implements/README.md) 87 | 88 | - [x] [Utility Types](./docs/zh/utility-types/README.md) 89 | 90 | - [ ] [Tips](./docs/zh/tips/README.md) 91 | 92 | - [ ] [FAQs](./docs/zh/faqs/README.md) 93 | 94 | 95 | 98 | 99 | ## 🤝 Contributing 100 | 101 | ![PR](https://img.shields.io/badge/PRs-Welcome-orange?style=flat-square&logo=appveyor) 102 | 103 | We welcome all contributions. You can submit any ideas as [pull requests](https://github.com/Rain120/typescript-guide/pulls) or as a GitHub [issue](https://github.com/Rain120/typescript-guide/issues). 104 | 105 | [How to write Docs](how-to-write-docs.md) 106 | 107 | ## 🔗 Links 108 | 109 | 110 | 111 | [Online Docs](https://rain120.github.io/typescript-guide/) 112 | 113 | ## 👨‍🏭 Author 114 | 115 | > Front-End development engineer, technology stack: React + Typescript + Mobx, also used Vue + Vuex for a while 116 | 117 | - [Github](https://github.com/Rain120) 118 | - [知乎](https://www.zhihu.com/people/yan-yang-nian-hua-120/activities) 119 | - [掘金](https://juejin.im/user/57c616496be3ff00584f54db) 120 | 121 | ## 📝 License 122 | 123 | [MIT](https://github.com/Rain120/typescript-guide/blob/master/LICENSE) 124 | 125 | Copyright © 2020-present [Rain120](https://github.com/Rain120). 126 | 127 | ## ☕ Coffee or Tea 128 | 129 | ![wechat-zhifubao-pay.png](./wechat-zhifubao-pay.png) 130 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["@commitlint/config-conventional"], 3 | rules: { 4 | "type-enum": [ 5 | 2, 6 | "always", 7 | [ 8 | "feat", 9 | "fix", 10 | "docs", 11 | "style", 12 | "refactor", 13 | "perf", 14 | "test", 15 | "build", 16 | "ci", 17 | "chore", 18 | "revert", 19 | "config", 20 | "wip" 21 | ] 22 | ], 23 | "subject-full-stop": [0, "never"], 24 | "subject-case": [0, "never"], 25 | "header-max-length": [0, "always", 150] 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /docs/.vuepress/components/Answer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 32 | 33 | 35 | -------------------------------------------------------------------------------- /docs/.vuepress/components/Editor.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 129 | 130 | -------------------------------------------------------------------------------- /docs/.vuepress/components/MySWUpdatePopup.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | 20 | 83 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin') 3 | const plugins = require('./utils/plugins'); 4 | const { sidebarHelper, sortSidebar } = require('./utils/sidebarHelper'); 5 | const nav = require('./utils/nav'); 6 | const slugify = require('@vuepress/shared-utils').slugify 7 | 8 | const sidebar = sortSidebar(sidebarHelper()); 9 | // console.log(sidebar) 10 | 11 | const fs = require('fs') 12 | 13 | const SPECIAL_HEADINGS = { 14 | '!': 'exclamation', 15 | '?': 'question', 16 | '+ -': 'plus-and-minus', 17 | }; 18 | 19 | module.exports = { 20 | // 替换成你的仓库名 21 | base: '/typescript-guide/', 22 | title: 'Typescript 指导书', 23 | description: 'Welcome to Typescript Guide', 24 | port: 9527, 25 | // dest: 'dist', 26 | // head 配置 27 | head: [ 28 | ['link', { rel: 'icon', href: '/ts-logo.png' }], 29 | ['link', { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.css' }], 30 | ['link', { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/2.10.0/github-markdown.min.css' }], 31 | ['link', { rel: 'manifest', href: '/manifest.json' }], 32 | ['meta', { name: 'theme-color', content: '#3eaf7c' }], 33 | ['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }], 34 | ['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }], 35 | ['link', { rel: 'apple-touch-icon', href: '/icons/apple-touch-icon-152x152.png' }], 36 | ['link', { rel: 'mask-icon', href: '/icons/safari-pinned-tab.svg', color: '#3eaf7c' }], 37 | ['meta', { name: 'msapplication-TileImage', content: '/icons/msapplication-icon-144x144.png' }], 38 | ['meta', { name: 'msapplication-TileColor', content: '#000000' }], 39 | ], 40 | // 别名配置 41 | configureWebpack: { 42 | resolve: { 43 | alias: { 44 | '@images': path.join(__dirname, '../..'), 45 | } 46 | } 47 | }, 48 | chainWebpack:(config, isServer) => { 49 | // config.resolve.alias.set('@images',path.resolve(__dirname, '../../')) 50 | config.plugin('monaco-editor').use(MonacoWebpackPlugin, [ 51 | { 52 | // Languages are loaded on demand at runtime 53 | languages: [ 54 | 'javascript', 55 | 'typescript', 56 | ] 57 | } 58 | ]) 59 | }, 60 | locales: { 61 | '/': { 62 | lang: 'zh-CN', 63 | } 64 | }, 65 | // markdown 66 | markdown: { 67 | lineNumbers: true, 68 | /** 69 | * 解决一个 "无实质内容的标题导致 permalink 出错" 的问题, 70 | * 目前发现有若干个有点问题的, 如 `!` 71 | * 72 | * @todo: 如果开始有多类似的个例, 可以引入特殊的 "heading anchor" 格式, 并统一处理 73 | * 74 | * 参考 : http://caibaojian.com/vuepress/config/#markdown-slugify 75 | * 76 | * @param {string} heading 77 | * @return {string|*|string} 78 | */ 79 | slugify: (heading) => { 80 | const originResult = slugify(heading) 81 | 82 | const trimmedHeading = (heading || '').trim() 83 | if (trimmedHeading in SPECIAL_HEADINGS) { 84 | return SPECIAL_HEADINGS[(heading || '').trim()] || '' 85 | } 86 | return originResult 87 | }, 88 | anchor: { 89 | permalink: true, 90 | }, 91 | toc: { 92 | includeLevel: [1, 2], 93 | }, 94 | extendMarkdown: md => { 95 | md.set({ html: true }); 96 | md.use(require('markdown-it-katex')); 97 | md.use(require('markdown-it-task-lists')); 98 | md.use(require('markdown-it-imsize'), { autofill: true }); 99 | } 100 | }, 101 | // 主题配置 102 | themeConfig: { 103 | theme: 'vue', 104 | repo: 'https://github.com/Rain120/typescript-guide', 105 | 106 | sidebar, 107 | nav, 108 | 109 | // polyfill IE 110 | evergreen: true, 111 | 112 | // search 113 | search: true, 114 | searchMaxSuggestions: 10, 115 | // 申请 116 | // https://docsearch.algolia.com/apply/ 117 | // algolia: { 118 | // apiKey: '', 119 | // indexName: '' 120 | // }, 121 | 122 | // PWA 123 | serviceWorker: true, 124 | 125 | displayAllHeaders: true, 126 | 127 | smoothScroll: true, 128 | 129 | // footer 130 | date_format: 'yyyy-MM-dd', 131 | lastUpdated: 'Last Updated', 132 | repoLabel: '查看源码', 133 | docsDir: 'docs', 134 | docsBranch: 'master', 135 | editLinks: true, 136 | editLinkText: '帮助我们改善此页面!' 137 | }, 138 | plugins 139 | }; 140 | -------------------------------------------------------------------------------- /docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Rainy 3 | * @Date: 2020-02-27 16:38:27 4 | * @LastEditors: Rainy 5 | * @LastEditTime: 2021-03-12 16:16:16 6 | */ 7 | 8 | // import copy from './utils/copy'; 9 | 10 | export default ({ Vue, options, router, siteData, isServer }) => { 11 | if (typeof process === 'undefined' || process.env.VUE_ENV !== 'server') { 12 | router.onReady(() => { 13 | const { app } = router; 14 | 15 | app.$once('hook:mounted', () => { 16 | setTimeout(() => { 17 | const { hash } = document.location; 18 | if (hash.length > 1) { 19 | const id = decodeURIComponent(hash.substring(1)); 20 | const element = document.getElementById(id); 21 | element && element.scrollIntoView(); 22 | } 23 | }, 500); 24 | }); 25 | }); 26 | } 27 | 28 | setTimeout(() => { 29 | try { 30 | //对document的判断是防止编译的时候报错 31 | document && 32 | (() => { 33 | // copy(); 34 | })(); 35 | } catch (e) { 36 | console.error(e.message); 37 | } 38 | }, 500); 39 | }; 40 | -------------------------------------------------------------------------------- /docs/.vuepress/public/images/docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/images/docs.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/images/icons/icon-128x128.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/images/icons/icon-144x144.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/images/icons/icon-152x152.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/images/icons/icon-192x192.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/images/icons/icon-384x384.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/images/icons/icon-512x512.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/images/icons/icon-72x72.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/images/icons/icon-96x96.png -------------------------------------------------------------------------------- /docs/.vuepress/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/logo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Vuepress Doc Template", 3 | "short_name": "Vuepress Doc Template", 4 | "theme_color": "#3EAF7C", 5 | "background_color": "#3EAF7C", 6 | "display": "standalone", 7 | "Scope": "/", 8 | "start_url": "/", 9 | "icons": [ 10 | { 11 | "src": "images/icons/icon-72x72.png", 12 | "sizes": "72x72", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "images/icons/icon-96x96.png", 17 | "sizes": "96x96", 18 | "type": "image/png" 19 | }, 20 | { 21 | "src": "images/icons/icon-128x128.png", 22 | "sizes": "128x128", 23 | "type": "image/png" 24 | }, 25 | { 26 | "src": "images/icons/icon-144x144.png", 27 | "sizes": "144x144", 28 | "type": "image/png" 29 | }, 30 | { 31 | "src": "images/icons/icon-152x152.png", 32 | "sizes": "152x152", 33 | "type": "image/png" 34 | }, 35 | { 36 | "src": "images/icons/icon-192x192.png", 37 | "sizes": "192x192", 38 | "type": "image/png" 39 | }, 40 | { 41 | "src": "images/icons/icon-384x384.png", 42 | "sizes": "384x384", 43 | "type": "image/png" 44 | }, 45 | { 46 | "src": "images/icons/icon-512x512.png", 47 | "sizes": "512x512", 48 | "type": "image/png" 49 | } 50 | ], 51 | "splash_pages": null 52 | } -------------------------------------------------------------------------------- /docs/.vuepress/public/ts-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/.vuepress/public/ts-logo.png -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | #app { 2 | .page { 3 | #gitalk-container { 4 | margin: auto; 5 | width: 60%; 6 | } 7 | .theme-default-content:not(.custom) { 8 | max-width: 840px; 9 | } 10 | } 11 | 12 | .page-nav, .page-edit { 13 | max-width: 840px; 14 | } 15 | 16 | details { 17 | border-radius: 4px; 18 | padding: .5em .5em; 19 | &:focus { 20 | outline: none; 21 | } 22 | } 23 | 24 | summary { 25 | font-weight: bold; 26 | margin: -.5em -.5em; 27 | margin-bottom: .8em; 28 | &:focus { 29 | outline: none; 30 | } 31 | } 32 | 33 | code { 34 | background: none; 35 | } 36 | 37 | .theorem { 38 | margin: 1rem 0; 39 | padding: .1rem 1.5rem; 40 | border-radius: 0.4rem; 41 | background-color: #f0f4f8; 42 | .title { 43 | font-weight: bold; 44 | } 45 | } 46 | 47 | .custom-block { 48 | &.right { 49 | color: transparentify($textColor, 0.4); 50 | font-size: 0.9rem; 51 | text-align: right; 52 | } 53 | } 54 | } 55 | 56 | ::-webkit-scrollbar { 57 | width: 8px; 58 | height: 8px; 59 | border-radius: 10px; 60 | background-color: #F5F5F5; 61 | } 62 | 63 | ::-webkit-scrollbar-track { 64 | border-radius: 10px; 65 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 66 | background-color: #F5F5F5; 67 | } 68 | 69 | ::-webkit-scrollbar-thumb { 70 | border-radius: 10px; 71 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 72 | border-radius: 10px; 73 | background-image: -webkit-gradient( 74 | linear, 75 | left bottom, left top, 76 | color-stop(.44, rgb(60, 186, 146)), 77 | color-stop(.72, rgb(253, 187, 45)), 78 | color-stop(.86, rgb(253, 187, 45)) 79 | ); 80 | transition: .3s ease-in-out; 81 | } 82 | 83 | ::-webkit-scrollbar-thumb:hover { 84 | background-image: -webkit-gradient( 85 | linear, 86 | left bottom, left top, 87 | color-stop(.44, rgb(253, 187, 45)), 88 | olor-stop(.72, rgb(253, 187, 45)), 89 | color-stop(.86, rgb(60, 186, 146)) 90 | ); 91 | transition: .3s ease-in-out; 92 | } 93 | -------------------------------------------------------------------------------- /docs/.vuepress/utils/alias.json: -------------------------------------------------------------------------------- 1 | { 2 | "guide": "介绍", 3 | "what-is-typescript": "Typescript 是什么? ", 4 | "compile-config": "Typescript 编译配置", 5 | "declaration": "Typescript 声明文件", 6 | "basic": "Typescript 基础类型", 7 | "advanced-types": "Typescript 高级类型", 8 | "type-assertion": "Typescript 类型断言", 9 | "intersection-types": "TypeScript 交叉类型", 10 | "union-types": "Typescript 联合类型", 11 | "type-guard": "Typescript 类型保护", 12 | "nullable": "Typescript Nullable", 13 | "array": "Typescript 数组", 14 | "function": "TypeScript 函数", 15 | "class": "Typescript 类", 16 | "built-in-objects": "Typescript 内置对象", 17 | "decorators": "Typescript 装饰器", 18 | "interface": "Typescript 接口", 19 | "generics": "Typescript 泛型", 20 | "keyword": "Typescript 关键字", 21 | "is": "is", 22 | "keyof": "keyof", 23 | "in": "in", 24 | "typeof": "typeof", 25 | "instanceof": "instanceof", 26 | "operator": "Typescript 运算符", 27 | "utility-types": "Typescript 使用工具类型", 28 | "extends": "extends", 29 | "implements": "implements", 30 | "infer": "infer", 31 | "blog": "博客", 32 | "file-inclusion": "Typescript 文件包含相关配置", 33 | "references": "tsconfig - references", 34 | "tsconfig-module-target": "Typescript Module Target", 35 | "interface-vs-type": "interface 和 type 有什么异同点?", 36 | "module-resolver": "Typescript 模块解析", 37 | "custom-utility-types": "自定义工具类型", 38 | "if-else": "条件类型", 39 | "spread": "拓展运算符", 40 | "tips": "Typescript Tips", 41 | "faqs": "Typescript FAQs" 42 | } -------------------------------------------------------------------------------- /docs/.vuepress/utils/copy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Rainy 3 | * @Date: 2020-02-27 16:38:27 4 | * @LastEditors: Rainy 5 | * @LastEditTime: 2020-08-02 16:07:40 6 | */ 7 | 8 | export default (userName = 'Rain120') => { 9 | function addCopy(e) { 10 | let copyTxt = ''; 11 | e.preventDefault(); // 取消默认的复制事件 12 | copyTxt = window.getSelection(0).toString(); 13 | copyTxt = `${copyTxt}\n作者: ${userName}\n原文: ${window.location.href}\n著作权归作者所有。商业转载请联系作者获得授权, 非商业转载请注明出处。`; 14 | const clipboardData = e.clipboardData || window.clipboardData; 15 | clipboardData.setData('text', copyTxt); 16 | } 17 | document.addEventListener('cut', e => { 18 | addCopy(e); 19 | }); 20 | document.addEventListener('copy', e => { 21 | addCopy(e); 22 | }); 23 | }; 24 | -------------------------------------------------------------------------------- /docs/.vuepress/utils/nav.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | text: 'Study Notes', 4 | link: 'https://rain120.github.io/study-notes/', 5 | target: '_blank' 6 | }, 7 | // { 8 | // text: 'Languages', 9 | // ariaLabel: 'Language Menu', 10 | // items: [ 11 | // { text: 'Chinese', link: '/zh/guide/' }, 12 | // { text: 'English', link: '/en/guide/' } 13 | // ] 14 | // }, 15 | { 16 | text: 'Hot Repo', 17 | items: [ 18 | { 19 | text: 'awesome-javascript-code-implementation', 20 | link: 'https://awesome-javascript-code-implementation.netlify.com/', 21 | target: '_blank' 22 | }, 23 | { 24 | text: 'qq-music-api', 25 | link: 'https://rain120.github.io/qq-music-api/', 26 | target: '_blank' 27 | }, 28 | { 29 | text: 'more', 30 | link: 'https://github.com/rain120', 31 | target: '_blank' 32 | }, 33 | ] 34 | }, 35 | { 36 | text: 'Github', 37 | link: 'https://github.com/rain120', 38 | target: '_blank' 39 | } 40 | ]; 41 | -------------------------------------------------------------------------------- /docs/.vuepress/utils/plugins.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment'); 2 | 3 | const containers = [ 4 | // 你可以多次使用这个插件 5 | [ 6 | 'vuepress-plugin-container', 7 | { 8 | type: 'right', 9 | defaultTitle: '', 10 | }, 11 | ], 12 | [ 13 | 'vuepress-plugin-container', 14 | { 15 | type: 'theorem', 16 | before: info => `

${info}

`, 17 | after: '
', 18 | }, 19 | ], 20 | // 这是 VuePress 默认主题使用这个插件的方式 21 | [ 22 | 'vuepress-plugin-container', 23 | { 24 | type: 'tip', 25 | defaultTitle: { 26 | '/': 'TIP', 27 | '/zh/': '提示', 28 | }, 29 | }, 30 | ], 31 | ] 32 | 33 | module.exports = [ 34 | ['@vuepress/back-to-top'], 35 | [ 36 | '@vuepress/google-analytics', 37 | { 38 | ga: 'UA-172045751-1' 39 | } 40 | ], 41 | [ 42 | '@vuepress/medium-zoom', 43 | { 44 | // selector: 'img.zoom-custom-imgs', 45 | options: { 46 | margin: 16 47 | } 48 | } 49 | ], 50 | [ 51 | 'vuepress-plugin-awesome-gitalk', 52 | { 53 | home: false, 54 | ignorePaths: ['/zh/guide/'], 55 | gitalk: { 56 | clientID: '13f222b6ec6782dbe85f', 57 | clientSecret: '60984ee0c8926c160d2dc1a32e2769f2002e0a1b', 58 | repo: 'typescript-guide', 59 | owner: 'Rain120', 60 | admin: ['Rain120'], 61 | distractionFreeMode: true, 62 | language: 'zh-CN', 63 | } 64 | } 65 | ], 66 | ['@vuepress/pwa', 67 | { 68 | serviceWorker: true, 69 | popupComponent: 'MySWUpdatePopup', 70 | updatePopup: { 71 | '/': { 72 | message: "官人, 人家又有新货了, 快来玩呀", 73 | buttonText: "我来啦" 74 | }, 75 | '/zh/': { 76 | message: "官人, 人家又有新货了, 快来玩呀", 77 | buttonText: "我来啦" 78 | } 79 | } 80 | } 81 | ], 82 | ['@vuepress/blog'], 83 | [ 84 | '@vuepress/last-updated', 85 | { 86 | transformer: (timestamp, lang) => { 87 | moment.locale(lang) 88 | return moment(timestamp).fromNow() 89 | } 90 | } 91 | ], 92 | [ 93 | 'vuepress-plugin-mathjax', 94 | { 95 | target: 'svg', 96 | macros: { 97 | '*': '\\times', 98 | }, 99 | }, 100 | ], 101 | ...containers, 102 | ]; 103 | -------------------------------------------------------------------------------- /docs/.vuepress/utils/sidebarHelper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Rainy 3 | * @Date: 2020-02-27 16:38:27 4 | * @LastEditors: Rainy 5 | * @LastEditTime: 2020-07-11 17:44:01 6 | */ 7 | 8 | const fs = require('fs'); 9 | const path = require('path'); 10 | 11 | const language = 'zh'; 12 | const filePath = path.join(__dirname, `../../${language}`); 13 | const ignore = ['images', '.vuepress', '.DS_Store']; 14 | const README_REG = /README/; 15 | 16 | // INFO: 从 package.json 获取你的文档名字, 主要为了配置多层级子目录 17 | const docsPath = process.cwd(); 18 | const pkg = require(`${docsPath}/package.json`); 19 | const pkgName = pkg.name || docsPath.trim().split('/').slice(-1).toString(); 20 | 21 | /** 22 | * @description 特殊处理文档顺序 23 | * alias 的顺序决定了文档菜单的目录顺序, 子菜单亦可 24 | * Eg: 25 | * p2: p2 26 | * p1: p1 27 | * p1-c2: p1-c2 28 | * p1-c1: p1-c1 29 | * -> 菜单顺序是 30 | * p2 31 | * p1 32 | * c2 33 | * c1 34 | */ 35 | const alias = require('./alias.json'); 36 | 37 | const mapper = code => { 38 | return alias[code]; 39 | } 40 | 41 | const isFile = ({ dir = filePath, fPath }) => 42 | fs.statSync(path.join(dir, fPath)).isFile(); 43 | 44 | function syncDirPath(file = filePath) { 45 | return fs.readdirSync(file) || []; 46 | } 47 | 48 | function helper({ dir, fPath }) { 49 | const prefixPath = dir.split(`${pkgName}/docs`)[1]; 50 | const currentPath = path.join(dir, fPath); 51 | 52 | const children = syncDirPath(currentPath) 53 | .filter(fPath => !ignore.includes(fPath)) 54 | .map((sub, index) => { 55 | const fsStats = fs.statSync(path.join(currentPath, sub)); 56 | 57 | if (fsStats.isDirectory()) { 58 | return helper({ dir: currentPath, fPath: sub }); 59 | } else if (fsStats.isFile() && !README_REG.test(sub)) { 60 | const name = sub.replace('\.md', ''); 61 | return { 62 | title: mapper(name) || `${name}`, 63 | key: name, 64 | path: `${prefixPath}/${fPath}/${name}`, 65 | } 66 | } 67 | }).filter(Boolean); 68 | 69 | return { 70 | title: mapper(fPath) || `${fPath}`, 71 | key: fPath, 72 | path: `${prefixPath}/${fPath}/`, 73 | collapsable: true, 74 | children: Array.isArray(children) ? children : [children], 75 | } 76 | } 77 | 78 | function sidebarHelper(dir = filePath) { 79 | return syncDirPath(dir) 80 | .filter(fPath => !isFile({ fPath }) && !ignore.includes(fPath)) 81 | .map((fPath, dirIndex) => { 82 | return helper({ dir, fPath }) || []; 83 | }); 84 | } 85 | 86 | function findIndex(value) { 87 | return Object.keys(alias).findIndex(item => item === value) 88 | } 89 | 90 | function sortSidebar(sidebar) { 91 | sidebar.sort((a, b) => { 92 | return findIndex(a.key) - findIndex(b.key); 93 | }); 94 | for (const item of sidebar) { 95 | if (item && Array.isArray(item.children)) { 96 | item.children = sortSidebar(item.children); 97 | } 98 | } 99 | return sidebar; 100 | } 101 | 102 | module.exports = { 103 | sidebarHelper, 104 | sortSidebar, 105 | }; 106 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | activity: true 4 | heroImage: /images/docs.png 5 | actionText: 快速上手 👉 6 | actionLink: /zh/guide/ 7 | 8 | # tagline: Welcome to the Typescript Guide 9 | 10 | features: 11 | 12 | - title: 清晰性 13 | details: 通过文档清晰准确的讲解 Typescript 的知识点, 让你更加快速的了解Typescript 14 | 15 | - title: 开放性 16 | details: 完全开源, 并接受您的 PR 和 Issue 17 | 18 | footer: MIT Licensed | Copyright © 2020-present Rain120 19 | --- 20 | -------------------------------------------------------------------------------- /docs/zh/advanced-types/README.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | 3 | :::theorem 高级类型 4 | Typescript 高级类型 5 | ::: 6 | 7 | - [TypeScript 交叉类型](./intersection-types/README.md) 8 | 9 | - [Typescript 联合类型](./union-types/README.md) 10 | 11 | - [Typescript 类型保护](./type-guard/README.md) 12 | 13 | - [Typescript Nullable](./nullable/README.md) 14 | 15 | ## 参考资料 16 | 17 | [Handbook - advanced types](https://www.typescriptlang.org/docs/handbook/advanced-types.html) 18 | -------------------------------------------------------------------------------- /docs/zh/advanced-types/intersection-types/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | :::theorem 交叉类型 4 | 交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型, 它包含了所需的所有类型的特性。 5 | ::: 6 | 7 | **Note:** 交叉类型是 **或** 的关系, 即 $A \cup B$, 使用 `&` 运算符。**如果两个类型中出现相同的key,但是类型不同**,**则该key为never**。 8 | 9 | ## 使用 10 | 11 | ```ts 12 | interface Boy { 13 | handsome: boolean; 14 | name?: string; 15 | } 16 | 17 | interface Girl { 18 | cute: boolean; 19 | name?: string; 20 | } 21 | 22 | // { 23 | // cute: boolean; 24 | // handsome: boolean; 25 | // name?: never; 26 | // } 27 | type Person = Boy & Girl; 28 | 29 | const someone: Person = { 30 | handsome: true, 31 | cute: false, 32 | name: 'Rain120' 33 | }; 34 | ``` 35 | 36 | 大多是在混入 `(mixins)` 或其它不适合典型面向对象模型的地方看到交叉类型的使用。如下示: 37 | 38 | ```ts 39 | function extend(first: T, second: U): T & U { 40 | let result = {}; 41 | for (let id in first) { 42 | (result)[id] = (first)[id]; 43 | } 44 | for (let id in second) { 45 | if (!result.hasOwnProperty(id)) { 46 | (result)[id] = (second)[id]; 47 | } 48 | } 49 | return result; 50 | } 51 | 52 | class Person { 53 | constructor(public name: string) {} 54 | } 55 | interface Loggable { 56 | log(): void; 57 | } 58 | class ConsoleLogger implements Loggable { 59 | log() { 60 | // ... 61 | } 62 | } 63 | var jim = extend(new Person('Jim'), new ConsoleLogger()); 64 | var n = jim.name; 65 | jim.log(); 66 | ``` 67 | 68 | ## 实现 69 | 70 | ```ts 71 | interface IntersectionTypes { 72 | assign(target: T, source: U): T & U; 73 | } 74 | ``` 75 | 76 | ## 快来耍耍啊 77 | 78 | ### 🌰🌰 79 | 80 | 81 | 82 | ``` 83 | // template 84 | ``` 85 | 86 | ### 游乐场 87 | 88 |
89 | 90 | 93 | 94 | ### 参考答案 95 | 96 | ```ts 97 | // answer 98 | ``` 99 | 100 | ## 参考资料 101 | 102 | [handbook - intersection-types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#intersection-types) 103 | 104 | [数学公式参考](https://latexlive.com/) 105 | -------------------------------------------------------------------------------- /docs/zh/advanced-types/nullable/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | :::theorem Nullable 4 | `TypeScript` 里空类型 `(void)` 有两种: `undefined` 与 `null`, 是 `(除never外)` 其它所有类型的子类型。 5 | 6 | 默认情况下, 类型检查器认为 `null`与 `undefined`可以赋值给任何类型。 `null`与 `undefined`是所有其它类型的一个有效值。 7 | ::: 8 | 9 | 解决方式有两种: 10 | 11 | ### 可选参数和可选属性 12 | 13 | 当你使用了 `--strictNullChecks` 配置, 可选参数列表会自动加上 `| nudefined`。 14 | 15 | ```ts 16 | function setName(name?: string) { 17 | return name || 'Rain120'; 18 | } 19 | 20 | setName('Lily'); 21 | setName(); 22 | 23 | ``` 24 | 25 | ### 类型保护 和 类型断言 26 | 27 | #### [类型保护](../type-guard/README.md) 28 | 29 | ```ts 30 | function setName(name?: string) { 31 | if (name === null) { 32 | return 'Rain120'; 33 | } 34 | return name; 35 | } 36 | ``` 37 | 38 | 当然, 你也可以通过短路运算符 `|` 来实现的。 39 | 40 | ```ts 41 | function setName(name?: string) { 42 | return name || 'Rain120'; 43 | } 44 | ``` 45 | 46 | #### [类型断言](../../type-assertion/README.md) 47 | 48 | ```ts 49 | function setName(name?: string) { 50 | return name!; 51 | } 52 | ``` 53 | 54 | 更多操作符相关, 请到 [Here](../../operator/README.md) 55 | 56 | ## 快来耍耍啊 57 | 58 | ### 🌰🌰 59 | 60 | 61 | 62 | ``` 63 | // template 64 | ``` 65 | 66 | ### 游乐场 67 | 68 |
69 | 70 | 73 | 74 | ### 参考答案 75 | 76 | ```ts 77 | // answer 78 | ``` 79 | 80 | ## 参考资料 81 | 82 | 83 | -------------------------------------------------------------------------------- /docs/zh/advanced-types/type-guard/README.md: -------------------------------------------------------------------------------- 1 | ## 前置知识 2 | 3 | ### 类型谓词 4 | 5 | 在[数学逻辑中](https://en.wikipedia.org/wiki/Mathematical_logic), **[谓词](https://en.wikipedia.org/wiki/Predicate_(mathematical_logic))** 通常被理解为[布尔值函数](https://en.wikipedia.org/wiki/Boolean-valued_function) `P:X → {true, false}`, 称为 **X** 上的谓词。非正式地, 谓词是取决于其变量值的对或错的语句。[\[1\]](https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)#cite_note-1) 可以将其视为返回 `true` 或 `false` 值的运算符或函数。 6 | 7 | **类型谓词** 是一种特殊的返回类型, 它向 `Typescript` 编译器发出信号, 告知特定值是什么类型。**类型谓词** 始终附加到使用单个参数并返回布尔值的函数。类型谓词表示为`argumentName is Type`。 8 | 9 | ```ts 10 | interface Cat { 11 | numberOfLives: number; 12 | } 13 | interface Dog { 14 | isAGoodBoy: boolean; 15 | } 16 | 17 | function isCat(animal: Cat | Dog): animal is Cat { 18 | return typeof animal.numberOfLives === 'number'; 19 | } 20 | ``` 21 | 22 | ## 定义 23 | 24 | > A type guard is some expression that performs a runtime check that guarantees the type in some scope. 25 | 26 | :::theorem 类型保护 27 | 类型保护就是一些表达式, 它们会在运行时检查以确保在某个作用域里的类型。可以通过 **检测属性、方法或原型, 以确定如何处理值**来实现。 28 | ::: 29 | 30 | ## 使用 31 | 32 | ### typeof 类型保护 33 | 34 | ```ts 35 | function padLeft(value: string, padding: string | number) { 36 | if (typeof x === 'number') { 37 | return Array(padding + 1).join(' ') + value; 38 | } 39 | if (typeof x === 'string') { 40 | return padding + value; 41 | } 42 | throw new Error(`Expected string or number, got '${padding}'.`); 43 | } 44 | ``` 45 | 46 | ### instanceof 类型保护 47 | 48 | ```ts 49 | interface Padder { 50 | getPaddingString(): string 51 | } 52 | 53 | class SpaceRepeatingPadder implements Padder { 54 | constructor(private numSpaces: number) { } 55 | getPaddingString() { 56 | return Array(this.numSpaces + 1).join(' '); 57 | } 58 | } 59 | 60 | class StringPadder implements Padder { 61 | constructor(private value: string) { } 62 | getPaddingString() { 63 | return this.value; 64 | } 65 | } 66 | 67 | function getRandomPadder() { 68 | return Math.random() < 0.5 ? 69 | new SpaceRepeatingPadder(4) : 70 | new StringPadder(' '); 71 | } 72 | 73 | // Type is 'SpaceRepeatingPadder | StringPadder' 74 | let padder: Padder = getRandomPadder(); 75 | 76 | if (padder instanceof SpaceRepeatingPadder) { 77 | padder; // type narrowed to 'SpaceRepeatingPadder' 78 | } 79 | if (padder instanceof StringPadder) { 80 | padder; // type narrowed to 'StringPadder' 81 | } 82 | ``` 83 | 84 | `instanceof`的右侧要求是一个构造函数, `TypeScript` 将细化为: 85 | 86 | 1. 此构造函数的 `prototype`属性的类型, 如果它的类型不为 `any`的话 87 | 2. 构造签名所返回的类型的联合 88 | 89 | ### in 类型保护 90 | 91 | ```ts 92 | interface Common { 93 | name: string; 94 | seeSomething: any; 95 | } 96 | 97 | interface Vip { 98 | name: string; 99 | doSomething: any; 100 | } 101 | 102 | type User = Common | Vip; 103 | 104 | function getUserInfo(user: User) { 105 | if ('doSomething' in user) { 106 | // vip 107 | } 108 | if ('seeSomething' in user) { 109 | // common 110 | } 111 | } 112 | ``` 113 | 114 | ### 自定义类型保护 115 | 116 | 有时候 `typeof` 和 `instanceof` 没法满足我们的需求, 我们可以通过自定义类型保护来缩窄类型 117 | 118 | ```ts 119 | interface CanLayEggs { 120 | layEggs(): void 121 | } 122 | 123 | interface Bird extends CanLayEggs { 124 | fly(): void 125 | } 126 | 127 | interface Fish extends CanLayEggs { 128 | swim(): void 129 | } 130 | 131 | function getSmallPet(): Fish | Bird { 132 | const fish: Fish = {} 133 | return fish 134 | } 135 | 136 | const pet = getSmallPet() 137 | 138 | // 使用 自定义的类型保护 139 | function isFish(pet: Fish | Bird): pet is Fish { 140 | return (pet).swim !== undefined 141 | } 142 | 143 | if (isFish(pet)) { 144 | pet.swim() 145 | } else { 146 | pet.fly() 147 | } 148 | ``` 149 | 150 | ## 快来耍耍啊 151 | 152 | ### 🌰🌰 153 | 154 | 155 | 156 | ``` 157 | // template 158 | ``` 159 | 160 | ### 游乐场 161 | 162 |
163 | 164 | 167 | 168 | ### 参考答案 169 | 170 | ```ts 171 | // answer 172 | ``` 173 | 174 | ## 参考资料 175 | 176 | [handbook - type-guards-and-differentiating-types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types) 177 | 178 | [type-guard](https://basarat.gitbook.io/typescript/type-system/typeguard) 179 | 180 | [aha-understanding-typescript-s-type-predicates](https://dev.to/daveturissini/aha-understanding-typescript-s-type-predicates-40ha) 181 | 182 | [typescript-type-predicates](https://fettblog.eu/typescript-type-predicates/) -------------------------------------------------------------------------------- /docs/zh/advanced-types/union-types/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | :::theorem 联合类型 4 | 联合类型具有 **或** 关系的多个类型组合而成, 只要满足其中一个类型即可。当你不确定某个对象的值是什么类型时就可以使用 **联合类型**。 5 | ::: 6 | 7 | **Note:** 联合类型是 **且** 的关系, 即 $A \cap B$, 使用 `|` 运算符 。 8 | 9 | ## Nullable 与 联合类型 10 | 11 | ```ts 12 | let name: string = 'Rain120' 13 | 14 | name = null; 15 | name = undefined; 16 | 17 | console.log(name.toString()) 18 | 19 | // ====> 20 | 21 | let name: string | null | undefined; 22 | 23 | ``` 24 | 25 | 更多尝试 [Here](https://www.typescriptlang.org/play/#code/DYUwLgBAdghgtiAXBAzmATgSygcwgXggHIAlGbARgCYAGIgKHtgQOgFdhgBuJ+EVtlAAmIAGbYQQnvQDGAeygo5oAHTA5OABTMQKsHIDKGbFoCUpoA) 26 | 27 | 从类型上看, `Nullable` 类型相当于原类型与`null | undefined`组成的联合类型, 从上示例意味着, **类型检查** 并不可靠, 针对空类型的 **潜在问题**, `TypeScript` 提供了`--strictNullChecks`选项, 开启之后会严格检查空类型。 28 | 29 | 更多 `Nullable` 相关请到 [Here](../nullable/README.md) 30 | 31 | ## 使用 32 | 33 | ```ts 34 | interface Boy { 35 | hair: boolean; 36 | tall: boolean; 37 | } 38 | 39 | interface Girl { 40 | hair: boolean; 41 | cute: boolean; 42 | } 43 | 44 | type Person = Boy | Girl 45 | 46 | const someone: Person = { 47 | hair: true 48 | } 49 | ``` 50 | 51 | ## 快来耍耍啊 52 | 53 | ### 🌰🌰 54 | 55 | 56 | 57 | ``` 58 | // template 59 | ``` 60 | 61 | ### 游乐场 62 | 63 |
64 | 65 | 68 | 69 | ### 参考答案 70 | 71 | ```ts 72 | // answer 73 | ``` 74 | 75 | ## 参考资料 76 | 77 | [handbook - union-types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types) 78 | 79 | [unions](https://basarat.gitbook.io/typescript/type-system/discriminated-unions) 80 | 81 | [数学公式参考](https://latexlive.com/) 82 | -------------------------------------------------------------------------------- /docs/zh/array/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | `TypeScript` 像 `JavaScript` 一样可以操作数组元素。 4 | 5 | ## 使用 6 | 7 | 有以下几种方式可以定义数组。 8 | 9 | ### 元素类型 + [] 10 | 11 | ```ts 12 | const list: number[] = [1, 2, 3]; 13 | ``` 14 | 15 | ### 数组泛型, `Array<元素类型>` 16 | 17 | ```ts 18 | const list: Array = [1, 2, 3]; 19 | ``` 20 | 21 | 泛型相关, 请到 [Here](../generics/README.md) 22 | 23 | ### 接口 24 | 25 | ```ts 26 | interface List { 27 | [index: number]: number; 28 | } 29 | 30 | const list: List = [1, 2, 3]; 31 | ``` 32 | 33 | ## 快来耍耍啊 34 | 35 | ### 🌰🌰 36 | 37 | 38 | 39 | ``` 40 | // template 41 | ``` 42 | 43 | ### 游乐场 44 | 45 |
46 | 47 | 50 | 51 | ### 参考答案 52 | 53 | ```ts 54 | // answer 55 | ``` 56 | 57 | ## 参考资料 58 | 59 | [Handbook - array](https://www.typescriptlang.org/docs/handbook/basic-types.html#array) 60 | 61 | [数组的类型](https://ts.xcatliu.com/basics/type-of-array.html) -------------------------------------------------------------------------------- /docs/zh/basic/README.md: -------------------------------------------------------------------------------- 1 | ## Boolean 类型 2 | 3 | ```ts 4 | const handsome: boolean = true; 5 | ``` 6 | 7 | ## Number 类型 8 | 9 | ```ts 10 | const age: number = 18; 11 | ``` 12 | 13 | ## String 类型 14 | 15 | ```ts 16 | const name: string = 'Rain120; 17 | ``` 18 | 19 | ## Array 类型 20 | 21 | ```ts 22 | const travel_cities: string[] = [ 23 | 'beijing', 24 | 'shanghai', 25 | 'nanjing', 26 | 'hangzhou', 27 | 'wuhan', 28 | 'changsha', 29 | 'jilin', 30 | 'shenyang' 31 | ]; 32 | 33 | // 使用数组泛型 34 | const travel_cities: Array = [ 35 | 'beijing', 36 | 'shanghai', 37 | 'nanjing', 38 | 'hangzhou', 39 | 'wuhan', 40 | 'changsha', 41 | 'jilin', 42 | 'shenyang' 43 | ]; 44 | ``` 45 | 46 | ## Tuple 类型 47 | 48 | 元组类型允许表示一个 **已知元素数量和类型** 的 **数组**, 各元素的类型不必相同。 比如, 你可以定义一对值分别为 `string` 和 `number` 类型的元组。 49 | 50 | ```ts 51 | let age: [number, string]; 52 | 53 | age = [18, '18']; // ok 54 | 55 | age = ['18', 18]; // error 56 | 57 | ``` 58 | 59 | ### 初始化 60 | 61 | 在元组初始化的时候, 我们还必须提供每个属性的值, 不然也会出现错误。 62 | 63 | ```ts 64 | age = [18]; 65 | 66 | // Property '1' is missing in type '[string]' but required in type '[number, string]'. 67 | ``` 68 | 69 | ### 越界元素 70 | 71 | 当添加越界的元素时, 它的类型会被限制为元组中每个类型的联合类型。 72 | 73 | ```ts 74 | age.push(true); 75 | 76 | // Argument of type 'true' is not assignable to parameter of type 'number | string'. 77 | ``` 78 | 79 | ## Enum 类型 80 | 81 | 使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 82 | 83 | ### 数字枚举 84 | 85 | ```ts 86 | enum Gender { 87 | FEMALE, 88 | MALE, 89 | } 90 | 91 | console.log(Gender.FEMALE); // 0 92 | ``` 93 | 94 | 转换成 `ES5` 95 | 96 | ```js 97 | "use strict"; 98 | var Gender; 99 | (function (Gender) { 100 | Gender[Gender["FEMALE"] = 0] = "FEMALE"; 101 | Gender[Gender["MALE"] = 1] = "MALE"; 102 | })(Gender || (Gender = {})); 103 | ``` 104 | 105 | [Go Demo](https://www.typescriptlang.org/play?#code/KYOwrgtgBA4qAmwBOUDeAoKUBiBRAsgIIAyuANJlEaRQL5A) 106 | 107 | 默认情况下, 从`0`开始为元素编号。 你也可以手动的指定成员的数值。比如 108 | 109 | ```ts 110 | enum Gender { 111 | FEMALE = 1, 112 | MALE, 113 | } 114 | 115 | console.log(Gender.FEMALE); // 1 116 | ``` 117 | 118 | 转换成 `ES5` 119 | 120 | ```js 121 | "use strict"; 122 | var Gender; 123 | (function (Gender) { 124 | Gender[Gender["FEMALE"] = 1] = "FEMALE"; 125 | Gender[Gender["MALE"] = 2] = "MALE"; 126 | })(Gender || (Gender = {})); 127 | ``` 128 | 129 | [Go Demo](https://www.typescriptlang.org/play?#code/KYOwrgtgBA4qAmwBOUDeAoKUBiBRAsgIIAyuUAvFAIwA0mURpdAvkA) 130 | 131 | ### 字符串枚举 132 | 133 | 在一个字符串枚举里, 每个成员都必须用字符串字面量, 或另外一个字符串枚举成员进行初始化。 134 | 135 | ```ts 136 | enum Gender { 137 | FEMALE = 'FEMALE', 138 | MALE = 'MALE', 139 | } 140 | 141 | console.log(Gender.FEMALE); // FEMALE 142 | ``` 143 | 144 | 转换成 `ES5` 145 | 146 | ```js 147 | "use strict"; 148 | var Gender; 149 | (function (Gender) { 150 | Gender["FEMALE"] = "FEMALE"; 151 | Gender["MALE"] = "MALE"; 152 | })(Gender || (Gender = {})); 153 | 154 | ``` 155 | 156 | [Go Demo](https://www.typescriptlang.org/play?#code/KYOwrgtgBA4qAmwBOUDeAoKUBiBRAsgIIAyuUAvFAOR5GlUA0mUdZlVrj6AvkA) 157 | 158 | ### 异构枚举 159 | 160 | 异构枚举的成员值是数字和字符串的混合 161 | 162 | ```ts 163 | enum Enum { 164 | A, 165 | B, 166 | C = "C", 167 | D = "D", 168 | E = 8, 169 | F, 170 | } 171 | 172 | console.log(Enum.C); // C 173 | console.log(Enum.E); // 8 174 | ``` 175 | 176 | 转换成 `ES5` 177 | 178 | ```js 179 | "use strict"; 180 | var Enum; 181 | (function (Enum) { 182 | Enum[Enum["A"] = 0] = "A"; 183 | Enum[Enum["B"] = 1] = "B"; 184 | Enum["C"] = "C"; 185 | Enum["D"] = "D"; 186 | Enum[Enum["E"] = 8] = "E"; 187 | Enum[Enum["F"] = 9] = "F"; 188 | })(Enum || (Enum = {})); 189 | ``` 190 | 191 | [Go Demo](https://www.typescriptlang.org/play?#code/KYOwrgtgBAou0G8BQUoEEA0KoCEuoGEoBeKAIgLPygBETyarsZ6AOagMSwF8kg) 192 | 193 | ## Any 类型 194 | 195 | 有时候, 我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型, 这些值可能来自于动态的内容。 196 | 197 | 在 `TypeScript` 中, 任何类型都可以被归为 `any` 类型。这让 `any`类型成为了类型系统的 [**顶级类型**](https://en.wikipedia.org/wiki/Top_type)(也被称作 **全局超级类型**)。 198 | 199 | 使用 `any` 类型的变量能够兼容所有的类型, `typescript` 将不会对他做任何类型检查, 所以我们将无法对其做类型保护, 这样我们就会很容易地编写类型正确, 但在运行时有问题的代码。 200 | 201 | 例如: 202 | 203 | ```ts 204 | let value: any; 205 | 206 | value = true; // OK 207 | value = 42; // OK 208 | value = "Hello World"; // OK 209 | value = []; // OK 210 | value = {}; // OK 211 | value = Math.random; // OK 212 | value = null; // OK 213 | value = undefined; // OK 214 | value = new TypeError(); // OK 215 | value = Symbol("type"); // OK 216 | ``` 217 | 218 | `any`类型本质上是类型系统的一个逃逸舱。作为开发者, 这给了我们很大的自由:TypeScript允许我们对 `any`类型的值执行任何操作, 而无需事先执行任何形式的检查。 219 | 220 | 在上述例子中, 变量 `value`被定义成类型 `any`。也是因此, `TypeScript` 认为以下所有操作都是类型正确的: 221 | 222 | ```ts 223 | let value: any; 224 | 225 | value.foo.bar; // OK 226 | value.trim(); // OK 227 | value(); // OK 228 | new value(); // OK 229 | value[0][1]; // OK 230 | ``` 231 | 232 | 这许多场景下, 这样的机制都太宽松了。使用`any`类型, 可以很容易地编写类型正确但是执行异常的代码。如果我们使用 `any`类型, 就无法享受 `TypeScript` 大量的保护机制。 233 | 234 | ## Unknown 类型 235 | 236 | `TypeScript 3.0` 引入了新的`unknown` 类型, 它是 `any` 类型对应的安全类型。 237 | 238 | `unknown` 和 `any` 的主要区别是 `unknown` 类型会更加严格:在对 `unknown` 类型的值执行大多数操作之前, 我们必须进行某种形式的检查。而在对 `any` 类型的值执行操作之前, 我们不必进行任何检查。 239 | 240 | ```ts 241 | let value: any; 242 | 243 | value = true; // OK 244 | value = 42; // OK 245 | value = "Hello World"; // OK 246 | value = []; // OK 247 | value = {}; // OK 248 | value = Math.random; // OK 249 | value = null; // OK 250 | value = undefined; // OK 251 | value = new TypeError(); // OK 252 | value = Symbol("type"); // OK 253 | ``` 254 | 255 | 对 `value`变量的所有赋值都被认为是类型正确的。 256 | 257 | 当我们尝试将类型为 `unknown`的值赋值给其他类型的变量时会发生什么? 258 | 259 | ```ts 260 | let value: unknown; 261 | 262 | let value1: unknown = value; // OK 263 | let value2: any = value; // OK 264 | let value3: boolean = value; // Error 265 | let value4: number = value; // Error 266 | let value5: string = value; // Error 267 | let value6: object = value; // Error 268 | let value7: any[] = value; // Error 269 | let value8: Function = value; // Error 270 | ``` 271 | 272 | `unknown`类型只能被赋值给 `any`类型和 `unknown`类型本身。直观的说, 这是有道理的:只有能够保存任意类型值的容器才能保存 `unknown`类型的值。毕竟我们不知道变量 `value`中存储了什么类型的值。 273 | 274 | 现在让我们看看当我们尝试对类型为 `unknown`的值执行操作时会发生什么。以下是我们之前看过的相同操作: 275 | 276 | ```ts 277 | let value: unknown; 278 | 279 | value.foo.bar; // Error 280 | value.trim(); // Error 281 | value(); // Error 282 | new value(); // Error 283 | value[0][1]; // Error 284 | ``` 285 | 286 | 将 `value`变量类型设置为 `unknown`后, 这些操作都不再被认为是类型正确的。通过改变 `any`类型到 `unknown`类型, 我们的默认设置从允许一切翻转式的改变成了几乎什么都不允许。 287 | 288 | 这是 `unknown`类型的主要价值主张:`TypeScript` 不允许我们对类型为 `unknown`的值执行任意操作。相反, 我们必须首先执行某种类型检查以缩小我们正在使用的值的类型范围。 289 | 290 | ## Null & Undefined 类型 291 | 292 | `undefined` 和 `null` 两者各自有自己的类型分别叫做 `undefined` 和 `null`。 293 | 294 | ```ts 295 | let u: undefined = undefined; 296 | let n: null = null; 297 | ``` 298 | 299 | 默认情况下`null`和`undefined`是所有类型的子类型。 就是说你可以把 `null`和`undefined`赋值给`number`类型的变量。**当你指定了`--strictNullChecks`标记, `null`和`undefined`只能赋值给`void`和它们各自的类型。** 300 | 301 | ## Void 类型 302 | 303 | 某种程度上来说, `void` 类型像是与any类型相反, 它**表示没有任何类型**。 当一个函数没有返回值时, 你通常会见到其返回值类型是 `void` : 304 | 305 | ```ts 306 | function warnUser(): void { 307 | console.log("This is my warning message"); 308 | } 309 | 310 | ``` 311 | 312 | 声明一个 `void` 类型的变量没有什么大用, 因为你只能为它赋予 `undefined` 和 `null`: 313 | 314 | ```ts 315 | let unusable: void = undefined; 316 | ``` 317 | 318 | ## Never 类型 319 | 320 | `never`类型表示的是那些**永不存在的值的类型**。例如, `never` 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。 321 | 322 | ```ts 323 | // 返回never的函数必须存在无法达到的终点 324 | function error(message: string): never { 325 | throw new Error(message); 326 | } 327 | 328 | // 推断的返回值类型为never 329 | function fail() { 330 | return error("Something failed"); 331 | } 332 | 333 | // 返回never的函数必须存在无法达到的终点 334 | function infiniteLoop(): never { 335 | while (true) { 336 | } 337 | } 338 | ``` 339 | 340 | `never`类型是任何类型的子类型, 也可以赋值给任何类型, 但它不可以被其他类型赋值, 它**只能被赋值**给另外一个 `never` 类型, `any` 也不行, 。 341 | 342 | ```ts 343 | function neverKnow(): never { 344 | throw new Error('error'); 345 | } 346 | 347 | let idk: never = neverKnow(); 348 | 349 | idk = "I don't know"; 350 | // Type '"I don't know"' is not assignable to type 'never'. 351 | ``` 352 | 353 | [Go Demo](https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABGApgNxQJwNJjgdwAoBKALmXS0QG8AoRRKAC0wIv0QFFNXNCByLL37EA3LQC+tWgBsUURDAAmAa3KoMmRAF4Km3ARLjaylTsQAiAJKIlCfgpV58F0UA) 354 | 355 | 在没有开启 **--strictNullChecks** 的前提下使用 `never` 避免出现新增了联合类型没有对应的实现, 目的就是写出类型绝对安全的代码。 356 | 357 | 举个具体点的例子, 当你有一个 `union type`: 358 | 359 | ```ts 360 | interface Foo { 361 | type: 'foo' 362 | } 363 | 364 | interface Bar { 365 | type: 'bar' 366 | } 367 | 368 | type All = Foo | Bar 369 | ``` 370 | 371 | 在 `switch` 当中判断 `type`, `TS` 是可以收窄类型的 `(discriminated union)`: 372 | 373 | ```ts 374 | function handleValue(val: All) { 375 | switch (val.type) { 376 | case 'foo': 377 | // 这里 val 被收窄为 Foo 378 | break 379 | case 'bar': 380 | // val 在这里是 Bar 381 | break 382 | default: 383 | // val 在这里是 never 384 | const exhaustiveCheck: never = val 385 | break 386 | } 387 | } 388 | ``` 389 | 390 | 注意在 `default` 里面我们把被收窄为 `never` 的 `val` 赋值给一个显式声明为 `never` 的变量。如果一切逻辑正确, 那么这里应该能够编译通过。但是假如后来有一天你的同事改了 All 的类型: 391 | 392 | ```ts 393 | type All = Foo | Bar | Baz 394 | ``` 395 | 396 | 然而他忘记了在 `handleValue` 里面加上针对 `Baz` 的处理逻辑, 这个时候在 `default branch` 里面 val 会被收窄为 Baz, 导致无法赋值给 `never`, 产生一个编译错误。所以通过这个办法, 你可以确保 `handleValue` 总是穷尽 `(exhaust)` 了所有 `All` 的可能类型。 397 | 398 | [TypeScript中的never类型具体有什么用? - 尤雨溪的回答 - 知乎](https://www.zhihu.com/question/354601204/answer/888551021) 399 | 400 | [Typescript Handbook 详尽检查](https://www.typescriptlang.org/docs/handbook/advanced-types.html#exhaustiveness-checking) 401 | 402 | ### Never 与 Void 的区别 403 | 404 | - `void`表示没有任何类型, `never`表示永不存在的值的类型 405 | - `--strictNullChecking=false`时, `void` 可以被赋值为任意类型, `never`只能被赋值为 `never` 406 | 407 | 410 | 411 | ## 快来耍耍啊 412 | 413 | ### 🌰🌰 414 | 415 | 定义一个人员信息, 包括姓名, 年龄等信息。 416 | 417 | ``` 418 | const profile = {} 419 | ``` 420 | 421 | ### 游乐场 422 | 423 |
424 | 425 | 429 | 430 | 433 | 434 | 435 | 436 | ### 参考答案 437 | 438 | ```ts 439 | interface Profile { 440 | name: string; 441 | age: number | string; 442 | } 443 | ``` 444 | 445 | ## 参考资料 446 | 447 | [Typescript Basic Types](https://www.typescriptlang.org/docs/handbook/basic-types.html) -> [中文](https://www.tslang.cn/docs/handbook/basic-types.html) 448 | 449 | [Typescript Handbook](https://www.typescriptlang.org/docs/handbook/basic-types.html) 450 | 451 | [the-unknown-type-in-typescript](https://mariusschulz.com/blog/the-unknown-type-in-typescript) 452 | -------------------------------------------------------------------------------- /docs/zh/blog/README.md: -------------------------------------------------------------------------------- 1 | ## 博客 & 学习网站 2 | 3 | - [TypeScript Github](https://github.com/Microsoft/TypeScript) 4 | - [Typescritp tsconfig](https://www.typescriptlang.org/tsconfig) 5 | - [Typescript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) 6 | - [Typescript Playground](https://www.typescriptlang.org/play): `TypeScript` 游乐场 7 | - [《TypeScript Deep Dive》](https://basarat.gitbook.io/typescript/) 是一本很好的开源书, 从基础到深入, 很全面的阐述了 `TypeScript` 的各种魔法, 不管你是新手, 还是老鸟, 它都将适应你。此外, 它不同于 `TypeScript` 官方给出的文档(当然 `TypeScript` 给出的文档是很好的), 在此书中, 结合实际应用下的场景用例, 你将能更深入的理解 `TypeScript`。[中文版](https://jkchao.github.io/typescript-book-chinese/) 8 | - [awesome-typescript](https://github.com/semlinker/awesome-typescript) 收集了很多 `Typescript` 的相关学习资料。 9 | - [typescript-cheatsheets-react](https://github.com/typescript-cheatsheets/react) 10 | 11 | ## Tips 12 | 13 | - [一些 Typescript的小知识](https://www.yuque.com/arvinxx-fe/typescript) 14 | 15 | ## Pdf & 书籍资料 16 | 17 | - [TypeScript入门指南案例教程(阮一峰).pdf](https://github.com/Rain120/typescript-guide/releases/tag/0.0.1) 18 | -------------------------------------------------------------------------------- /docs/zh/built-in-objects/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | **内置对象** 是指根据标准`(ECMAScript, DOM, BOM 等其他标准)`在全局作用域 `(Global)` 上已经存在定义的对象。`JavaScript` 中有很多 [标准内置对象](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects), 它们可以直接在 `TypeScript` 中当做定义好了的类型。 4 | 5 | ## ECMAScript 的内置对象 6 | 7 | 从 `MDN` 中 [JavaScript 标准内置对象](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects) 中, 我们知道 `JavaScript` 有很多 **内置对象**, 比如 `String`, `Boolean`, `Date`等等。那在 `Typescript` 中, 我们改怎么取定义这些类型呢? 8 | 9 | ```ts 10 | // https://github.com/microsoft/TypeScript/blob/2dd7a4bf939ffac4002ea9c76651166ba457ac70/src/lib/es5.d.ts#L497 11 | const name: String = new String('Rain120'); 12 | 13 | // https://github.com/microsoft/TypeScript/blob/2dd7a4bf939ffac4002ea9c76651166ba457ac70/src/lib/es5.d.ts#L509 14 | const handsome: Boolean = new Boolean(true); 15 | 16 | // https://github.com/microsoft/TypeScript/blob/2dd7a4bf939ffac4002ea9c76651166ba457ac70/src/lib/es5.d.ts#L709 17 | const birthday_month: Date = new Date('11'); 18 | ``` 19 | 20 | 这里我们使用 `Typescript` 来实现下 `Boolean` 定义。 21 | 22 | ```ts 23 | 24 | interface Boolean { 25 | /** Returns the primitive value of the specified object. */ 26 | valueOf(): boolean; 27 | } 28 | 29 | interface BooleanConstructor { 30 | new(value?: any): Boolean; 31 | (value?: T): boolean; 32 | readonly prototype: Boolean; 33 | } 34 | 35 | declare var Boolean: BooleanConstructor; 36 | ``` 37 | 38 | 更多`ES5` 相关的内置对象定义在这👉👉👉 [Here on Typescript Definition](https://github.com/microsoft/TypeScript/blob/master/src/lib/es5.d.ts) 39 | 40 | ## DOM & BOM 的内置对象 41 | 42 | [DOM (文档对象模型)](https://developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model) 和 `BOM (浏览器对象模型)`提供了很多内置对象,比如 `NodeList`, `HTMLElemnt` 等内置对象。 43 | 44 | ```ts 45 | // https://github.com/microsoft/TypeScript/blob/2dd7a4bf939ffac4002ea9c76651166ba457ac70/src/lib/dom.generated.d.ts#L10984 46 | const divs: NodeList = document.querySelectorAll('div'); 47 | 48 | // https://github.com/microsoft/TypeScript/blob/master/src/lib/dom.generated.d.ts#L10984 49 | interface Window { 50 | history: History 51 | } 52 | 53 | console.log(window?.history) 54 | ``` 55 | 56 | 57 | 58 | 更多`DOM` 相关的内置对象定义在这👉👉👉 [Here on Typescript Definition](https://github.com/microsoft/TypeScript/blob/master/src/lib/dom.generated.d.ts) 59 | 60 | ## 包内置对象 61 | 62 | 当你使用 `Typescript` 写 `Node` 时, 你会发现很多都没有语法提示,这时,你需要执行下面的命令 63 | 64 | ```sh 65 | npm install @types/node 66 | ``` 67 | 68 | 在 `@types/node` 已经将 `node` 所有的内置对象的 `typescript` 的定义都定义好了,当前很多 `typescript` 包也都有这类的 `type` 定义, 你可以通过下列命令来 **查询是否存在类型定义** 且 **安装类型定义文件** 69 | 70 | ```sh 71 | # 查询是否存在类型定义 72 | npm search @types/xxx 73 | 74 | # 安装 75 | npm install @types/xxx 76 | ``` 77 | 78 | ## 快来耍耍啊 79 | 80 | ### 🌰🌰 81 | 82 | 83 | 84 | ``` 85 | // template 86 | ``` 87 | 88 | ### 游乐场 89 | 90 |
91 | 92 | 95 | 96 | ### 参考答案 97 | 98 | ```ts 99 | // answer 100 | ``` 101 | 102 | ## 参考资料 103 | 104 | [Typescript 核心文件库](https://github.com/Microsoft/TypeScript/tree/master/src/lib) 105 | 106 | [JavaScript 标准内置对象](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects) 107 | 108 | [文档对象模型 DOM](https://developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model) 109 | 110 | [MDN Window](https://developer.mozilla.org/zh-CN/docs/Web/API/Window) -------------------------------------------------------------------------------- /docs/zh/class/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | 类(英语: `class`)在[**面向对象编程(oop)**](https://zh.wikipedia.org/zh-cn/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1)中是一种面向对象计算机编程语言的构造, 是创建对象的蓝图, 描述了所创建的对象共同的属性和方法。 4 | 5 | `JavaScript` 语言中, 生成实例对象的传统方法是通过构造函数。`ES6` 提供了更接近传统语言的写法, 引入了 `Class(类)`这个概念, 作为对象的模板。通过 `class` 关键字, 可以定义类。 6 | 7 | `TypeScript` 除了实现了所有 `ES6` 中的类的功能以外,还添加了一些新的用法。 8 | 9 | ### 类的概念 10 | 11 | - 对象 12 | 13 | 类的实例, 通过 `new`实例化 14 | 15 | - [面向对象三大特性](#面向对象的三大特性) 16 | 17 | 👇👇👇 [Here](#面向对象的三大特性) 18 | 19 | - [存取器](#存取器) 20 | 21 | `getter`: 对属性的取值行为 22 | 23 | `setter`: 对属性的赋值行为 24 | 25 | - [修饰符](#修饰符) 26 | 27 | `public`: 修饰**公有**属性和方法 `(默认)`,可以在任何地方被访问到 28 | 29 | `protected`: 修饰**保护**属性和方法,在子类中也是允许被访问的 30 | 31 | `private`: 修饰**私有**属性和方法,不能在声明它的类的外部访问 32 | 33 | - [静态属性 & 方法 `static`](#静态属性-方法) 34 | 35 | **只能**通过类访问的属性 `or` 方法。 36 | 37 | - [抽象类](#抽象类) 38 | 39 | 抽象类`(absctract)`是供其他类继承的基类,**抽象类不允许被实例化**。抽象类中的抽象方法**必须在子类中被实现** 40 | 41 | - [接口](#把类当接口使用) 42 | 43 | 不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现 `(implements)`。**一个类只能继承自另一个类,但是可以实现多个接口** 44 | 45 | ## 面向对象的三大特性 46 | 47 | ### 封装 48 | 49 | 利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,**数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节**,只保留一些对外接口使之与外部发生联系。 50 | 51 | ### 继承 52 | 53 | 子类获取父类的所有属性和行为`(除了父类中用 private 修饰的变量和方法)`。 54 | 55 | ### 多态 56 | 57 | **多种不同的实现方式**即为多态, 它允许方法重名,参数或返回值可以是父类型传入或返回。 58 | 59 | ## 类的好处 60 | 61 | - 对象提供了模型化和信息隐藏的好处。 62 | 63 | - 类提供了[可重复使用性](https://zh.wikipedia.org/w/index.php?title=可重複使用性&action=edit&redlink=1)的好处。 64 | 65 | ## 使用 66 | 67 | ### public(公有) & protected(保护) & private(私有) 修饰符 68 | 69 | #### public 70 | 71 | 修饰**公有**属性和方法 `(默认)`,可以在任何地方被访问到 72 | 73 | ```ts 74 | class Animal { 75 | public name: string; 76 | public constructor(theName: string) { this.name = theName; } 77 | public move(distanceInMeters: number) { 78 | console.log(`${this.name} moved ${distanceInMeters}m.`); 79 | } 80 | } 81 | ``` 82 | 83 | [Playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAECCB2BLAtmE0DeAoavoAcBXAIxEWGnjGQFMAuaCAFwCdF4BzAbhzyNPLRgAe3jMWhYE2EsAFEwAWNAHLV6jVuw4BKTNEWIIAOiq1oAXn1LVtLtAC+vXPzIVkwgG41ZAE0NMweGAaAEl4AFkaJhoWCAZ4QmRiGN1sPHShUQhhEBojEGEOWQADABIMA2NTGntody8faHK-ZkDgsMjo2PtkI2LtHnTHeyA) 84 | 85 | #### protected 86 | 87 | 修饰**保护**属性和方法,在子类中也是允许被访问的 88 | 89 | ```ts 90 | class Person { 91 | protected name: string; 92 | constructor(name: string) { this.name = name; } 93 | } 94 | 95 | class Employee extends Person { 96 | private department: string; 97 | 98 | constructor(name: string, department: string) { 99 | super(name) 100 | this.department = department; 101 | } 102 | 103 | public getElevatorPitch() { 104 | return `Hello, my name is ${this.name} and I work in ${this.department}.`; 105 | } 106 | } 107 | 108 | let rainy = new Employee("Rain", "120"); 109 | console.log(rainy.getElevatorPitch()); 110 | console.log(rainy.name); // 错误 111 | ``` 112 | 113 | [Playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAEAKCmAnCB7AdtA3gKGn6ADoigC7zBkAm0aYAtvAFzQQmICWaA5gNy77B0rRAFcKKRAApaDZsM5cAlFmgkAFuwgA6GfGgBeGvXg9oAX2wXsoSDACidAiBQBPeHvgAPMmkowEyOhY-HhE7ABuYGTQlPAEYIgkDGgkcmwKfCHQgmjCYiQS0sZpHNwANDFxCUnwKSUKyjj4zSwiBEhFDIpZzeqaWrHxickkBpVDNSl8zVbNBCIARiDswNBc8CR2IPCRBYiw7CTAapKNPfiIGyKIGAAGABLwIM4VdC5GDNCa0AAkmH3aXRmaBgXzQACS0AA7hIANZfDB-AEDKrDWokMxaW7TfAWKzbUaIMCcd6GNDwKHQBxOVzuSQAIgASsS0PSKvSAIwAJgADPTFHwcqhtlpnFxJESSVp1pttrsJAcjidFALrEIUCKxRKWS4dMYBdAAPSG6CATFTAPfRQA) 114 | 115 | #### private 116 | 117 | 修饰**私有**属性和方法,不能在声明它的类的外部访问 118 | 119 | ```ts 120 | class Animal { 121 | private name: string; 122 | constructor(theName: string) { this.name = theName; } 123 | } 124 | 125 | class Cat extends Animal { 126 | constructor() { super("Cat"); } 127 | } 128 | 129 | class Employee { 130 | private name: string; 131 | constructor(theName: string) { this.name = theName; } 132 | } 133 | 134 | let animal = new Animal("Dog"); 135 | let cat = new Cat(); 136 | let employee = new Employee("Rain120"); 137 | 138 | animal = cat; 139 | animal = employee; // 错误: Animal 与 Employee 不兼容. 140 | ``` 141 | 142 | [Playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAECCB2BLAtmE0DeAoavoAcAnRANzABcBTaeMZSgLmgnOPgHMBuHPYAe3gtCAV2Dk+hABTkAFpQBydRs1aIOASkzRZiCADpa9aAF5tcxfU7QAvlltZQkGAGEK0SgA8q8ACYwEKGiYPLj8gqyi4lKaGMzC+JRSAESu5EnqVrb2jlDQAKLI+CB8AJ6U1Nh4BMRkVDRKTEJqXCHQYUKREtLmDSps7DFmugZKJmYKSpl2WFgglOTQYEio6KbwlADucMtokkkAInzs6dxzC8Bua5vQqZIZs-PuhcVl1FdbBUWl5XsASmBqACMACYAAwnGZLQKrNoUbhQlZjSjPb6UKwAenR0EAmKmAe+imAFEYA4OXyKNe0EAsHKAH0VAJ3aeiAA) 143 | 144 | ### readonly 修饰符 145 | 146 | #### 属性 147 | 148 | 将属性设置为只读的。 **只读属性必须在声明时或构造函数里被初始化**。 149 | 150 | ```ts 151 | class Octopus { 152 | readonly name: string; 153 | readonly numberOfLegs: number = 8; 154 | constructor (theName: string) { 155 | this.name = theName; 156 | } 157 | } 158 | let dad = new Octopus("Man with the 8 strong legs"); 159 | dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的. 160 | ``` 161 | 162 | [Playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAEDywBcD2AHArjA3gKGn6ATgKZgAmSAdiAJ7QVgC2RAXNBAgQJYUDmA3LnzEylGnTQMARkQKwAZgBkiPCKwoTpBaAF5oADgH5owSuwJpESLQAoEACyIA5RizYduPAJTQcRo-c4IADp6Jh1oeycXQ3wAX2x4kCIEaFIycIoiAHc4S3QIawAiAFkwCmgsznsIh303AkoeaCSVQs8BNNIQl3CSsoqquxqiaABmAFoUTiJgEYg0KsK+IA) 163 | 164 | #### 参数 165 | 166 | ```ts 167 | class Octopus { 168 | readonly numberOfLegs: number = 8; 169 | constructor(readonly name: string) { 170 | } 171 | } 172 | ``` 173 | 174 | [Playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAEDywBcD2AHArjA3gKGn6ATgKZgAmSAdiAJ7QVoC2ARkQbAGYAyRA5hAFx1GLAtAC80ABwBuXPmCUICAmkRICACmJlKNOmAZFBSggEsKPAJTQc+aAF9s9oA) 175 | 176 | ### 存取器 177 | 178 | ```ts 179 | class Employee { 180 | private _fullName: string = ''; 181 | 182 | constructor(_fullName: string) {} 183 | 184 | get fullName(): string { 185 | return this._fullName; 186 | } 187 | 188 | set fullName(newName: string) { 189 | this._fullName = newName; 190 | } 191 | } 192 | 193 | let employee = new Employee('Rainy'); 194 | employee.fullName = "Rain120"; 195 | console.log(employee.fullName) 196 | ``` 197 | 198 | [Playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAECiC2AHEB7AngUw9A3gKGkOkQCcBLANzABdsB9AMwFcQQA5MeDALmgmvIA7AObQAvNADkkgNx48ASGApB-Ek2DUUJABSMW7Tjz4CyIgJS4AvvKLRhGatGasOXHed5qzo-HbskjkwkgtDUABZkEAB0+q5GcnY2BEQQjs4Gbhg6ghgA7llepha4Kf5hkTFxhlzi0LkFCWXQNskg6RhIqJjYEg1wXehYOpIASmBmaJLmcp3IQxjRLjW90ABE42YAjABMAAxrcsqqKO3RqMI6c91YS5lG5kA) 199 | 200 | **Note:** 201 | 202 | - 存取器要求你将编译器设置为输出 `ECMAScript 5`或更高。 不支持降级到`ECMAScript 3`。 203 | - **只带有 `get`不带有 `set`的存取器**自动被推断为 `readonly`。 这在从代码生成 `.d.ts`文件时是有帮助的,因为利用这个属性的用户会看到不允许够改变它的值。 204 | 205 | ### 静态属性 & 方法 206 | 207 | 只能通过类来访问,实例不行 208 | 209 | ```ts 210 | class Boy { 211 | static handsome: boolean = true; 212 | constructor(public name: string) {} 213 | static isHandsome() { 214 | return this.handsome; 215 | } 216 | } 217 | 218 | let rain120 = new Boy('Rain120'); 219 | console.log(Boy.handsome); 220 | console.log(Boy.isHandsome); 221 | console.log(rain120.handsome); // Property 'handsome' is a static member of type 'Boy' 222 | console.log(rain120.isHandsome); // Property 'isHandsome' is a static member of type 'Boy' 223 | ``` 224 | 225 | [Playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAEBCD2BPaBvAUNaEAuZsEthoALMAOwBMJ4BbAUwC5oAjeeEO86AXmmwCcArnQDcGaMHhkcQ4Nnj8AFAAdBzEIWhkw9JjPxkA5gEpUAX3E48m-BAAS5KrTqLT6TJn51sg-mT7EtgB0pJTU9GKYFhZoHNjQ-GAGAIwATAAMPFp0AO5wSIoA5ABKSWRp6YXGYpLS7HRBIPCGigiIIY7hdMZotdQcjc2tSEG2DmHOPX31gy2JKRkdE-RTUv0NTXNlFaP2nZNAA) 226 | 227 | ### 继承 228 | 229 | ```ts 230 | class Boy { 231 | handsome: boolean; 232 | name: string; 233 | 234 | constructor(name: string, handsome: boolean) { 235 | this.name = name; 236 | this.handsome = handsome; 237 | } 238 | 239 | isHandsome() {} 240 | } 241 | 242 | class Mine extends Boy { 243 | isHandsome() { 244 | return this.handsome; 245 | } 246 | } 247 | 248 | const mine = new Mine('Rain120', true); 249 | console.log(mine) 250 | ``` 251 | 252 | [Playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAEBCD2BPaBvAUNaALMA7AJhPALYCmAXNAEbzwil4DcG0uYZlEALgE4CWuAObNMLYPFzceAV2Bd4PABRsO0KQMEAabHkIkK1WvTwBKVC0xcsfCADoVpaAF5W7UiMzQrN2zgJEyZx1-fQ8AXxY0AEgbAAldANJFMxQIiLRQSBgAWQFHUgAPLlJ-OCRzTDiE-WSKzx5SLmkeXC9rOz89MnC0dPFJLmhiPKDcUgB3aFyxxQByACUwAQBGACYABlntXmlSE2Z+onpbEHhBRWGxkyA) 253 | 254 | ### 多态 255 | 256 | ```ts 257 | export function trace(cities: any, prop?: string, enterBreakPoint?: boolean): void; 258 | 259 | export function trace(cities: any, enterBreakPoint?: boolean): void; 260 | 261 | export function trace(enterBreakPoint?: boolean): void; 262 | 263 | export function trace(...args: any[]): void { 264 | } 265 | ``` 266 | 267 | [Playground](https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBAMwK4DsDGMCWEVxlAQzWAAo1MtgBnALjgJQE8AaOMKCMAfjqv0xQBzVsBQxgUAEJRgBANYAFCAJg84AIwgQANrJQBKOgDdlAEwDcAKEuhIsRKgzZc+IqXKVa9JiLETpsorKYmqaOnqGcCaYFta20PDI6Fg4eITEJKLiUjLySiqhWroMkdGxNuAJDsnOaW4kAHRNBFCCXgyMANoAuqVmcADelgC+QA) 268 | 269 | ### 抽象类 270 | 271 | ```ts 272 | abstract class Boy { 273 | handsome: boolean; 274 | name: string; 275 | 276 | constructor(name: string, handsome: boolean) { 277 | this.name = name; 278 | this.handsome = handsome; 279 | } 280 | 281 | abstract isHandsome(): boolean; 282 | } 283 | 284 | class Mine extends Boy { 285 | isHandsome() { 286 | return this.handsome; 287 | } 288 | } 289 | 290 | const mine = new Mine('Rain120', true); 291 | console.log(mine); 292 | ``` 293 | 294 | [Playground](https://www.typescriptlang.org/play?#code/IYIwzgLgTsDGEAJYBthjAgQgewJ4IG8AoBBAC2ADsATMbAWwFMAuBEbbZRqgbhIUrAmrSFACWlAOZ9S-WNkqiArvGxQAFIOEJREyQBpyVWgxZsOXKgEpC-UhDJiwAOi2MEAXgFDGM0ggcnZwoaOiZPI1DTPwBffn5QUThEJwAJYzDGdStWdk5uSj44ohQ0DABZCXdGAA8IRlCsPFtSNIzTbJb-KEYIJShKAMcXEJMmWKJi+UVEeiqIykYAdwRKxfUAcgAlYAkARgAmAAYNw2glRis+abouZ2RsSXU5xaugA) 295 | 296 | ### 把类当接口使用 297 | 298 | ```ts 299 | class Boy { 300 | handsome: boolean = true; 301 | } 302 | 303 | class Girl { 304 | beatiful: boolean = true; 305 | } 306 | 307 | enum Gender { 308 | 'MALE', 309 | 'FEMALE' 310 | } 311 | 312 | interface Person extends Boy, Girl { 313 | gender: Gender; 314 | } 315 | ``` 316 | 317 | [Playground](https://www.typescriptlang.org/play?#code/MYGwhgzhAEBCD2BPaBvAUNaALMA7AJhPALYCmAXNAEbzwil7QC80ALgE4CupA3GgL5o0oSDADiAS3YhUGag1YSAZpxCUadBrmZsuvAUNK5OxaGKP5S7WZgDkAWQCCAGQCitgDRzbAMVdO3WwM0CVxWKyUwYFJoAAUrIm1SAA9wghgERA8zKRl0TABzCytKcwIrPn4gA) 318 | 319 | ## 快来耍耍啊 320 | 321 | ### 🌰🌰 322 | 323 | 324 | 325 | ``` 326 | // template 327 | ``` 328 | 329 | ### 游乐场 330 | 331 |
332 | 333 | 336 | 337 | ### 参考答案 338 | 339 | ```ts 340 | // answer 341 | ``` 342 | 343 | ## 参考资料 344 | 345 | [handbook - classes](https://www.typescriptlang.org/docs/handbook/classes.html) 346 | 347 | [深入理解 TypeScript - 类](https://jkchao.github.io/typescript-book-chinese/faqs/class.html) 348 | 349 | [ECMAScript 6入门 - Class基本语法](https://es6.ruanyifeng.com/#docs/class) 350 | 351 | [类 (计算机科学)](https://zh.wikipedia.org/zh-cn/%E7%B1%BB_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)) 352 | -------------------------------------------------------------------------------- /docs/zh/compile-config/README.md: -------------------------------------------------------------------------------- 1 | ## 配置 2 | 3 | - 手动 创建一个 `tsconfig.json`文件 4 | - 使用`tsc`命令 5 | - `npx tsc --init` 6 | - `npm i -g typescript` `tsc --init` 7 | 8 | `config` 文件解释 9 | 10 | ```json 11 | { 12 | "extends": "extends config files path", // 从另一个配置文件里继承配置 13 | "compileOnSave": true, // IDE在保存文件的时候根据tsconfig.json重新生成文件。 14 | "compilerOptions": { 15 | /* 基本选项 */ 16 | "target": "es5", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT' 17 | "module": "commonjs", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015' 18 | "lib": [], // 指定要包含在编译中的库文件 19 | "allowJs": true, // 允许编译 javascript 文件 20 | "checkJs": true, // 报告 javascript 文件中的错误 21 | "jsx": "preserve", // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react' 22 | "declaration": true, // 生成相应的 '.d.ts' 文件 23 | "sourceMap": true, // 生成相应的 '.map' 文件 24 | "outFile": "./", // 将输出文件合并为一个文件 25 | "outDir": "./", // 指定输出目录 26 | "rootDir": "./", // 用来控制输出目录结构 --outDir. 27 | "removeComments": true, // 删除编译后的所有的注释 28 | "noEmit": true, // 不生成输出文件 29 | "importHelpers": true, // 从 tslib 导入辅助工具函数 30 | "isolatedModules": true, // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似). 31 | 32 | /* 严格的类型检查选项 */ 33 | "strict": true, // 启用所有严格类型检查选项 34 | "noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错 35 | "strictNullChecks": true, // 启用严格的 null 检查 36 | "noImplicitThis": true, // 当 this 表达式值为 any 类型的时候, 生成一个错误 37 | "alwaysStrict": true, // 以严格模式检查每个模块, 并在每个文件里加入 'use strict' 38 | 39 | /* 额外的检查 */ 40 | "noUnusedLocals": true, // 有未使用的变量时, 抛出错误 41 | "noUnusedParameters": true, // 有未使用的参数时, 抛出错误 42 | "noImplicitReturns": true, // 并不是所有函数里的代码都有返回值时, 抛出错误 43 | "noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误。(即, 不允许 switch 的 case 语句贯穿) 44 | 45 | /* 模块解析选项 */ 46 | "moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6) 47 | "baseUrl": "./", // 用于解析非相对模块名称的基目录 48 | "paths": {}, // 模块名到基于 baseUrl 的路径映射的列表 49 | "rootDirs": [], // 根文件夹列表, 其组合内容表示项目运行时的结构内容 50 | "typeRoots": [], // 包含类型声明的文件列表 51 | "types": [], // 需要包含的类型声明文件名列表 52 | "allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。 53 | 54 | /* Source Map Options */ 55 | "sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置 56 | "mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置 57 | "inlineSourceMap": true, // 生成单个 soucemaps 文件, 而不是将 sourcemaps 生成不同的文件 58 | "inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中, 要求同时设置了 --inlineSourceMap 或 --sourceMap 属性 59 | 60 | /* 其他选项 */ 61 | "experimentalDecorators": true, // 启用装饰器 62 | "emitDecoratorMetadata": true // 为装饰器提供元数据的支持 63 | }, 64 | "files": [], // 指定一个包含相对或绝对文件路径的列表 65 | "include": [], // 指定文件包含列表 (glob匹配模式) 66 | "exclude": [], // 指定文件过滤列表 (glob匹配模式) 67 | } 68 | ``` 69 | 70 | [官网文档 - tsconfig.json](http://www.tslang.cn/docs/handbook/tsconfig-json.html) 71 | 72 | [tsconfig schema](http://json.schemastore.org/tsconfig) 73 | 74 | ::: tip 75 | 如果一个 `glob` 模式里的某部分只包含 `* 或 .*`, 那么仅有支持的文件扩展名类型被包含在内(比如默认 `.ts`, `.tsx`, 和 `.d.ts`, 如果 `allowJs: true` 还包含 `.js` 和`.jsx`)。 76 | 77 | 支持的 `glob` 通配符有: 78 | 79 | - **\*** 匹配0或多个字符(不包括目录分隔符) 80 | 81 | - **?** 匹配一个任意字符(不包括目录分隔符) 82 | 83 | - **\*\*/** 递归匹配任意子目录 84 | 85 | ::: 86 | 87 | ## 编译选项 88 | 89 | 运行`tsc`即可将`ts`编辑成`js`文件, 运行`tsc -w` 在监视模式下运行编译器。 90 | 91 | `--watch / -w`: 在监视模式下运行编译器。会监视输出文件, 在它们改变时重新编译。监视文件和目录的具体实现可以通过环境变量进行配置。详情请看[配置 Watch](http://www.tslang.cn/docs/handbook/configuring-watch.html)。 92 | 93 | 编译会通过配置文件`tsconfig.json`中`files`, `include`, `exclude`来读取, 筛选文件。 94 | 95 | **Note:** 可以通过`globs`来匹配文件, `eg:` `lib/**/*` 96 | 97 | [编译选项](http://www.tslang.cn/docs/handbook/compiler-options.html) 98 | 99 | ## 配置详解 100 | 101 | - [references](./references/README.md) 102 | 103 | - [tsconfig-module-target](./tsconfig-module-target/README.md) 104 | 105 | - [TypeScript 文件包含相关配置](./file-inclusion/README.md) 106 | 107 | ## 参考资料 108 | 109 | [深入理解 TypeScript](https://jkchao.github.io/typescript-book-chinese/) 110 | 111 | [Typescritp tsconfig](https://www.typescriptlang.org/tsconfig) 112 | -------------------------------------------------------------------------------- /docs/zh/compile-config/file-inclusion/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | 这些设置用于确保 `TypeScript` 处理正确的文件。 4 | 5 | ## 关键字 6 | 7 | ### extends 8 | 9 | 默认值: `false` 10 | 11 | `extends` 的值是一个字符串,它包含要继承的另一个配置文件的路径。路径可以使用 `Node.js` 样式解析。 12 | 13 | 首先加载基本文件中的配置,然后由 **继承的配置文件** 中的配置覆盖。**在配置文件中找到的所有相对路径都将相对于它们最初所在的配置文件进行解析。** 14 | 15 | 值得注意的是,从 **继承的配置文件** 中 [包含(include)](#include) 和 [排除(exclude)](#exclude) 的文件会覆盖从 **基本配置文件** 中 [包含(include)](#include) 和 [排除(exclude)](#exclude) 的文件,并且配置文件之间不允许循环。 16 | 17 | 目前,唯一被排除在继承之外的顶级属性是 [references](#references)。 18 | 19 | **Note👇👇👇** 20 | 21 | - 继承的配置文件: `tsconfig.json` 22 | 23 | - 基本配置文件: `tsconfig.base.json` 24 | 25 | `tsconfig.base.json` 26 | ```json 27 | { 28 | "compilerOptions": { 29 | "noImplicitAny": true, 30 | "strictNullChecks": true 31 | } 32 | } 33 | ``` 34 | 35 | `tsconfig.json` 36 | ```json 37 | { 38 | "extends": "./tsconfig.base" 39 | } 40 | ``` 41 | 42 | 在配置文件中找到的具有相对路径的属性(没有从继承中排除)将相对于它们的起始配置文件进行解析。 43 | 44 | ### exclude 45 | 46 | 默认值: `["node_modules", "bower_components", "jspm_packages"]`, 如果指定了一个, 则加上 `outDir` 的值。 47 | 48 | 它是用来指定解析 `include` 时应跳过的文件名或模式数组, 也就是文件过滤列表 (`glob` 匹配模式)。 49 | 50 | ```json 51 | { 52 | "exclude": ["node_modules"] 53 | } 54 | ``` 55 | 56 | ### include 57 | 58 | 默认值: 除非被指定了文件, 否则就是 `["**/*"]`。 59 | 60 | 指定要包含在程序中的文件名或模式的数组。这些文件名是相对于包含`tsconfig.json` 的目录解析的文件。 61 | 62 | ```json 63 | { 64 | "include": ["src/**/*", "tests/**/*"] 65 | } 66 | ``` 67 | 68 | 它将会包含 69 | 70 | ```sh 71 | . 72 | ├── scripts ⨯ 73 | │ ├── lint.ts ⨯ 74 | │ ├── update_deps.ts ⨯ 75 | │ └── utils.ts ⨯ 76 | ├── src ✓ 77 | │ ├── client ✓ 78 | │ │ ├── index.ts ✓ 79 | │ │ └── utils.ts ✓ 80 | │ ├── server ✓ 81 | │ │ └── index.ts ✓ 82 | ├── tests ✓ 83 | │ ├── app.test.ts ✓ 84 | │ ├── utils.ts ✓ 85 | │ └── tests.d.ts ✓ 86 | ├── package.json 87 | ├── tsconfig.json 88 | └── yarn.lock 89 | ``` 90 | 91 | ::: tip 92 | `include` 和 `exclude`支持通配符来生成 `glob`模式, 如下 👇👇👇: 93 | 94 | - **\*** 匹配 0 或多个字符(不包括目录分隔符) 95 | 96 | - **?** 匹配一个任意字符(不包括目录分隔符) 97 | 98 | - **\*\*/** 递归匹配任意子目录 99 | 100 | 如果一个 `glob` 模式里的某部分只包含 `* 或 .*`, 那么仅有支持的文件扩展名类型被包含在内(比如默认 `.ts`, `.tsx`, 和 `.d.ts`, 如果 `allowJs: true` 还包含 `.js` 和`.jsx`)。 101 | ::: 102 | 103 | ### files 104 | 105 | 默认值: `false` 106 | 107 | 指定程序中包含的文件的允许列表。如果无法找到任何文件,就会发生错误。 108 | 109 | ```json 110 | { 111 | "files": ["main.ts", "supplemental.ts"] 112 | } 113 | ``` 114 | 115 | **Note:** 当您只有少量文件且不需要使用 `glob` 来引用许多文件时,这很有用。如果需要,那么使用[include](#include)。 116 | 117 | ### references 118 | 119 | 默认值: `false` 120 | 121 | 项目引用是一种将你的 `TypeScript` 程序结构成更小块的方法。使用`Project References` 可以极大地改进构建和编辑器的交互时间, 强制组件之间的逻辑分离, 并以新的和改进的方式组织代码。 122 | 123 | ```json 124 | { 125 | "references": [ 126 | // ... path 127 | "some/path/which/you/want/to/set/it", 128 | ] 129 | } 130 | ``` 131 | 132 | 你可以在 **官方手册** 中的[项目参考(Project References)](https://www.typescriptlang.org/docs/handbook/project-references.html)资料部分阅读更多关于参考资料如何工作的内容, 或者参考我另一篇笔记获取更多有关于 [Project References](../references/README.md) 的信息。 133 | 134 | ### typeAcquisition 135 | 136 | 默认是: `false` 137 | 138 | 当你的编辑器中有一个 `JavaScript` 项目时, `TypeScript` 会使用`@types` 定义的 `DefinitelyTyped` 集合自动为你的节点模块提供类型。这称为自动类型获取, 您可以使用配置中的 `typeAcquisition` 对象对其进行自定义。换句话来说就是设置自动引入库类型定义文件 `.d.ts` 相关。 139 | 140 | #### 语法 141 | 142 | ```json 143 | { 144 | // ... 145 | "typeAcquisition": { 146 | // 是否开启自动引入库类型定义文件 .d.ts,默认为 false 147 | "enable": false, 148 | // 允许自动引入的库名,如:[ "jquery", "lodash" ] 149 | "include": ["jest"], 150 | // 排除的库名。 151 | "exclude": ["jquery"], 152 | } 153 | } 154 | 155 | ``` 156 | 157 | #### 使用 158 | 159 | 如果您想禁用或自定义此特性, 请创建 `jsconfig.json` 在项目的根目录中 160 | 161 | ```json 162 | { 163 | "typeAcquisition": { 164 | "enable": false 165 | } 166 | } 167 | ``` 168 | 169 | 如果你有一个特定的模块, 应该包括(但不在 `node_modules` 中) 170 | 171 | ```json 172 | { 173 | "typeAcquisition": { 174 | "include": ["jest"] 175 | } 176 | } 177 | ``` 178 | 179 | 如果不应该自动获取某个模块, 例如, 如果该库在您的 `node_modules` 中可用, 但您的团队已经同意不使用它 180 | 181 | ```json 182 | { 183 | "typeAcquisition": { 184 | "exclude": ["jquery"] 185 | } 186 | } 187 | ``` 188 | 189 | 在`TypeScript 4.1`中, 还添加了禁用文件名触发类型获取的特殊大小写的功能。 190 | 191 | ```json 192 | { 193 | "typeAcquisition": { 194 | "disableFilenameBasedTypeAcquisition": true 195 | } 196 | } 197 | ``` 198 | 199 | 这意味着在你的项目中有一个像 `jquery.js` 这样的文件不会自动从`DefinitelyTyped` 下载 `JQuery` 的类型。 200 | 201 | ## 快来耍耍啊 202 | 203 | ### 🌰🌰 204 | 205 | 206 | 207 | ``` 208 | 209 | // template 210 | 211 | ``` 212 | 213 | ### 游乐场 214 | 215 |
216 | 217 | 220 | 221 | ### 参考答案 222 | 223 | ```ts 224 | // answer 225 | ``` 226 | 227 | ## 参考资料 228 | 229 | [typescript lang: File Inclusion](https://www.typescriptlang.org/tsconfig#Project_Files_0) 230 | -------------------------------------------------------------------------------- /docs/zh/compile-config/module-resolver/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | 这些设置用于`TypeScript` 的模块解析。 4 | 5 | ## 关键字 6 | 7 | ### baseUrl 8 | 9 | 用于解析非相对模块名称的基目录。可以定义一个可以进行绝对文件解析的根文件夹。 10 | 11 | ```json 12 | { 13 | "compilerOptions": { 14 | "baseUrl": ".", 15 | } 16 | } 17 | ``` 18 | 19 | ### paths 20 | 21 | 根据 `baseUrl` 配置来告知 `TypeScript` 应如何解析 `require` 或 `import` 中的导入。 22 | 23 | ```json 24 | { 25 | "compilerOptions": { 26 | "baseUrl": ".", 27 | }, 28 | "paths": { 29 | "src": [ 30 | "./src/**" 31 | ] 32 | } 33 | } 34 | ``` 35 | 36 | ### rootDirs 37 | 38 | 使用 `rootDirs`,可以在构建时让编译器将这个路径列表中的路径的内容都放到一个文件夹中。 39 | 40 | ```json 41 | { 42 | "compilerOptions": { 43 | "rootDirs": [ 44 | "src/home", 45 | "src/profile", 46 | ], 47 | } 48 | ``` 49 | 50 | ### typeRoots 51 | 52 | 用来指定默认的类型声明文件查找路径,默认为 `node_modules/@types`, 指定 `typeRoots`后,`TypeScript` 编译器会从指定的路径去引入声明文件,而不是 `node_modules/@types`, 比如以下配置会从 `typings`路径下去搜索声明: 53 | 54 | ```json 55 | { 56 | "compilerOptions": { 57 | "typeRoots": ["./typings"] 58 | } 59 | } 60 | ``` 61 | 62 | ### types 63 | 64 | `TypeScript` 编译器会默认引入 `typeRoots` 下所有的声明文件,但是有时候我们并不希望全局引入所有定义,而是仅引入部分模块。这种情景下可以通过 `types` 指定模块名只引入我们想要的模块,比如以下只会引入 `jquery` 的声明文件: 65 | 66 | ```json 67 | { 68 | "compilerOptions": { 69 | "types": ["jquery"] 70 | } 71 | } 72 | ``` 73 | 74 | ## 快来耍耍啊 75 | 76 | ### 🌰🌰 77 | 78 | 79 | 80 | ``` 81 | // template 82 | ``` 83 | 84 | ### 游乐场 85 | 86 |
87 | 88 | 91 | 92 | ### 参考答案 93 | 94 | ```ts 95 | // answer 96 | ``` 97 | 98 | ## 参考资料 99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/zh/compile-config/references/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | `reference (引用)` 是 `TypeScript 3.0`的新特性,它支持将项目的各个部分定义为单独的`TypeScript`模块, 分割成更小的组成部分。除此之外,这允许以不同的方式配置这些模块,分别构建它们等等。 4 | 5 | ## 什么是项目引用 6 | 7 | 每个引用的`path`属性都可以指向包含 `tsconfig.json` 文件的目录,或者配置文件本身(可以有任何名称)。当你引用一个项目时: 8 | 9 | - **从被引用的项目中导入模块将会加载它的输出声明文件`(.d.ts)`** 10 | - 如果引用的项目生成`outFile`,则在此项目中将显示输出文件`.d.ts`文件的声明 11 | - 如果需要,构建模式将自动构建引用的项目 12 | 13 | #### Note 14 | 15 | 引用的工程必须启用新的`composite`设置。 这个选项用于帮助TypeScript快速确定引用工程的输出文件位置。 若启用`composite`标记则会发生如下变动: 16 | 17 | - 对于`rootDir`设置,如果没有被显式指定,默认为包含`tsconfig`文件的目录 18 | - 所有的实现文件必须匹配到某个`include`模式或在`files`数组里列出。如果违反了这个限制,`tsc`会提示你哪些文件未指定。 19 | - 必须开启`declaration`选项。 20 | 21 | ## 作用 22 | 23 | `reference` 属性作用是 **指定工程引用依赖**。通过分成多个项目,可以大大提高类型检查和编译的速度,减少使用编辑器时的内存使用,并改善对程序逻辑组的执行。 24 | 25 | ## 使用 26 | 27 | ```ts 28 | type Reference = string[] & { 29 | path: string; 30 | prepend?: Boolean; 31 | } 32 | ``` 33 | 34 | `prepend`选项可以启用前置某个依赖的输出,前置工程会将工程的输出添加到当前工程的输出之前。它对`.js`文件和`.d.ts`文件都有效,`source map`文件也同样会正确地生成。 35 | 36 | ### tsconfig.json 37 | 38 | ```json 39 | { 40 | "references": [ 41 | // ... path 42 | "some/path/which/you/want/to/set/it", 43 | ] 44 | } 45 | ``` 46 | 47 | 或者这样使用 48 | 49 | ```json 50 | { 51 | "references": [{ 52 | "path": "some/path/which/you/want/to/set/it", 53 | "prepend": true 54 | }] 55 | } 56 | ``` 57 | 58 | ## 快来耍耍啊 59 | 60 | ### 🌰🌰 61 | 62 | 63 | 64 | ``` 65 | // template 66 | ``` 67 | 68 | ### 游乐场 69 | 70 |
71 | 72 | 75 | 76 | ### 参考答案 77 | 78 | ```ts 79 | // answer 80 | ``` 81 | 82 | ## 参考资料 83 | 84 | [Typescript Handbook Reference](https://www.typescriptlang.org/docs/handbook/project-references.html) 85 | 86 | [How to use project references in TypeScript 3.0?](https://stackoverflow.com/questions/51631786/how-to-use-project-references-in-typescript-3-0) 87 | 88 | [What is a Project Reference?](https://www.typescriptlang.org/docs/handbook/project-references.html#what-is-a-project-reference) -------------------------------------------------------------------------------- /docs/zh/compile-config/tsconfig-module-target/README.md: -------------------------------------------------------------------------------- 1 | ## 前置 2 | 3 | 下面的内容在 `Typescript` 中是一个很常见的配置。 4 | 5 | ```json 6 | { 7 | "compilerOptions": { 8 | "target": "es5", 9 | "module": "es6" 10 | } 11 | } 12 | ``` 13 | 14 | 很多时候, 我们会混淆 `target` 和 `module`的意思, 所以这篇, 我们主要是来讲一下这两个的作用。 15 | 16 | > **ESNEXT** 表示[最新标准](https://github.com/tc39/proposals)的 `js` 版本 17 | 18 | ## Target 19 | 20 | **指定编译的 `ECMAScript` 目标版本** `(与代码的输出相关)`。 默认值: **"ES3"** 21 | 22 | ```ts 23 | [ 24 | 'ES5', 25 | 'ES2015', 26 | 'ES2016', 27 | 'ES2017', 28 | 'ES2018', 29 | 'ES2019', 30 | 'ESNEXT' 31 | ] 32 | ``` 33 | 34 | ## Module 35 | 36 | **指定生成哪个模块系统代码**。 默认值: 根据 `--target` 选项不同而不同, 即 `target === "ES6" ? "ES6" : "commonjs"` 37 | 38 | ► 只有 `"AMD"` 和 `"System"` 能和 `--outFile` 一起使用。 39 | 40 | ► `"ES6"` 和 `"ES2015"` 可使用在目标输出为 `"ES5"` 或更低的情况下 41 | 42 | ```ts 43 | [ 44 | 'none', 45 | 'commonjs', 46 | 'amd', 47 | 'system', 48 | 'umd', 49 | 'es2015', 50 | 'ESNEXT' 51 | ] 52 | ``` 53 | 54 | ## 如何理解 55 | 56 | - **`module` 决定于引入方式** 57 | 58 | - **`target` 决定于输出方式** 59 | 60 | 模块系统独立于语言实现。`ES6(ES2015)` 模块使用 `import / export` 语法, 由模块加载器来解释。 61 | 62 | `JavaScript` 本身可能面向 `ES5`, 并且仅使用 `ES5` 功能, 但是从理论上讲, 可以将模块加载器与以`ES2015` 模块语法运行的代码一起使用。尽管有可能, 但不一定要执行此操作。在 `ES5 JavaScript` 中使用 `CommonJS` 或 `AMD` 模块更为常见。 63 | 64 | **Note:** 在 `TypeScript 2.0` 之前甚至不允许这种组合。 65 | 66 | ## 快来耍耍啊 67 | 68 | ### 🌰🌰 69 | 70 | 71 | 72 | ``` 73 | // template 74 | ``` 75 | 76 | ### 游乐场 77 | 78 |
79 | 80 | 83 | 84 | ### 参考答案 85 | 86 | ```ts 87 | // answer 88 | ``` 89 | 90 | ## 参考资料 91 | 92 | [Understanding "target" and "module" in tsconfig](https://stackoverflow.com/questions/41993811/understanding-target-and-module-in-tsconfig) 93 | 94 | [编译选项](https://www.tslang.cn/docs/handbook/compiler-options.html) -------------------------------------------------------------------------------- /docs/zh/declaration/README.md: -------------------------------------------------------------------------------- 1 | ## 声明文件 2 | 3 | 当使用第三方库时, 我们需要引用它的声明文件, 才能获得对应的代码补全、接口提示等功能。 4 | 5 | :::warning 6 | 声明文件必需以 `.d.ts` 为后缀。 7 | ::: 8 | 9 | ### 项目如何识别声明文件(识别顺序) 10 | 11 | 优先从 `tsconfig.json` 配置的 `includes`字段配置的路径查询,然后从项目中查到`*.d.ts`文件,最后到 `node_modules/@types`路径中找。 12 | 13 | ### 声明文件位置 14 | 15 | - 第三方安装的 `@types/xxx`,会在 `node_modules/@types` 路径下。 16 | :::tip 应用方式 17 | 所有的 `@types` 包都会 **在编译时** 应用,`typescript` 会从 `node_modules/@types`,以及依赖包的 `node_modules/@types` 中去匹配到相应的 **类型定义文件**。 18 | 19 | ```sh 20 | . 21 | ├── node_modules 22 | │   ├── @types 23 | │   ├── pkg 24 | │   ├── node_modules 25 | │   ├── @types 26 | ``` 27 | ::: 28 | 29 | - 自定义的,我一般会写在项目的根路径 `typings` 或者 `@types`。 30 | 31 | :::tip 应用方式 32 | 自定义的 **类型定义** 可以通过 `tsconfig.json` 的配置 `compilerOptions.typesRoot` 来设置匹配的类型文件,如下👇🏻👇🏻👇🏻 33 | 34 | ```json 35 | { 36 | "compilerOptions": { 37 | "typeRoots" : ["./typings"] 38 | } 39 | } 40 | ``` 41 | 42 | **Note:** 只有在 `typeRoots` 中的包才会被包含,也就是不会再去查找`node_modules/@types` 路径下 **类型定义** 了。 43 | 44 | 除此之外,也可以通过`compilerOptions.typesRoot` 来设置匹配的类型文件。 45 | 46 | ```json 47 | { 48 | "compilerOptions": { 49 | "types" : ["node", "lodash"] 50 | } 51 | } 52 | ``` 53 | 54 | **Note:** 这样将只会包含下面两个类型定义,**其它的** 则不会被包含进来。 55 | 56 | ```sh 57 | . 58 | ├── node_modules 59 | │   ├── @types 60 | │   ├── node 61 | │   ├── lodash 62 | ``` 63 | 如果配置为 `"types": []` 则不会包含任何包。 64 | ::: 65 | 66 | ## 使用 67 | 68 | ### 直接使用第三方声明文件 69 | 70 | 我们在大不多数的时候, 都可以通过 `npm` 安装 **社区或者第三方类库** 提供对应的声明模块即可。 71 | 72 | ```sh 73 | npm install --save-dev @types/pkg-name 74 | 75 | // or 76 | 77 | yarn add --save-dev @types/pkg-name 78 | ``` 79 | 80 | ::: tip 更多声明模块 81 | 82 | - 搜索 🔍 [here](https://www.typescriptlang.org/dt/search/) 83 | 84 | - 发布声明文件 🖥 [here](http://definitelytyped.org/) 85 | 86 | - 查看 👁👁 [here](https://github.com/DefinitelyTyped/DefinitelyTyped) 87 | 88 | 89 | ::: 90 | 91 | ### 自定义声明文件 92 | 93 | 当然, 社区不是万能的, 有时候, 有些声明文件需要我们自己自定义, 那我们将如何书写呢?👇👇👇 94 | 95 | 在不同的场景下, 声明文件的内容和使用方式会有所区别。 96 | 97 | #### 全局变量 98 | 99 | `declare global` 扩展全局变量 100 | 101 | ```ts 102 | // xxx.d.ts 103 | declare global { 104 | // ... 105 | } 106 | ``` 107 | 108 | `declare (var | let | const)` 声明全局变量 109 | 110 | ```ts 111 | // JQuery.d.ts 112 | declare var JQuery: (selector: string) => any; 113 | declare let JQuery: (selector: string) => any; 114 | declare const JQuery: (selector: string) => any; 115 | ``` 116 | 117 | `declare function` 声明全局方法, 在函数类型的声明语句中, 函数重载也是支持的 118 | 119 | ```ts 120 | // xxx.d.ts 121 | declare function moduleLib(options: Options): void; 122 | declare function moduleLib(callback: () => void): void; 123 | ``` 124 | 125 | `declare class` 声明全局类 126 | 127 | ```ts 128 | // xxx.d.ts 129 | declare class Person { 130 | name: string; 131 | constructor(name: string); 132 | getName(): string; 133 | } 134 | ``` 135 | 136 | `declare enum` 声明全局枚举类型 137 | 138 | ```ts 139 | // xxx.d.ts 140 | declare enum Days { 141 | Sun, 142 | Mon, 143 | Tue, 144 | Wed, 145 | Thu, 146 | Fri, 147 | Sat, 148 | } 149 | ``` 150 | 151 | ::: warning 152 | 153 | `declare enum`, `declare class` , `declare enum` 语句**只能用来定义类型**, 不能用来定义具体的实现, 也不是具体的值。 154 | 155 | ::: 156 | 157 | `interface` 和 `type` 声明全局类型, 如果你需要将一下类型定义暴露出来, 可以使用 `interface`或者 `type`。 158 | 159 | 为了**防止命名冲突**, 暴露在最外层的 `interface` 或 `type` 会作为全局类型作用于整个项目中, 我们应该尽可能的减少全局变量或全局类型的数量。 160 | 161 | ```ts 162 | // xxx.d.ts 163 | export interface Day { 164 | format: (value: Date) => string; 165 | } 166 | 167 | export type Time = Day | null; 168 | ``` 169 | 170 | `declare namespace` 声明 (含有子属性的) 全局对象 171 | 172 | 随着 `ES6` 的广泛应用, 现在已经**不建议再使用** `ts` 中的 `namespace`, 而推荐使用 `ES6` 的模块化, 例如 `import foo from 'foo'`。 173 | 174 | ```ts 175 | // xxx.d.ts 176 | export type Method = 'GET' | 'POST' | 'DELETE' | 'OPTIONS'; 177 | 178 | export interface Options { 179 | method: Method; 180 | [key: string]?: any; 181 | } 182 | 183 | declare namespace $ { 184 | const version: number | string; 185 | function ajax(url: string, options?: Options): void; 186 | // 嵌套命名空间 187 | namespace get { 188 | function getSomething(id: string): any; 189 | // etc... 190 | } 191 | } 192 | ``` 193 | 194 | #### `ES6` 模块 195 | 196 | 符合 `ES6` 模块 `(module)` 导入导出规范 197 | 198 | `export` 导出变量 199 | 200 | ```ts 201 | // xxx.d.ts 202 | export const name: string; 203 | ``` 204 | 205 | `export namespace` 导出 (含有子属性的) 对象 206 | 207 | ```ts 208 | // xxx.d.ts 209 | export declare namespace $ { 210 | const version: number | string; 211 | function ajax(url: string, options?: Options): void; 212 | // 嵌套命名空间 213 | namespace get { 214 | function getSomething(id: string): any; 215 | // etc... 216 | } 217 | } 218 | ``` 219 | 220 | `export default ES6` 默认导出 221 | 222 | ```ts 223 | // xxx.d.ts 224 | export default function getRandomColor(): string; 225 | ``` 226 | 227 | ::: warning 228 | 229 | 只有 `function`、`class` 和 `interface` 可以直接默认导出, 其他的变量需要先定义出来, 再默认导出 230 | 231 | ::: 232 | 233 | `export = commonjs` 导出模块 234 | 235 | ```ts 236 | // xxx.d.ts 237 | // 整体导出 238 | module.exports = foo; 239 | // 单个导出 240 | exports.bar = bar; 241 | ``` 242 | 243 | `export as namespace UMD` 库声明全局变量 244 | 245 | 一般使用 `export as namespace` 时, 都是先有了 npm 包的声明文件, 再基于它添加一条 `export as namespace` 语句, 即可将声明好的一个变量声明为全局变量。 246 | 247 | ```ts 248 | // xxx.d.ts 249 | export as namespace moment; 250 | declare namespace moment { 251 | export function valueOf(): number; 252 | } 253 | ``` 254 | 255 | `declare module` 扩展模块 256 | 257 | ```ts 258 | // xxx.d.ts 259 | // 导入 moment 260 | declare module 'moment' { 261 | export function valueOf(): number; 262 | } 263 | 264 | // 导入 lodash 265 | declare module 'lodash' { 266 | export function isEmpty(params: any): boolean; 267 | } 268 | 269 | // 导入 png 图片 270 | declare module '*.png' { 271 | const value: string; 272 | export = value; 273 | } 274 | ``` 275 | 276 | #### 声明合并 277 | 278 | - **函数** 合并(**重载**) 279 | 280 | ```ts 281 | function getFullName(x: function): string; 282 | function getFullName(x: string): string; 283 | function getFullName(x: string | function): string { 284 | if (typeof x === 'function') { 285 | return x(); 286 | } else { 287 | return x; 288 | } 289 | } 290 | ``` 291 | 292 | - **接口 & 类** 合并 293 | 294 | ```ts 295 | interface Profile { 296 | name: string; 297 | getAge(): number; 298 | } 299 | 300 | interface Profile { 301 | age: number | string; 302 | getAge(): string; 303 | } 304 | 305 | // => 306 | interface Profile { 307 | // 属性必须唯一 308 | name: string; 309 | age: number | string; 310 | // 这里和函数合并保持一致, 因为函数可以重载 311 | getAge(): number; 312 | getAge(): string; 313 | } 314 | ``` 315 | 316 | :::warning 317 | 318 | 接口合并的**属性的类型必须是唯一的**。 319 | 320 | ::: 321 | 322 | #### 使用依赖 323 | 324 | 以下情况可以通过使用 **/// 三斜线指令** 来解决。 325 | 326 | - 依赖全局库 327 | - 依赖模块 328 | - 依赖`UMD`库 329 | - 全局库 330 | - 一个模块或`UMD`库 331 | 332 | 随着 `ES6` 的广泛应用, 现在已经不建议再使用 `ts` 中的三斜线指令来声明模块之间的依赖关系了。 333 | 334 | ```ts 335 | // xxx.d.ts 336 | /// 337 | ``` 338 | 339 | ::: warning 340 | 341 | *不要*使用`/// 需要注意的是, 在 `TypeScript 1.5` 中, 命名法发生了变化。内部模块 `(Internal modules)` 现在是 _namespaces_。外部模块 `(External modules)` 现在只是简单的 _modules_。_内部模块_ 是没有引号的模块 413 | 414 | [更多信息可以到 Github issue#13774](https://github.com/Microsoft/TypeScript/issues/13774) 415 | 416 | ## 快来耍耍啊 417 | 418 | ### 🌰🌰 419 | 420 | 421 | 422 | ``` 423 | // template 424 | ``` 425 | 426 | ### 游乐场 427 | 428 |
429 | 430 | 433 | 434 | ### 参考答案 435 | 436 | ```ts 437 | // answer 438 | ``` 439 | 440 | ## 参考资料 441 | 442 | [handbook: namespaces](https://www.typescriptlang.org/docs/handbook/namespaces.html) 443 | 444 | [handbook: Namespaces and Modules](https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html) 445 | 446 | [handbook: declaration-files](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html) 447 | 448 | [How do I use namespaces with TypeScript external modules?](https://stackoverflow.com/questions/30357634/how-do-i-use-namespaces-with-typescript-external-modules) 449 | 450 | [Validators in a single file](https://www.typescriptlang.org/docs/handbook/namespaces.html#validators-in-a-single-file) 451 | 452 | [Module vs Namespace - Import vs Require Typescript](https://stackoverflow.com/questions/38582352/module-vs-namespace-import-vs-require-typescript) 453 | 454 | [Is typescript Namespace feature deprecated?](https://michelenasti.com/2019/01/23/is-typescript-namespace-feature-deprecated.html) 455 | 456 | [Module vs Namespace - Import vs Require Typescript](https://stackoverflow.com/questions/38582352/module-vs-namespace-import-vs-require-typescript) 457 | 458 | [如何在 TypeScript 外部模块中使用命名空间?](https://stackoverflow.com/questions/30357634/how-do-i-use-namespaces-with-typescript-external-modules) 459 | 460 | [声明文件](https://ts.xcatliu.com/basics/declaration-files.html) 461 | -------------------------------------------------------------------------------- /docs/zh/decorators/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | **装饰器**是一种特殊类型的声明, 它能够被附加到[类声明](http://www.tslang.cn/docs/handbook/decorators.html#class-decorators), [方法](http://www.tslang.cn/docs/handbook/decorators.html#method-decorators), [访问符](http://www.tslang.cn/docs/handbook/decorators.html#accessor-decorators), [属性](http://www.tslang.cn/docs/handbook/decorators.html#property-decorators)或[参数](http://www.tslang.cn/docs/handbook/decorators.html#parameter-decorators)上。 装饰器使用 `@expression` 这种形式, `expression` 求值后必须为一个函数, 它会在运行时被调用, 被装饰的声明信息做为参数传入。 4 | 5 | 了解更多有关装饰器实现原理的知识 👉👉👉 [Javascript Decorator (装饰器) 实现原理及其使用](https://rain120.github.io/study-notes/#/notes/javascript/key-concept/decorator?id=javascript-decorator-装饰器-实现原理及其使用) 6 | 7 | ### 类型 & 优先级 8 | 9 | **优先级依次往下执行** 10 | 11 | 1. 参数装饰器 `(Parameter Decorators)` 12 | 13 | **参数装饰器**声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件`(.d.ts)`, 重载或其它外部上下文(比如 `declare`的类)里。 14 | 15 | 2. 方法装饰器 `(Method Decorators)` 16 | 17 | **方法装饰器**声明在一个方法的声明之前(紧靠着方法声明)。 它会被应用到方法的 *属性描述符*上, 可以用来监视, 修改或者替换方法定义。 方法装饰器不能用在声明文件`(.d.ts)`, 重载或者任何外部上下文(比如`declare`的类)中。 18 | 19 | 3. 访问器或属性装饰器 `(Accessor or Property Decorators)` 20 | 21 | **访问器装饰器**声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 *属性描述符*并且可以用来监视, 修改或替换一个访问器的定义。 访问器装饰器不能用在声明文件中`(.d.ts)`, 或者任何外部上下文(比如 `declare` 的类)里。 22 | 23 | **属性装饰器**声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中`(.d.ts)`, 或者任何外部上下文(比如 `declare` 的类)里。 24 | 25 | 1. 类属性 26 | 2. 构造函数参数列表 `(使用类构造函数装饰器时)` 27 | 28 | **Note:** 访问器 `get` `set` 29 | 30 | 4. 类装饰器 `(Class Decorators)` 31 | 32 | **类装饰器** 在类声明之前被声明 (紧靠着类声明)。 类装饰器应用于类构造函数, 可以**用来监视, 修改或替换类定义**。 类装饰器不能用在声明文件中( `.d.ts`), 也不能用在任何外部上下文中(比如`declare`的类)。 33 | 34 | ## 使用 35 | 36 | 若要启用实验性的装饰器特性, 你必须在命令行或`tsconfig.json`里启用`experimentalDecorators`编译器选项: 37 | 38 | **命令行**: 39 | 40 | ```shell 41 | tsc --target ES5 --experimentalDecorators 42 | ``` 43 | 44 | **tsconfig.json**: 45 | 46 | ```json 47 | { 48 | "compilerOptions": { 49 | "target": "ES5", 50 | "experimentalDecorators": true 51 | } 52 | } 53 | ``` 54 | 55 | ### 装饰器组合 56 | 57 | 多个装饰器可以同时应用声明到一个 [类声明](http://www.tslang.cn/docs/handbook/decorators.html#class-decorators), [方法](http://www.tslang.cn/docs/handbook/decorators.html#method-decorators), [访问符](http://www.tslang.cn/docs/handbook/decorators.html#accessor-decorators), [属性](http://www.tslang.cn/docs/handbook/decorators.html#property-decorators)或[参数](http://www.tslang.cn/docs/handbook/decorators.html#parameter-decorators)上。 58 | 59 | ```ts 60 | // 一行写法 61 | @f @g isHandsome() {} 62 | 63 | // 多行写法 ----> 个人喜欢这种写法 64 | @f 65 | @g 66 | isHandsome() {} 67 | ``` 68 | 69 | 当复合 **f** 和 **g** 时, [复合](https://zh.wikipedia.org/wiki/%E5%A4%8D%E5%90%88%E5%87%BD%E6%95%B0) `(把一个函数的输出作为另一个函数的输入)`的结果 $(f ∘ g)(x) = f(g(x))$。 70 | 71 | **Note:** 当在一个地方使用**多个装饰器**时 72 | 73 | - **由上至下**依次对装饰器表达式求值 74 | - 执行顺序是 **从下往上** 依次执行。 75 | 76 | ```ts 77 | function first() { 78 | console.log('first: evaluated'); 79 | return (target, propertyKey: string, descriptor: PropertyDescriptor) => { 80 | console.log('first: called'); 81 | }; 82 | } 83 | 84 | function second() { 85 | console.log('second: evaluated'); 86 | return (target, propertyKey: string, descriptor: PropertyDescriptor) => { 87 | console.log('second: called'); 88 | }; 89 | } 90 | 91 | class Example { 92 | @second 93 | @first 94 | method() {} 95 | } 96 | 97 | // 'second: evaluated' 98 | // 'first: evaluated' 99 | // 'first: called' 100 | // 'second: called' 101 | ``` 102 | 103 | ### 参数装饰器 104 | 105 | 参数装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数: 106 | 107 | 1. 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。 108 | 2. 成员的名字。 109 | 3. 参数在函数参数列表中的索引。 110 | 111 | ::: warning 112 | 注意: 参数装饰器只能用来监视一个方法的参数是否被传入。 113 | ::: 114 | 115 | 参数装饰器的返回值会被忽略。 116 | 117 | ```ts 118 | function parameterDecorator(value: boolean) { 119 | return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { 120 | console.log('parameterDecorator'); 121 | }; 122 | } 123 | 124 | class Boy { 125 | name: string; 126 | age: number; 127 | handsome: boolean; 128 | 129 | constructor(name, handsome) { 130 | this.name = name; 131 | this.handsome = handsome; 132 | } 133 | 134 | setAge(@parameterDecorator('parameterDecorator') age: number) { 135 | this.age = age; 136 | } 137 | } 138 | ``` 139 | 140 | ### 方法装饰器 141 | 142 | 方法装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数: 143 | 144 | 1. 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。 145 | 2. 成员的名字。 146 | 3. 成员的 **属性描述符**。 147 | 148 | ::: warning 149 | 如果代码输出目标版本小于`ES5`, *属性描述符*将会是`undefined`。 150 | ::: 151 | 152 | 如果方法装饰器返回一个值, 它会被用作方法的*属性描述符*。 153 | 154 | ::: warning 155 | 如果代码输出目标版本小于`ES5`返回值会被忽略。 156 | ::: 157 | 158 | ```ts 159 | function methodDecorator(value: boolean) { 160 | return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { 161 | target[propertyKey] = value; 162 | }; 163 | } 164 | 165 | class Boy { 166 | name: string; 167 | handsome: boolean; 168 | 169 | @propertyDecorator('属性装饰器', Boy) 170 | public age: number = 18; 171 | 172 | constructor(name, handsome) { 173 | this.name = name; 174 | this.handsome = handsome; 175 | } 176 | 177 | @methodDecorator(true) 178 | isHandsome() { 179 | return this.handsome; 180 | } 181 | } 182 | ``` 183 | 184 | ### 访问器或属性装饰器 185 | 186 | #### 属性装饰器 187 | 188 | 属性装饰器表达式会在运行时当作函数被调用, 传入下列 `2` 个参数: 189 | 190 | 1. 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。 191 | 2. 成员的名字。 192 | 193 | ::: warning 194 | **属性描述符** 不会做为参数传入属性装饰器, 这与`TypeScript`是如何初始化属性装饰器的有关。 因为目前没有办法在定义一个原型对象的成员时描述一个实例属性, 并且没办法监视或修改一个属性的初始化方法。返回值也会被忽略。因此, 属性描述符只能用来监视类中是否声明了某个名字的属性。 195 | ::: 196 | 197 | ```ts 198 | function propertyDecorator(value: string, theClass) { 199 | console.log(value); 200 | return function(prototype, key) { 201 | console.log('AccessDecorator'); 202 | }; 203 | } 204 | 205 | class Boy { 206 | name: string; 207 | handsome: boolean; 208 | 209 | @propertyDecorator('属性装饰器', Boy) 210 | public age: number = 18; 211 | 212 | constructor(name, handsome) { 213 | this.name = name; 214 | this.handsome = handsome; 215 | } 216 | 217 | @AccessDecorator('访问器装饰器') 218 | get isHandsome() { 219 | return this.handsome; 220 | } 221 | } 222 | ``` 223 | 224 | #### 访问器装饰器 225 | 226 | ::: warning 227 | `TypeScript`不允许同时装饰一个成员的`get` 和 `set` 访问器。取而代之的是, 一个成员的所有装饰的必须应用在文档顺序的第一个访问器上。这是因为, 在装饰器应用于一个**属性描述符**时, 它联合了 `get` 和 `set` 访问器, 而不是分开声明的。 228 | ::: 229 | 230 | 访问器装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数: 231 | 232 | 1. 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。 233 | 2. 成员的名字。 234 | 3. 成员的**属性描述符**。 235 | 236 | ::: warning 237 | 如果代码输出目标版本小于 `ES5`, **Property Descriptor** 将会是 `undefined`。 238 | ::: 239 | 240 | 如果访问器装饰器返回一个值, 它会被用作方法的*属性描述符*。 241 | 242 | ::: warning 243 | 如果代码输出目标版本小于 `ES5` 返回值会被忽略。 244 | ::: 245 | 246 | ```ts 247 | function AccessDecorator(value: string) { 248 | console.log(value); 249 | return function() { 250 | console.log('AccessDecorator'); 251 | }; 252 | } 253 | 254 | class Boy { 255 | name: string; 256 | handsome: boolean; 257 | 258 | constructor(name, handsome) { 259 | this.name = name; 260 | this.handsome = handsome; 261 | } 262 | 263 | @AccessDecorator('访问器装饰器') 264 | get isHandsome() { 265 | return this.handsome; 266 | } 267 | } 268 | ``` 269 | 270 | ### 类装饰器 271 | 272 | 类装饰器表达式会在运行时当作函数被调用, **类的构造函数作为其唯一的参数**。 273 | 274 | 如果类装饰器返回一个值, 它会使用提供的构造函数来替换类的声明。 275 | 276 | ::: warning 277 | 如果你要返回一个新的构造函数, 你必须注意处理好原来的原型链。在运行时的装饰器调用逻辑中 **不会** 为你做这些。 278 | ::: 279 | 280 | ```ts 281 | function sealed(constructor: Function) { 282 | Object.seal(constructor); 283 | Object.seal(constructor.prototype); 284 | } 285 | 286 | @sealed 287 | class Greeter { 288 | greeting: string; 289 | constructor(message: string) { 290 | this.greeting = message; 291 | } 292 | greet() { 293 | return 'Hello, ' + this.greeting; 294 | } 295 | } 296 | ``` 297 | 298 | ## 快来耍耍啊 299 | 300 | ### 🌰🌰 301 | 302 | 303 | 304 | ``` 305 | // template 306 | ``` 307 | 308 | ### 游乐场 309 | 310 |
311 | 312 | 315 | 316 | ### 参考答案 317 | 318 | ```ts 319 | // answer 320 | ``` 321 | 322 | ## 参考资料 323 | 324 | [handbook - decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) 325 | 326 | [使用 TypeScript 装饰器装饰你的代码](https://codeburst.io/decorate-your-code-with-typescript-decorators-5be4a4ffecb4) 327 | -------------------------------------------------------------------------------- /docs/zh/faqs/README.md: -------------------------------------------------------------------------------- 1 | ## FAQs 列表 2 | 3 | [interface 和 type 有什么异同点?](./interface-vs-type.md) 4 | 5 | ## 参考资料 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/zh/faqs/interface-vs-type.md: -------------------------------------------------------------------------------- 1 | ## interface 和 type 有什么异同点? 2 | 3 | [interface-declarations](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#71-interface-declarations) 4 | 5 | > An interface cannot declare a property with the same name as an inherited private or protected property. 6 | 7 | [type-aliases](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#310-type-aliases) 8 | 9 | > An interface can have multiple merged declarations, but a type alias for an object type literal cannot 10 | 11 | ### 相同点 12 | 13 | - 描述一个对象或者函数 14 | 15 | ```typescript 16 | export interface IUser { 17 | id: string | number; 18 | name: string; 19 | age?: number; 20 | } 21 | 22 | export interface IGetUser { 23 | (id: string | number): IUser; 24 | } 25 | 26 | export type User = { 27 | name: string; 28 | age?: number; 29 | } 30 | 31 | export type GetUser = (id: string | number): User; 32 | 33 | ``` 34 | 35 | - 允许类型拓展(`type`不能使用`extends`关键字) 36 | 37 | ```typescript 38 | interface FE extends IUser { 39 | type: string; 40 | } 41 | 42 | type FE = { type: string; } & User; 43 | 44 | ``` 45 | 46 | ### 不同点 47 | 48 | - `type` 可以声明基本类型别名, 联合类型, 元组等类型 49 | 50 | - `interface` 能够声明合并 51 | 52 | ```typescript 53 | interface IUser { 54 | id: string | number; 55 | } 56 | 57 | interface IUser { 58 | name: string; 59 | age?: number; 60 | } 61 | 62 | // => 63 | interface IUser { 64 | id: string | number; 65 | name: string; 66 | age?: number; 67 | } 68 | ``` 69 | 70 | ## 参考资料 71 | 72 | [handbook - type-inference](https://www.typescriptlang.org/docs/handbook/type-inference.html) 73 | 74 | [interfaces](https://basarat.gitbook.io/typescript/type-system/interfaces) 75 | 76 | [typescript-interfaces-vs-types](https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types) 77 | 78 | [handbook - differences-between-type-aliases-and-interfaces](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces) 79 | -------------------------------------------------------------------------------- /docs/zh/function/README.md: -------------------------------------------------------------------------------- 1 | ## 函数 2 | 3 | :::theorem 函数 4 | 函数是 `JavaScript` 中的基本组件之一。 一个函数是 `JavaScript` 过程 ---- 一组执行任务或计算值的语句。要使用一个函数, 你必须将其定义在你希望调用它的作用域内。 5 | ::: 6 | 7 | ### TypeScript VS JavaScript 8 | 9 | | TypeScript | JavaScript | 10 | | -------------- | ------------------------------------------------------------ | 11 | | 含有类型 | 无类型 | 12 | | 箭头函数 | 箭头函数 `(ES2015)` | 13 | | 函数类型 | 无函数类型 | 14 | | 必填和可选参数 | 所有参数都是可选的, 如果传入了参数, 该参数, 后面的参数都是可选的 | 15 | | 默认参数 | 默认参数 | 16 | | 剩余参数 | 剩余参数 | 17 | | 函数重载 | 无函数重载 | 18 | 19 | ### 函数的组成 20 | 21 | - 函数的名称 22 | 23 | - 函数参数列表, 包围在括号中并由逗号分隔。 24 | 25 | - 定义函数的 `JavaScript` 语句, 用大括号 `{}` 括起来 26 | 27 | - 函数的返回值 28 | 29 | ## 声明(定义)函数 30 | 31 | `JavaScript` 中声明函数有👇👇👇方式, 在 `Typescript` 中也是一样的。 32 | 33 | ### 函数声明 (Function Declaration) 34 | 35 | ```ts 36 | function getFullName(name: string): string { 37 | return `Rainy ${name}`; 38 | } 39 | ``` 40 | 41 | ### 函数表达式 (Function Expression) 42 | 43 | 函数也可以由函数表达式创建, 这样的函数可以是 **匿名的**。 44 | 45 | ```ts 46 | const getFullName: (name: string) => string = function(name: string): string { 47 | return `Rainy ${name}`; 48 | } 49 | ``` 50 | 当然你也可以使用箭头函数 51 | 52 | ```ts 53 | const getFullName: (name: string) => string = (name: string): string => { 54 | return `Rainy ${name}`; 55 | } 56 | ``` 57 | 58 | **Note:** 59 | 60 | - 在 `TypeScript` 的类型定义中, `=>` 用来表示函数的定义的 **输出类型** 。 61 | - `ES6` 允许使用 **箭头** (`=>`) 定义函数, 更多详见 [ES6 箭头函数](http://es6.ruanyifeng.com/#docs/function#%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0) 62 | 63 | ## 声明函数定义方式 64 | 65 | ### 匿名定义 66 | 67 | ```ts {1} 68 | const getFullName: (name: string) => string 69 | = function(name: string): string { 70 | return `Rainy ${name}`; 71 | } 72 | ``` 73 | 74 | 75 | 如果你会使用 `type`, `interface` 了, 你也可以这样 76 | 77 | ### type 定义 78 | 79 | ```ts {1} 80 | type GetFullName = (name: string) => string; 81 | ``` 82 | 83 | 还可以这样 84 | 85 | ### 接口 (Interface) 定义 86 | 87 | ```ts {2} 88 | interface GetFullName { 89 | (name: string) => string; 90 | } 91 | ``` 92 | 93 | ## 函数参数 94 | 95 | ### 可选参数 96 | 97 | `JavaScript` 每个参数都是可选的, 可传可不传。 没传参的时候, 它的值就是 `undefined` , `TypeScript` 里的每个函数参数都是必须的, 它可以通过使用 `?`实现可选参数的功能。 98 | 99 | ```ts 100 | function getInfo( 101 | name: string, 102 | gender: number | string, 103 | age?: number | string 104 | ): { 105 | return `I'm ${name}${age ? `${, I'm ${age}}` : ''}, I'm a ${gender}.` 106 | } 107 | ``` 108 | 109 | **Note:** 可选参数 **必须要** 放在 必选参数 的 **后面**, 不然会导致编译错误。 110 | 111 | ### 默认参数 112 | 113 | 在 `TypeScript` 里, 我们也可以为参数提供一个默认值当用户没有传递这个参数或传递的值是`undefined`时。 它们叫做有默认初始化值的参数。 114 | 115 | ```ts 116 | function getInfo( 117 | name: string, 118 | gender: number | string = 'boy', 119 | age?: number | string 120 | ): { 121 | return `I'm ${name}${age ? `${, I'm ${age}}` : ''}, I'm a ${gender}.` 122 | } 123 | ``` 124 | 125 | ### 剩余参数 126 | 127 | 剩余参数会被当做个数不限的可选参数。 可以一个都没有, 同样也可以有任意个。 编译器创建参数数组, 可以通过扩展运算符 `(spread)` 来设置参数名。 128 | 129 | [扩展运算符(spread)](https://es6.ruanyifeng.com/?search=扩展&x=8&y=10#docs/array#扩展运算符) 是 三个 (`...`), 它好比 `rest` 参数的逆运算, 将一个数组转为用逗号分隔的参数序列。 130 | 131 | ```ts 132 | function buildName(firstName: string, ...restOfName: string[]) { 133 | return firstName + " " + restOfName.join(" "); 134 | } 135 | 136 | let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie"); 137 | ``` 138 | 139 | ## 函数重载 140 | 141 | [函数重载](https://zh.wikipedia.org/wiki/函数重载) 是定义了多个相同名字的方法, 而输入输出类型或个数不同的子程序的一项特性。 142 | 143 | 可惜 `JavaScript` 不支持函数重载, 但是 `Typescript` 支持。 144 | 145 | ```ts 146 | function add(a: number, b: number): number; 147 | function add(a: string, b: string): string; 148 | function add(a: string, b: number): string; 149 | function add(a: number, b: string): string; 150 | function add(a: Combinable, b: Combinable) { 151 | if (typeof a === "string" || typeof b === "string") { 152 | return a.toString() + b.toString(); 153 | } 154 | return a + b; 155 | } 156 | ``` 157 | 158 | **Note:** `TypeScript` 会优先从最前面的函数定义开始匹配, 所以多个函数定义如果有包含关系, 需要优先把精确的定义写在前面。 159 | 160 | ## 快来耍耍啊 161 | 162 | ### 🌰🌰 163 | 164 | 165 | 166 | ``` 167 | // template 168 | ``` 169 | 170 | ### 游乐场 171 | 172 |
173 | 174 | 177 | 178 | ### 参考答案 179 | 180 | ```ts 181 | // answer 182 | ``` 183 | 184 | ## 参考资料 185 | 186 | [handbook - functions](https://www.typescriptlang.org/docs/handbook/functions.html) 187 | 188 | [functions](https://basarat.gitbook.io/typescript/type-system/functions) 189 | 190 | [MDN - Functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions) 191 | -------------------------------------------------------------------------------- /docs/zh/generics/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | **泛型**就是指定一个表示类型的变量, 用它来代替某个实际的类型用于编程, 而后再通过实际运行或推导的类型来对其进行替换, 以达到一段使用泛型程序可以实际适应不同类型的目的。**「泛型就是不预先确定的数据类型, 具体的类型在使用的时候再确定的一种类型约束规范」**。 4 | 5 | 泛型的好处: 6 | 7 | - 函数和类可以轻松的支持多种类型, 增强程序的扩展性 8 | - 不必写多条函数重载, 冗长的联合类型声明, 增强代码的可读性 9 | - 灵活控制类型之间的约束 10 | 11 | ## 泛型约束 12 | 13 | 有时候我们希望限制每个类型变量**接受的类型数量**, 这就是**泛型约束**。 14 | 15 | 我们可以使用 `,` 号来分隔多种约束类型, 比如: ``。 16 | 17 | ## 常见的一些泛型变量含义 18 | 19 | - T (Type): 表示一个 `TypeScript` 类型 20 | 21 | - K (Key): 表示对象中的键类型 22 | 23 | - V (Value): 表示对象中的值类型 24 | 25 | - E (Element): 表示元素类型 26 | 27 | 28 | ## 使用 29 | 30 | ```ts 31 | function validator(arg: T): T { 32 | return arg; 33 | } 34 | ``` 35 | 36 | ## 快来耍耍啊 37 | 38 | ### 🌰🌰 39 | 40 | 41 | 42 | ``` 43 | // template 44 | ``` 45 | 46 | ### 游乐场 47 | 48 |
49 | 50 | 53 | 54 | ### 参考答案 55 | 56 | ```ts 57 | // answer 58 | ``` 59 | 60 | ## 参考资料 61 | 62 | [handbook - generics](https://www.typescriptlang.org/docs/handbook/generics.html) 63 | 64 | [generics](https://basarat.gitbook.io/typescript/type-system/generics) 65 | 66 | [TypeScript Spec](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md) 67 | 68 | [TypeScript进阶 之 重难点梳理](https://mp.weixin.qq.com/s/xWaVvh5lXG8Nb_U6bmJamw) 69 | 70 | [一文读懂 TypeScript 泛型及应用( 7.8K字)](https://juejin.im/post/6844904184894980104) 71 | -------------------------------------------------------------------------------- /docs/zh/guide/README.md: -------------------------------------------------------------------------------- 1 |

2 | Typescript Guide 3 | 4 |

5 | 6 |
7 | 8 | [![GitHub watchers](https://img.shields.io/github/watchers/rain120/typescript-guide?style=social)](https://github.com/Rain120/typescript-guide/watchers) 9 | [![STAR](https://img.shields.io/github/stars/rain120/typescript-guide?style=social)](https://github.com/Rain120/typescript-guide/stargazers) [![FORK](https://img.shields.io/github/forks/rain120/typescript-guide?style=social)](https://github.com/Rain120/typescript-guide/network/members) 10 | 11 | [![ISSUES](https://img.shields.io/github/issues/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/issues) [![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/pulls) [![COMMIT](https://img.shields.io/github/last-commit/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/commits/master) 12 | 13 | ![LANGUAGES](https://img.shields.io/github/languages/top/rain120/typescript-guide?style=flat-square) 14 | [![VERSION](https://img.shields.io/github/package-json/v/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/blob/master/package.json) [![LICENSE](https://img.shields.io/github/license/rain120/typescript-guide?style=flat-square)](https://github.com/Rain120/typescript-guide/blob/master/LICENSE) 15 | 16 |
17 | 18 | ## 😚 Welcome 19 | 20 | Welcome to the Typescript Guide. 21 | 22 | ## 🎮 TL;DR 23 | 24 | 25 | [Document](https://rain120.github.io/typescript-guide/) 26 | 27 | ## ✍ Why am I doing this? 28 | 29 | Write documents for how to easily use typescript. 30 | 31 | ## 🍾 Objective Key Result (OKR) 32 | 33 | ### Objective 34 | 35 | Learning all about the base of Typescript, and practice it 36 | 37 | ### Key Result 38 | 39 | - [x] [Compile Config](../compile-config/README.md) 40 | 41 | - [x] [Basic](../basic/README.md) 42 | 43 | - [x] [Type Assertion](../type-assertion/README.md) 44 | 45 | - [x] [Advanced Types](../advanced-types/README.md) 46 | 47 | - [x] [Intersection Types](../advanced-types/intersection-types/README.md) 48 | 49 | - [x] [Union Types](../advanced-types/union-types/README.md) 50 | 51 | - [x] [Type Guard](../advanced-types/type-guard/README.md) 52 | 53 | - [x] [Nullable](../advanced-types/nullable/README.md) 54 | 55 | - [x] [Array](../array/README.md) 56 | 57 | - [x] [Function](../function/README.md) 58 | 59 | - [ ] [Decorators](../decorators/README.md) 60 | 61 | - [ ] [Class](../class/README.md) 62 | 63 | - [x] [内置对象](../built-in-objects/README.md) 64 | 65 | - [ ] [Interface](../interface/README.md) 66 | 67 | - [ ] [Generics](../generics/README.md) 68 | 69 | - [x] [Operator](../operator/README.md) 70 | 71 | - [x] [Keyword](../keyword/README.md) 72 | 73 | - [x] [is](../keyword/is/README.md) 74 | 75 | - [x] [keyof](../keyword/keyof/README.md) 76 | 77 | - [x] [in](../keyword/in/README.md) 78 | 79 | - [x] [typeof](../keyword/typeof/README.md) 80 | 81 | - [x] [instanceof](../keyword/instanceof/README.md) 82 | 83 | - [x] [extends](../keyword/extends/README.md) 84 | 85 | - [x] [implements](../keyword/implements/README.md) 86 | 87 | - [ ] [infer](../keyword/infer/README.md) 88 | 89 | - [x] [Utility Types](./docs/zh/utility-types/README.md) 90 | 91 | - [ ] [Tips](../tips/README.md) 92 | 93 | - [ ] [FAQs](../faqs/README.md) 94 | 95 | 96 | ⌨️ To be Continue... 97 | 98 | 101 | 102 | ## 🤝 Contributing 103 | 104 | ![PR](https://img.shields.io/badge/PRs-Welcome-orange?style=flat-square&logo=appveyor) 105 | 106 | We welcome all contributions. You can submit any ideas as [pull requests](https://github.com/Rain120/typescript-guide/pulls) or as a GitHub [issue](https://github.com/Rain120/typescript-guide/issues). 107 | 108 | [How to write Docs](how-to-write-docs.md) 109 | 110 | ## 🔗 Links 111 | 112 | 113 | 114 | [Online Docs](https://rain120.github.io/typescript-guide/) 115 | 116 | ## 👨‍🏭 Author 117 | 118 | > Front-End development engineer, technology stack: React + Typescript + Mobx, also used Vue + Vuex for a while 119 | 120 | - [Github](https://github.com/Rain120) 121 | - [知乎](https://www.zhihu.com/people/yan-yang-nian-hua-120/activities) 122 | - [掘金](https://juejin.im/user/57c616496be3ff00584f54db) 123 | 124 | ## 📝 License 125 | 126 | [MIT](https://github.com/Rain120/typescript-guide/blob/master/LICENSE) 127 | 128 | Copyright © 2020-present [Rain120](https://github.com/Rain120). 129 | 130 | ## ☕ Coffee or Tea 131 | 132 | ![wechat-zhifubao-pay.png](~@images/wechat-zhifubao-pay.png) 133 | -------------------------------------------------------------------------------- /docs/zh/interface/README.md: -------------------------------------------------------------------------------- 1 | ## Previously 2 | 3 | 接下来我们来了解一下 [面向对象编程 `OOP(object oriented programming)`](https://en.wikipedia.org/wiki/Object-oriented_programming)中一个概念: 接口。 4 | 5 | 接口是一种用来定义程序的协议,它描述可属于任何类或结构的一组相关行为。 6 | 7 | 接口的目的是指明相关或者不相关类的多个对象的共同行为,跟抽象类很相似,可以说接口是更加抽象的抽象类。 8 | 9 | 接口体现了程序设计的多态和高内聚低耦合的设计思想。 10 | 11 | [Java 中的接口有什么作用? - 知乎](https://www.zhihu.com/question/20111251) 12 | 13 | ## 定义 14 | 15 | **接口** 是 `Typescript` 中一个很重要的概念, 主要是对类型的行为进行抽象, 描述, 并进行类型检查 16 | 17 | ## 使用 18 | 19 | ```ts 20 | interface Profile { 21 | name: string; 22 | age?: string | number; 23 | gender: 'MALE' | 'FEMALE'; 24 | } 25 | ``` 26 | 27 | ## FAQs 28 | 29 | [interface 和 type 有什么异同点?](../faqs/interface-vs-type.md) 30 | ## 快来耍耍啊 31 | 32 | ### 🌰🌰 33 | 34 | 35 | 36 | ``` 37 | // template 38 | ``` 39 | 40 | ### 游乐场 41 | 42 |
43 | 44 | 47 | 48 | ### 参考答案 49 | 50 | ```ts 51 | // answer 52 | ``` 53 | 54 | ## 参考资料 55 | 56 | [interfaces](https://basarat.gitbook.io/typescript/type-system/interfaces) 57 | 58 | -------------------------------------------------------------------------------- /docs/zh/keyword/README.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | 3 | :::theorem Typescript 关键字 4 | Typescript 常用关键字解析和使用。 5 | ::: 6 | 7 | [TypeScript as 关键字](./as/README.md) 8 | 9 | [TypeScript is 关键字](./is/README.md) 10 | 11 | [TypeScript keyof 关键字](./keyof/README.md) 12 | 13 | [TypeScript in 关键字](./in/README.md) 14 | 15 | [TypeScript typeof 关键字](./typeof/README.md) 16 | 17 | [TypeScript instanceof 关键字](./instanceof/README.md) 18 | 19 | [TypeScript entends 关键字](./entends/README.md) 20 | 21 | [TypeScript implements 关键字](./implements/README.md) 22 | 23 | [TypeScript infer 关键字](./infer/README.md) 24 | 25 | ## 参考资料 26 | 27 | [Typescript Handbook](https://www.typescriptlang.org/docs/handbook/basic-types.html) 28 | -------------------------------------------------------------------------------- /docs/zh/keyword/as/README.md: -------------------------------------------------------------------------------- 1 | ## Previously 2 | 3 | ```js 4 | const digit = 100000; 5 | // 怎么获取 digit 的长度呢? 6 | digit.length; 7 | ``` 8 | 9 | ## 定义 10 | 11 | :::theorem as 12 | 用来手动指定一个值的类型([类型断言 或 类型保护](../../type-assertion/README.md))。换句话来说,就是你比编译器更了解这个变量的类型是什么。 13 | ::: 14 | 15 | ## 使用 16 | 17 | ```ts 18 | const someValue: any = "this is a string"; 19 | const strLength: number = (someValue as string).length; 20 | ``` 21 | 22 | ## 快来耍耍啊 23 | 24 | ### 🌰🌰 25 | 26 | 27 | 28 | ``` 29 | // template 30 | ``` 31 | 32 | ### 游乐场 33 | 34 |
35 | 36 | 39 | 40 | ### 参考答案 41 | 42 | ```ts 43 | // answer 44 | ``` 45 | 46 | ## 参考资料 47 | 48 | 49 | -------------------------------------------------------------------------------- /docs/zh/keyword/extends/README.md: -------------------------------------------------------------------------------- 1 | ## Previously 2 | 3 | ```js 4 | class Fruit { 5 | name: string; 6 | color: string; 7 | } 8 | 9 | class Apple extends Fruit { 10 | // bla bla 11 | } 12 | ``` 13 | 14 | `Class` 可以通过 `extends` 关键字实现继承,这比 `ES5` 的通过修改原型链实现继承,要清晰和方便很多。[More Info](https://es6.ruanyifeng.com/?search=extends&x=0&y=0#docs/class-extends) 15 | 16 | ## 定义 17 | 18 | :::theorem extends 19 | 可以用来继承一个类,也可以用来继承一个 `interface`,但还可以用来判断有条件类型,**接口支持多重继承,语法为逗号隔开**。 20 | :::right 21 | [TypeScript 2.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html) 22 | ::: 23 | 24 | ## 使用 25 | 26 | ### 条件类型 27 | 28 | [Typescript 2.8 新增](https://devblogs.microsoft.com/typescript/announcing-typescript-2-8-2/#conditional-types) `extends` 用来条件类型判断。 29 | 30 | :::tips 31 | 表示条件判断,如果前面的条件满足,则返回问号后的第一个参数,否则第二个。类似于js的三元运算。 32 | ::: 33 | 34 | ```ts 35 | T extends U ? X : Y 36 | ``` 37 | 38 | 上面的类型表示当 `T` 可分配给 `U` 时,类型为 `X`,否则为 `Y`。 39 | 40 | 原理是令 `T'` 和 `U'` 分别为 `T` 和 `U` 的实例,并将所有类型参数替换为 `any`,如果 `T'` 能赋值给 `U'`,则将有条件的类型解析成 `X`,否则为`Y`。 41 | 42 | ```ts 43 | // Remove types from T that are assignable to U ===> 差集 44 | type Diff = T extends U ? never : T; 45 | // Remove types from T that are not assignable to U ===> 交集 46 | type Filter = T extends U ? T : never; 47 | 48 | type T1 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; 49 | // ^ = type T1 = "b" | "d" 50 | type T2 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c" 51 | // ^ = type T2 = "a" | "c" 52 | type T3 = Diff void), Function>; // string | number 53 | // ^ = type T3 = string | number 54 | type T4 = Filter void), Function>; // () => void 55 | // ^ = type T4 = () => void 56 | ``` 57 | 58 | 当 `T` 是联合类型时, 59 | 60 | ```ts 61 | (T1 | T2) extends U ? X : Y 62 | 63 | // (T1 extends U | T2 extends U) ? X : Y 64 | ``` 65 | 66 | ### 继承 67 | 68 | 像类一样,接口可以互相扩展。 这使您可以将一个接口的成员复制到另一个接口中,从而在如何将接口分离为可重用组件方面提供了更大的灵活性。 69 | 70 | ```ts 71 | interface Shape { 72 | color: string; 73 | } 74 | 75 | interface Square extends Shape { 76 | sideLength: number; 77 | } 78 | 79 | let square = {} as Square; 80 | square.color = "blue"; 81 | square.sideLength = 10; 82 | ``` 83 | 84 | 一个接口可以扩展多个接口,从而创建所有接口的组合。 85 | 86 | ```ts 87 | interface Shape { 88 | color: string; 89 | } 90 | 91 | interface PenStroke { 92 | penWidth: number; 93 | } 94 | 95 | interface Square extends Shape, PenStroke { 96 | sideLength: number; 97 | } 98 | 99 | let square = {} as Square; 100 | square.color = "blue"; 101 | square.sideLength = 10; 102 | square.penWidth = 5.0; 103 | ``` 104 | 105 | ### 类继承 106 | 107 | ```ts 108 | interface Profile { 109 | name: string; 110 | age?: string | number; 111 | } 112 | 113 | class Person { 114 | name: string; 115 | age?: string | number; 116 | 117 | constructor(options: Profile) { 118 | this.name = options?.name; 119 | this.age = options?.age; 120 | } 121 | } 122 | 123 | class Boy extends Person { 124 | gender: string 125 | } 126 | ``` 127 | 128 | ## 快来耍耍啊 129 | 130 | ### 🌰🌰 131 | 132 | 133 | 134 | ``` 135 | // template 136 | ``` 137 | 138 | ### 游乐场 139 | 140 |
141 | 142 | 145 | 146 | ### 参考答案 147 | 148 | ```ts 149 | // answer 150 | ``` 151 | 152 | ## 参考资料 153 | 154 | [conditional-types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#conditional-types) 155 | 156 | [extending-interfaces](https://www.typescriptlang.org/docs/handbook/interfaces.html#extending-interfaces) 157 | 158 | [whats-the-difference-between-extends-and-implements-in-typescript](https://stackoverflow.com/questions/38834625/whats-the-difference-between-extends-and-implements-in-typescript) 159 | -------------------------------------------------------------------------------- /docs/zh/keyword/implements/README.md: -------------------------------------------------------------------------------- 1 | ## Previously 2 | 3 | 请先行了解 👉 [Interface](../../interface/README.md)。 4 | ## 定义 5 | 6 | :::theorem implements 7 | [implements (实现)](https://en.wikipedia.org/wiki/Implement) 是面向对象中的一个重要概念。它是要实现一个已经定义好的接口中的方法。 8 | ::: 9 | ## 使用 10 | 11 | ### 接口实现 12 | 13 | ```ts 14 | interface Shape { 15 | color: string; 16 | draw(): void; 17 | } 18 | class DrawShape implements Shape { 19 | color: string; 20 | 21 | constructor(color: string) { 22 | this.color = color; 23 | } 24 | 25 | draw() { 26 | console.log(`draw shape with ${this.color}`); 27 | } 28 | } 29 | ``` 30 | 31 | 一个类可以实现多个接口 32 | 33 | ```ts 34 | interface Shape { 35 | color: string; 36 | draw(): void; 37 | } 38 | 39 | interface Paint { 40 | paint(): void; 41 | } 42 | 43 | class DrawShape implements Shape, Paint { 44 | color: string; 45 | 46 | constructor(color: string) { 47 | this.color = color; 48 | } 49 | 50 | draw() { 51 | console.log(`draw shape with ${this.color}`); 52 | } 53 | 54 | paint() { 55 | console.log(`draw shape with ${this.color}`); 56 | } 57 | } 58 | ``` 59 | 60 | 61 | 62 | ## 快来耍耍啊 63 | 64 | ### 🌰🌰 65 | 66 | 67 | 68 | ``` 69 | // template 70 | ``` 71 | 72 | ### 游乐场 73 | 74 |
75 | 76 | 79 | 80 | ### 参考答案 81 | 82 | ```ts 83 | // answer 84 | ``` 85 | 86 | ## 参考资料 87 | 88 | [whats-the-difference-between-extends-and-implements-in-typescript](https://stackoverflow.com/questions/38834625/whats-the-difference-between-extends-and-implements-in-typescript) 89 | -------------------------------------------------------------------------------- /docs/zh/keyword/in/README.md: -------------------------------------------------------------------------------- 1 | ## Previously 2 | 3 | 如果指定的属性在指定的对象或其原型链中,则 `in` 运算符返回 `true`。 4 | 5 | ```js 6 | const car = { make: 'Honda', model: 'Accord', year: 1998 }; 7 | 8 | console.log('make' in car); 9 | // expected output: true 10 | 11 | delete car.make; 12 | if ('make' in car === false) { 13 | car.make = 'Suzuki'; 14 | } 15 | 16 | console.log(car.make); 17 | // expected output: "Suzuki" 18 | 19 | ``` 20 | 21 | ## 定义 22 | 23 | :::theorem in 24 | 用来遍历枚举类型。 25 | ::: 26 | 27 | ## 使用 28 | 29 | ```ts 30 | type Keys = 'name' | 'age'; 31 | 32 | interface Profile { 33 | [P in Keys]: string; 34 | } 35 | 36 | /** 37 | * interface Profile { 38 | * name: string; 39 | * age: string; 40 | * } 41 | * 42 | */ 43 | 44 | ``` 45 | 46 | ## 快来耍耍啊 47 | 48 | ### 🌰🌰 49 | 50 | 51 | 52 | ``` 53 | // template 54 | ``` 55 | 56 | ### 游乐场 57 | 58 |
59 | 60 | 63 | 64 | ### 参考答案 65 | 66 | ```ts 67 | // answer 68 | ``` 69 | 70 | ## 参考资料 71 | 72 | 73 | -------------------------------------------------------------------------------- /docs/zh/keyword/infer/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | `infer` 最早出现在此 [PR](https://github.com/Microsoft/TypeScript/pull/21496) 中, 表示在 `extends` 条件语句中待推断的类型变量。 4 | 5 | `infer` 关键词常在条件类型中和 `extends` 关键词一同出现, 表示**将要推断的类型, 作为类型变量可以在三元表达式的 `true` 部分引用**。而 `ReturnType` 正是使用这种方式提取到了函数的返回类型。 6 | 7 | 使用 `infer`, 编译器确保您已经显式声明了所有类型变量。 8 | 9 | ## 使用 10 | 11 | ```ts 12 | type Unpacked = T extends (infer U)[] 13 | ? U 14 | : T extends (...args: any[]) => infer U 15 | ? U 16 | : T extends Promise 17 | ? U 18 | : T; 19 | 20 | type T0 = Unpacked; // string 21 | type T1 = Unpacked; // string 22 | type T2 = Unpacked<() => string>; // string 23 | type T3 = Unpacked>; // string 24 | type T4 = Unpacked[]>; // Promise 25 | type T5 = Unpacked[]>>; // string 26 | ``` 27 | 28 | `infer` 可以用来推断联合类型 29 | 30 | ```ts 31 | type Foo = T extends {a: infer U; b: infer U} ? U : never; 32 | 33 | type T10 = Foo<{a: string; b: string}>; // string 34 | type T11 = Foo<{a: string; b: number}>; // string | number 35 | ``` 36 | 37 | 同样,在变数位置中针对同一类型变量的多个候选会导致得出交集类型: 38 | 39 | ```ts 40 | type Bar = T extends {a: (x: infer U) => void; b: (x: infer U) => void} ? U : never; 41 | type T20 = Bar<{a: (x: string) => void; b: (x: string) => void}>; // string 42 | type T21 = Bar<{a: (x: string) => void; b: (x: number) => void}>; // string & number 43 | ``` 44 | 45 | ## 内置类型 46 | 47 | ### 用于提取函数类型的返回值类型 48 | 49 | ```ts 50 | /** 51 | * 获取函数 T 的返回类型 52 | */ 53 | type ReturnType any> = T extends (...args: any) => infer R ? R : any; 54 | ``` 55 | 56 | 更多有关于 `ReturnType` [Here](../../utility-types/#returntype-t) 57 | 58 | #### Demo 59 | 60 | ```ts 61 | type Func = (...args: any) => string | number; 62 | 63 | type ReturnValue = ReturnType; // string | number 64 | ``` 65 | 66 | ### 用于提取构造函数中参数 (实例) 类型 67 | 68 | 构造函数可以使用 `new` 来实例化, 因此它的类型通常表示如下: 69 | 70 | ```ts 71 | type Constructor = new (...ages: any[]) => any; 72 | ``` 73 | 74 | 当 `infer` 用于构造函数类型中, 可用于参数位置 `new (...args: infer P) => any` 和 返回值位置 `new (...args: any[]) => infer P`。 75 | 76 | 因此就内置如下两个映射类型: 77 | 78 | ```ts 79 | // 获取参数类型 80 | type ConstructorParameters any> = T extends new ( 81 | ...args: infer P 82 | ) => any 83 | ? P 84 | : never; 85 | 86 | // 获取实例类型 87 | type InstanceType any> = T extends new (...args: any[]) => infer R 88 | ? R 89 | : any; 90 | ``` 91 | 92 | #### Demo 93 | 94 | ```ts 95 | class TestClass { 96 | constructor(public name: string, public string: number) {} 97 | } 98 | 99 | type Params = ConstructorParameters; // [string, numbder] 100 | 101 | type Instance = InstanceType; // TestClass 102 | ``` 103 | 104 | ## 快来耍耍啊 105 | 106 | ### 🌰🌰 107 | 108 | 109 | 110 | ``` 111 | // template 112 | ``` 113 | 114 | ### 游乐场 115 | 116 |
117 | 118 | 121 | 122 | ### 参考答案 123 | 124 | ```ts 125 | // answer 126 | ``` 127 | 128 | ## 参考资料 129 | 130 | [infer PR: Type inference in conditional types](https://github.com/Microsoft/TypeScript/pull/21496) 131 | 132 | [typescript-2-8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html) 133 | 134 | [type-inference-in-conditional-types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#type-inference-in-conditional-types) 135 | 136 | [TypeScript 面试题](https://github.com/LeetCode-OpenSource/hire/blob/master/typescript_zh.md) -------------------------------------------------------------------------------- /docs/zh/keyword/instanceof/README.md: -------------------------------------------------------------------------------- 1 | ## Previously 2 | 3 | `instanceof` 运算符用于检测构造函数的 `prototype` 属性是否出现在某个实例对象的原型链上。 4 | 5 | ```js 6 | function Car(make, model, year) { 7 | this.make = make; 8 | this.model = model; 9 | this.year = year; 10 | } 11 | const auto = new Car('Honda', 'Accord', 1998); 12 | 13 | console.log(auto instanceof Car); 14 | // expected output: true 15 | 16 | console.log(auto instanceof Object); 17 | // expected output: true 18 | ``` 19 | 20 | 21 | ## 定义 22 | 23 | :::theorem instanceof 24 | `instanceof` 通过 **构造函数** 来细化类型, 用来检测实例与 **类** 的所属关系。 25 | ::: 26 | 27 | **Note:** 28 | 29 | - 参数: `instanceof` 在左侧使用变量名称, 在左侧使用函数或类的名称。 30 | - 返回: `Boolean` 值。 31 | 32 | ## 使用 33 | 34 | ```ts 35 | interface Person { 36 | name: string; 37 | age: string | number; 38 | } 39 | 40 | const mine: Person = { 41 | name: 'Rain120', 42 | age: 18 43 | } 44 | 45 | const isPerson = typeMine instanceof Person; // true 46 | ``` 47 | 48 | ## 快来耍耍啊 49 | 50 | ### 🌰🌰 51 | 52 | 53 | 54 | ``` 55 | // template 56 | ``` 57 | 58 | ### 游乐场 59 | 60 |
61 | 62 | 65 | 66 | ### 参考答案 67 | 68 | ```ts 69 | // answer 70 | ``` 71 | 72 | ## 参考资料 73 | 74 | [instanceof-guard](https://alligator.io/typescript/instanceof-guard/) 75 | 76 | 77 | -------------------------------------------------------------------------------- /docs/zh/keyword/is/README.md: -------------------------------------------------------------------------------- 1 | ## Previously 2 | 3 | ```ts 4 | function isString(value: any): boolean { 5 | // toExponential() 方法以指数表示法返回该数值字符串表示形式。numObj = 77.1234; => numObj.toExponential(2) //输出 7.71e+1 6 | console.log(value.toExponential(2)); 7 | return value === 'string'; 8 | } 9 | ``` 10 | 11 | ## 定义 12 | 13 | :::theorem is 14 | `is` 关键字被称为类型谓词, 它表示是否属于某个类型, 可以有效地缩小类型范围, 它可以帮助开发者在编辑阶段发现错误,从而避免一些隐藏的运行时错误。 15 | ::: 16 | 17 | 作用: 既可以作为返回值,也可以缩小变量(函数内部会校验类型)的类型范围。 18 | 19 | ## 使用 20 | 21 | ```ts 22 | // incorrect 23 | function isString(value: any): boolean { 24 | // toExponential() 方法以指数表示法返回该数值字符串表示形式。 25 | console.log(value.toExponential(2)); 26 | return typeof value === 'string'; 27 | } 28 | 29 | // 使用 Demo 30 | function isString_is(value: any): value is string { 31 | return typeof value === 'string'; 32 | } 33 | 34 | function testString(string: any) { 35 | if (isString(string)) { 36 | console.log(string.length) 37 | console.log(string.toExponential(2)) 38 | } 39 | 40 | // 测试 is 收窄范围和普通模式下的优势 41 | if (isString_is(string)) { 42 | console.log(string.length) 43 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential 44 | // Property 'toExponential' does not exist on type 'string'.(2339) 45 | console.log(string.toExponential(2)) 46 | } 47 | } 48 | 49 | testString('female'); 50 | 51 | ``` 52 | 53 | [直接体验](https://www.typescriptlang.org/play?#code/PTAEEsDsGMHsCd4FNoBcBQAzArjV5ZIIBnAZVXigHMAKANwEMAbbJALlAcgE8BKDgEaxYTJF1ABvdAEgQoVLACiADwAOhJJHzMavUIE7TQKs2gU7lA4MaAHU0AWEYC5PQ4BX4wHtqgU+jzgHgVA6tqAyb0BMcjcBG+oDw+oBADOigoHCQxCJIAHRMsLSMLLEKKuqQmtpMNABMvLwA3KGgyKjY8ESo3KpIsJigSaygALytoADkxBTU7UUAvujocoD+8oAUrqAAIkgAtrBYuGgEROBk3ZBUAPor9MysHFx8HI1IJKBdlOuSxaXlldW19cctbZ1rVL3oA-N4S-JIXeQLrRztR9jw9FIwuB6jQVoDqDQQet8lcwmEIlFRHEEoi3nFNFRUAALXjFdGETGxeLAvGpNQaLTgHR5UlhL5hOSAaVtAKvRp0AbKaAEK9AMDBgBe1QAxKoA7M0AWAmAQisAoBoOUAIW6ADHlAP1KxWhoFhqyBW2IuKBKMhaIx0WxNKB+PWxNZaLkRNQqFUxDYIAAJkg6Eh4jV4DFZgAvcBMJgMGIIKjATQAWgAqqRgG7YNBiMAAOpIATAABSDEYpGglFUqGAACUkJgkMgYEhgABxeICZgbADyAgAVihUKmAHLYaYCKvAOnpTJMphk0ByAAK8FgvqqHRHDKy7VASf+oEgsFQoCQyhWu8I8nuHSR7xiuQAzFeAJy28mRM3Ug3UGLLjKM5n5YoDL6of5UHhdYaHaStpmYJB2kKIA) 54 | 55 | ## 快来耍耍啊 56 | 57 | ### 🌰🌰 58 | 59 | 60 | 61 | ``` 62 | // template 63 | ``` 64 | 65 | ### 游乐场 66 | 67 |
68 | 69 | 72 | 73 | ### 参考答案 74 | 75 | ```ts 76 | // answer 77 | ``` 78 | 79 | ## 参考资料 80 | 81 | [what-does-the-is-keyword-do-in-typescript](https://stackoverflow.com/questions/40081332/what-does-the-is-keyword-do-in-typescript) 82 | -------------------------------------------------------------------------------- /docs/zh/keyword/keyof/README.md: -------------------------------------------------------------------------------- 1 | ## Previously 2 | 3 | `JavaScript` 是一种动态语言。有时在静态类型系统中捕获某些操作的语义可能会很棘手。 4 | 5 | ```js 6 | function prop(obj, key) { 7 | return obj && obj[key] ? obj[key] : null; // lodash.get(prop, key) 8 | } 9 | ``` 10 | 11 | 该函数接收 `obj` 和 `key` 两个参数,并返回对应属性的值。对象上的不同属性,可以具有完全不同的类型,我们甚至不知道 `obj` 对象长什么样。 12 | 13 | ```ts 14 | function prop(obj, key: string) { 15 | return (obj as any)[key]; 16 | } 17 | ``` 18 | ## 定义 19 | 20 | :::theorem keyof 21 | `keyof` 也称为输入索引类型查询, 与之相对应的是索引访问类型, 也称为查找类型, 用来取得一个对象接口(某种类型)的所有 `key` 值, 返回一个联合类型。 22 | 23 | :::right 24 | [Typescript 2.1 新增](https://devblogs.microsoft.com/typescript/announcing-typescript-2-1-2/#keyof-and-lookup-types) 25 | ::: 26 | 27 | ## 如何解决上述问题 28 | 29 | ```ts 30 | type Todo = { 31 | id: number; 32 | text: string; 33 | done: boolean; 34 | } 35 | 36 | const todo: Todo = { 37 | id: 1, 38 | text: "Learn TypeScript keyof", 39 | done: false 40 | } 41 | 42 | // extends 关键字约束该类型必须是 object 类型的子类型 43 | function prop(obj: T, key: K) { 44 | return obj[key]; 45 | } 46 | 47 | // number 48 | const id = prop(todo, "id"); 49 | 50 | // string 51 | const text = prop(todo, "text"); 52 | 53 | // boolean 54 | const done = prop(todo, "done"); 55 | 56 | ``` 57 | 58 | ## 使用 59 | 60 | ```ts 61 | interface Profile { 62 | name: string; 63 | age: number; 64 | } 65 | 66 | // 'name' | 'age' 67 | type Keys = keyof Profile; 68 | 69 | // 'string' | 'number' 70 | type TypeKeys = keyof { [K: string]: Profile}; 71 | ``` 72 | 73 | ### 访问值 74 | 75 | 可通过 **T[K]** 索引访问。 76 | 77 | ```ts 78 | interface Profile { 79 | name: string, 80 | readonly age: number, 81 | } 82 | 83 | // string 84 | type Name = Profile['name'] 85 | 86 | // string | number 87 | type NameAge = Profile['name' | 'age'] 88 | 89 | // 如果[]中的key有不存在T中的,则是any; 90 | // 因为ts也不知道该key最终是什么类型,所以是any; 91 | // 且也会报错 92 | // any 93 | type GetValueFromUnknownKey = Profile['name' | 'unknownKey'] 94 | 95 | // string | number 96 | type ProfileValue = Profile[keyof Profile] 97 | 98 | ``` 99 | 100 | ## ⚠️ 注意 101 | 102 | 对于 **任何类型T**, **keyof T**的结果为该类型上所有 **公有(public)属性key** 的联合。 103 | 104 | ```ts 105 | interface Profile { 106 | name: string, 107 | readonly age: number, 108 | } 109 | 110 | // ProfileKeys 的类型实则是 name | age 111 | type ProfileKeys = keyof Profile; 112 | 113 | class PersonProfile { 114 | private name: string; 115 | protected home: string; 116 | public readonly age: number; 117 | } 118 | 119 | // PersonProfileKeys 实则被约束为 age 120 | // 而 name 和 home 不是公有属性,所以不能被 keyof 获取到 121 | type PersonProfileKeys = keyof PersonProfile; 122 | ``` 123 | 124 | ## 快来耍耍啊 125 | 126 | ### 🌰🌰 127 | 128 | 129 | 130 | ``` 131 | // template 132 | ``` 133 | 134 | ### 游乐场 135 | 136 |
137 | 138 | 141 | 142 | ### 参考答案 143 | 144 | ```ts 145 | // answer 146 | ``` 147 | 148 | ## 参考资料 149 | 150 | [TypeScript keyof 操作符](https://cloud.tencent.com/developer/article/1595718) 151 | -------------------------------------------------------------------------------- /docs/zh/keyword/typeof/README.md: -------------------------------------------------------------------------------- 1 | ## Previously 2 | 3 | `typeof` 只能校验基本类型只能返回这种类型, `undefined`, `boolean`, `string`, `number`, `object`, `function`。 4 | 5 | ## 定义 6 | 7 | :::theorem typeof 8 | 用于获取变量的声明类型。 9 | ::: 10 | 11 | **Note:** 12 | 13 | - 参数: `typeof` 只接受我们正在检查其变量类型的变量的名称, 该变量的名称在右侧, 而左侧则没有。 14 | 15 | - 返回: `类型 (Type)` 的值。 16 | 17 | ## 使用 18 | 19 | ```ts 20 | function getType(val: any) { 21 | return typeof val; 22 | } 23 | 24 | getType('name'); // string 25 | 26 | const COLORS = { 27 | red: 'red', 28 | blue: 'blue' 29 | } 30 | 31 | // 通过 typeof 操作符获取 color 变量的类型 32 | type Type = typeof COLORS 33 | // { 34 | // red: string; 35 | // blue: string; 36 | // } 37 | ``` 38 | 39 | ## 快来耍耍啊 40 | 41 | ### 🌰🌰 42 | 43 | 44 | 45 | ``` 46 | // template 47 | ``` 48 | 49 | ### 游乐场 50 | 51 |
52 | 53 | 56 | 57 | ### 参考答案 58 | 59 | ```ts 60 | // answer 61 | ``` 62 | 63 | ## 参考资料 64 | 65 | 66 | -------------------------------------------------------------------------------- /docs/zh/operator/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | 运算符定义一些将对数据, 变量执行的功能。 运算符所作用的数据称为操作数或者操作变量。 4 | 5 | ## & 运算符 6 | 7 | [交叉类型](../advanced-types/intersection-types/) 8 | 9 | ```ts 10 | interface Boy { 11 | handsome: boolean; 12 | } 13 | 14 | interface Girl { 15 | cute: boolean; 16 | } 17 | 18 | type Person = Boy & Girl; 19 | 20 | const someone: Person = { 21 | handsome: true, 22 | cute: false 23 | }; 24 | ``` 25 | 26 | ## | 运算符 27 | 28 | [联合类型](../advanced-types/union-types/) 29 | 30 | ```ts 31 | interface Boy { 32 | hair: boolean; 33 | tall: boolean; 34 | } 35 | 36 | interface Girl { 37 | hair: boolean; 38 | cute: boolean; 39 | } 40 | 41 | type Person = Boy | Girl 42 | 43 | const someone: Person = { 44 | hair: true 45 | } 46 | ``` 47 | 48 | ## ! 非空断言操作符 49 | 50 | 表达式不能为 `null` 或 `undefined` 的方式 51 | 52 | > `!`在类型检查器无法得出结论的情况下,可以使用新的后缀表达式运算符来断言其操作数为非`null`且未定义。具体来说,操作`x!`生成一个类型为`x`的值,不包含 `null` 和 `undefined`的值。类似于表单`x`和的类型声明`x as T`。 53 | > 54 | > **Note:** `!`非空断言操作符会从编译生成的 `JavaScript` 代码中移除。 55 | 56 | ```typescript 57 | class C { 58 | foo!: number; 59 | // ^ 60 | // Notice this '!' modifier. 61 | // This is the "definite assignment assertion" 62 | 63 | constructor() { 64 | this.initialize(); 65 | } 66 | 67 | initialize() { 68 | this.foo = 0; 69 | } 70 | } 71 | ``` 72 | 73 | ### 忽略 null 和 undefined 类型 74 | 75 | ```ts 76 | const profile: any = { 77 | name: 'Rain120', 78 | schools: {} 79 | } 80 | 81 | const getProfile(profile: any) { 82 | console.log(profile!.name, profile!.age, profile!.schools!) 83 | } 84 | 85 | getProfile(profile); 86 | getProfile(); 87 | ``` 88 | 89 | ### 忽略函数 undefined 类型 90 | 91 | ```ts 92 | const curry = (fn: any) => { 93 | return fn!(); 94 | } 95 | ``` 96 | 97 | **Note:** 98 | 99 | 出现下面情况,需要注意一下,因为`!`非空断言操作符会从编译生成的 `JavaScript` 代码中移除。 100 | 101 | ```ts 102 | const name: undefined | string = undefined; 103 | const getName: string = name!; 104 | console.log(getName); 105 | 106 | // 转换成 ES5 ===> 107 | "use strict"; 108 | const name = undefined; 109 | const getName = name; 110 | console.log(getName); 111 | ``` 112 | 113 | [严格的属性初始化](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#strict-class-initialization) 114 | 115 | [非null断言运算符](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator) 116 | 117 | ## ? 运算符 118 | 119 | - 定义属性用于 **可选属性定义** 120 | 121 | ```typescript 122 | interface Profile { 123 | name: string; 124 | age?: number | string; 125 | } 126 | ``` 127 | 128 | [optional-properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#optional-properties) 129 | 130 | - 使用属性用于 **可选的属性访问** 131 | 132 | ### ?. 运算符 133 | 134 | **?.** 只会检查其左侧的值是否为 `null` 或 `undefined`, 而不检查任何后续属性。 135 | 136 | ```ts 137 | const x = foo?.bar.baz 138 | 139 | // ===> 140 | 141 | const x = (foo === null || foo === undefined) 142 | ? undefined 143 | : foo.bar.baz(); 144 | ``` 145 | 146 | **Note:** `typescript 3.7+`才支持。 147 | 148 | [optional-chaining](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html?#optional-chaining) 149 | 150 | [Announcing TypeScript 3.7 RC](https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-rc/) -> [译文](https://www.infoq.cn/article/d95pGayR9s4eucUGKSFP) 151 | 152 | ### ?? 运算符 153 | 154 | **空值合并运算符** 是即将推出的另一个 `ECMAScript 2020`功能, 它与可选的链接并驾齐驱。 155 | 156 | **当左侧操作数为 null 或 undefined 时,其返回右侧的操作数,否则返回左侧的操作数**。 157 | 158 | ```ts 159 | let x = foo ?? bar(); 160 | 161 | // ===> 162 | 163 | let x = (foo !== null && foo !== undefined) 164 | ? foo 165 | : bar(); 166 | ``` 167 | 168 | [nullish-coalescing](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing) 169 | 170 | ## + - 运算符 171 | 172 | `TypeScript 2.8` 为映射类型增加了增加或移除特定修饰符的能力。 特别地, 映射类型里的`readonly`或`?`属性修饰符现在可以使用`+`或`-`前缀, 来表示修饰符是添加还是移除。 173 | 174 | ```ts 175 | type MutableRequired = { 176 | -readonly [P in keyof T]-?: T[P] 177 | }; // 移除readonly和? 178 | type ReadonlyPartial = { 179 | +readonly [P in keyof T]+?: T[P] 180 | }; // 添加readonly和? 181 | ``` 182 | 183 | [改进对映射类型修饰符的控制](http://www.tslang.cn/docs/release-notes/typescript-2.8.html) 184 | 185 | ## _ 运算符 186 | 187 | TypeScript 2.7支持ECMAScript的数字分隔符提案。 这个特性允许用户在数字之间使用下划线(_)来对数字分组(就像使用逗号和点来对数字分组那样)。 188 | 189 | ```ts 190 | // Constants 191 | const COULOMB = 8.957_551_787e9; // N-m^2 / C^2 192 | const PLANCK = 6.626_070_040e-34; // J-s 193 | const JENNY = 867_5309; // C-A-L^2 194 | ``` 195 | 196 | 这些分隔符对于二进制和十六进制同样有用。 197 | 198 | ```ts 199 | let bits = 0b0010_1010; 200 | let routine = 0xC0FFEE_F00D_BED; 201 | let martin = 0xF0_1E_ 202 | ``` 203 | 204 | 注意,可能有些反常识,`JavaScript`里的数字表示信用卡和电话号并不适当。 这种情况下使用字符串更好。 205 | 206 | [数字分隔符](https://www.tslang.cn/docs/release-notes/typescript-2.7.html) 207 | 208 | ## \# 运算符 209 | 210 | TypeScript 3.8 支持在 ECMAScript 中处于 [stage-3](https://github.com/tc39/proposal-class-fields/) 中的私有字段。 211 | 212 | ```ts 213 | class Person { 214 | #name: string 215 | 216 | constructor(name: string) { 217 | this.#name = name; 218 | } 219 | 220 | greet() { 221 | console.log(`Hello, my name is ${this.#name}!`); 222 | } 223 | } 224 | 225 | let jeremy = new Person("Jeremy Bearimy"); 226 | 227 | jeremy.#name 228 | // ~~~~~ 229 | // Property '#name' is not accessible outside class 'Person' 230 | // because it has a private identifier. 231 | ``` 232 | 233 | 不同于正常属性(甚至是使用 `private` 修饰符声明的属性),私有字段有一些需要记住的规则: 234 | 235 | - 私有字段使用 `#` 字符作为开始,通常,我们也把这些称为私有名称。 236 | - 每个私有字段的名字,在被包含的类中,都是唯一的 237 | - 在 TypeScript 中,像 `public` 和 `private` 修饰符不能用于私有字段 238 | - 私有字段不能在所包含的类之外访问 —— 即使是对于 JavaScript 使用者来说也是如此。通常,我们把这种称为「hard privacy」。 239 | 240 | 除了「hard privacy」,私有字段的另外一个优点是我们先前提到的唯一性。 241 | 242 | 正常的属性容易被子类所改写 243 | 244 | ```ts 245 | class C { 246 | foo = 10; 247 | 248 | cHelper() { 249 | return this.foo; 250 | } 251 | } 252 | 253 | class D extends C { 254 | foo = 20; 255 | 256 | dHelper() { 257 | return this.foo; 258 | } 259 | } 260 | 261 | let instance = new D(); 262 | // 'this.foo' refers to the same property on each instance. 263 | console.log(instance.cHelper()); // prints '20' 264 | console.log(instance.dHelper()); // prints '20' 265 | ``` 266 | 267 | 使用私有字段时,你完全不必对此担心,因为每个私有字段,在所包含的类中,都是唯一的 268 | 269 | ```ts 270 | class C { 271 | #foo = 10; 272 | 273 | cHelper() { 274 | return this.#foo; 275 | } 276 | } 277 | 278 | class D extends C { 279 | #foo = 20; 280 | 281 | dHelper() { 282 | return this.#foo; 283 | } 284 | } 285 | 286 | let instance = new D(); 287 | // 'this.#foo' refers to a different field within each class. 288 | console.log(instance.cHelper()); // prints '10' 289 | console.log(instance.dHelper()); // prints '20' 290 | ``` 291 | 292 | 另外有一个值得注意的地方,访问一个有其他类型的私有字段,都将导致 `TypeError`。 293 | 294 | ```ts 295 | class Square { 296 | #sideLength: number; 297 | 298 | constructor(sideLength: number) { 299 | this.#sideLength = sideLength; 300 | } 301 | 302 | equals(other: any) { 303 | return this.#sideLength === other.#sideLength; 304 | } 305 | } 306 | 307 | const a = new Square(100); 308 | const b = { sideLength: 100 }; 309 | 310 | // Boom! 311 | // TypeError: attempted to get private field on non-instance 312 | // This fails because 'b' is not an instance of 'Square'. 313 | console.log(a.equals(b)); 314 | ``` 315 | 316 | 对于类属性来说,`JavaScript` 总是允许使用者访问没被声明的属性,而 TypeScript 需要使用者在访问之前先定义声明。使用私有字段时,无论时 `.js` 文件还是 `.ts`,都需要先声明。 317 | 318 | ```ts 319 | class C { 320 | /** @type {number} */ 321 | #foo; 322 | 323 | constructor(foo: number) { 324 | // This works. 325 | this.#foo = foo; 326 | } 327 | } 328 | ``` 329 | 330 | 更多信息,请查看此 [PR](https://github.com/Microsoft/TypeScript/pull/30829)。 331 | 332 | ### 私有字段与 private 的区别 333 | 334 | 说到这里使用 `#` 定义的私有字段与 `private` 修饰符定义字段有什么区别呢?现在我们先来看一个 `private` 的示例: 335 | 336 | ```ts 337 | class Person { 338 | constructor(private name: string) {} 339 | } 340 | 341 | let person = new Person("Semlinker"); 342 | console.log(person.name); 343 | ``` 344 | 345 | 在上面代码中,我们创建了一个 `Person` 类,该类中使用 `private` 修饰符定义了一个私有属性 `name`,接着使用该类创建一个 `person` 对象,然后通过 `person.name` 来访问 `person` 对象的私有属性,这时 `TypeScript` 编译器会提示以下异常: 346 | 347 | ``` 348 | Property 'name' is private and only accessible within class 'Person'.(2341) 349 | ``` 350 | 351 | 那如何解决这个异常呢?当然你可以使用类型断言把 person 转为 any 类型: 352 | 353 | ```ts 354 | console.log((person as any).name); 355 | ``` 356 | 357 | 通过这种方式虽然解决了 TypeScript 编译器的异常提示,但是在运行时我们还是可以访问到 `Person` 类内部的私有属性,为什么会这样呢?我们来看一下编译生成的 ES5 代码,也许你就知道答案了: 358 | 359 | ```ts 360 | var Person = (function () { 361 | function Person(name) { 362 | this.name = name; 363 | } 364 | return Person; 365 | }()); 366 | 367 | var person = new Person("Semlinker"); 368 | console.log(person.name); 369 | ``` 370 | 371 | 在 TypeScript 3.8 以上版本通过 `#` 号定义的私有字段编译后会生成什么代码: 372 | 373 | ```ts 374 | class Person { 375 | #name: string; 376 | 377 | constructor(name: string) { 378 | this.#name = name; 379 | } 380 | 381 | greet() { 382 | console.log(`Hello, my name is ${this.#name}!`); 383 | } 384 | } 385 | ``` 386 | 387 | 以上代码目标设置为 `ES2015`,会编译生成以下代码: 388 | 389 | ```js 390 | "use strict"; 391 | var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) 392 | || function (receiver, privateMap, value) { 393 | if (!privateMap.has(receiver)) { 394 | throw new TypeError("attempted to set private field on non-instance"); 395 | } 396 | privateMap.set(receiver, value); 397 | return value; 398 | }; 399 | 400 | var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) 401 | || function (receiver, privateMap) { 402 | if (!privateMap.has(receiver)) { 403 | throw new TypeError("attempted to get private field on non-instance"); 404 | } 405 | return privateMap.get(receiver); 406 | }; 407 | 408 | var _name; 409 | class Person { 410 | constructor(name) { 411 | _name.set(this, void 0); 412 | __classPrivateFieldSet(this, _name, name); 413 | } 414 | greet() { 415 | console.log(`Hello, my name is ${__classPrivateFieldGet(this, _name)}!`); 416 | } 417 | } 418 | _name = new WeakMap(); 419 | ``` 420 | 421 | 通过观察上述代码,使用 `#` 号定义的 `ECMAScript` 私有字段,会通过 WeakMap 对象来存储,同时编译器会生成 `__classPrivateFieldSet` 和 `__classPrivateFieldGet` 这两个方法用于设置值和获取值。 422 | 423 | [ECMAScript Private Fields](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#ecmascript-private-fields) 424 | 425 | ## 快来耍耍啊 426 | 427 | ### 🌰🌰 428 | 429 | 430 | 431 | ``` 432 | // template 433 | ``` 434 | 435 | ### 游乐场 436 | 437 |
438 | 439 | 442 | 443 | ## 参考答案 444 | 445 | ```ts 446 | // answer 447 | ``` 448 | 449 | ## 参考资料 450 | 451 | [What's new in TypeScript](https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript) 452 | 453 | [TypeScript 3.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#ecmascript-private-fields) 454 | 455 | [ECMAScript feature: numeric separators](https://2ality.com/2018/02/numeric-separators.html) 456 | 457 | [细数 TS 中那些奇怪的符号](https://www.yuque.com/arvinxx-fe/typescript/dfe2722f-0c2a-4189-b2c5-de128f85d40f#d958e3d1) 458 | -------------------------------------------------------------------------------- /docs/zh/tips/README.md: -------------------------------------------------------------------------------- 1 | ## Tips 列表 2 | 3 | [if else](./if-else/README.md) 4 | 5 | [spread](./spread/README.md) 6 | -------------------------------------------------------------------------------- /docs/zh/tips/if-else/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | 条件类型,条件类型冒号左边为 if 右边为 else 4 | 5 | ## 使用 6 | 7 | ```ts 8 | type If = T extends K ? true : false; 9 | 10 | type IfValue = T extends true ? K : L; 11 | ``` 12 | 13 | ## 快来耍耍啊 14 | 15 | ### 🌰🌰 16 | 17 | 18 | 19 | ```ts 20 | type A = { name: string } 21 | type B = { name: string; age?: number | string } 22 | 23 | type x = If 24 | 25 | type xA = IfValue 26 | type xB = IfValue 27 | 28 | ``` 29 | 30 | [Go Demo](https://www.typescriptlang.org/play?#code/C4TwDgpgBAkgZgHgCoBooGkB8UC8UlQQAewEAdgCYDOGUA-FMAE4Cu0AXFHAIYA2VEANwAoYaEiw4ANT5tkhEuWpQARgHs1vCNzJp0aADLY8BYqUo1mberU4GRY8NACCuKAG8oZbgFsInKmYASzIAcygAX0cJACE3T28-AOCwwShuUIg6TjIWHxUIJigAHyhAphDwqOjoIjd4BGc0GMxRcVrXPHgZXjkrCDQmqBaaqCI4rulZCAQefgGoIZagA) 31 | 32 | ### 游乐场 33 | 34 |
35 | 36 | 39 | 40 | ### 参考答案 41 | 42 | ```ts 43 | // answer 44 | ``` 45 | 46 | ## 参考资料 47 | 48 | 49 | -------------------------------------------------------------------------------- /docs/zh/tips/spread/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | 拓展运算符 4 | 5 | ## 使用 6 | 7 | ```ts 8 | type spreadFirst = T extends [infer First, ...infer Rest] ? First : never; 9 | 10 | type spreadLast = T extends [...infer First, infer Last] ? Last : never; 11 | 12 | type spreadFirstChar = T extends `${infer First}${infer Rest}`? First : never; 13 | 14 | type spreadRestChar = T extends `${infer First}${infer Rest}`? Rest : never; 15 | ``` 16 | 17 | ## 快来耍耍啊 18 | 19 | ### 🌰🌰 20 | 21 | 22 | 23 | ```ts 24 | type Arr = [1, 2, 3] 25 | type Str = '123' 26 | type Num = 123 27 | 28 | type FA = spreadFirst // 1 29 | type LA = spreadLast // 3 30 | 31 | type FS = spreadFirstChar // 1 32 | type LS = spreadRestChar // 23 33 | 34 | type FN = spreadFirstChar // never 35 | 36 | ``` 37 | 38 | [Go Demo](https://www.typescriptlang.org/play?#code/C4TwDgpgBAzmBOECGATAYgS3jYAeAKgHxQC8U+UEAHsBAHYoxQDaGdAZhPFJtsADRQAdCLaduAJQg4AulAD8PLDigAuKHQgA3LgG4AUPtCRYCZCgAySHAWJkK1WgybMRQsVyV9BH7ldkKUP7AahraeobG0HCIqLw4AMIAFkjwtqTklDT0jFAABgAkAN6+XjgAvsWlUhV5ivEh6po68AZG4NFmqDXAyanp9llOuYUlHJ4NlWPiUD3ldbPSjWEtbVFQAILw3GTMAIyCAEyCAMwy7SYAysA7UADke4cndxfQAHIArgC2GY8nkR0eBsMjFzA1cFt4IRXkFgWRQahghDttCYWhLiCuuhlL0UmlrlCYRYMfCsT0+vibqj1mg3pjYti+BTcJ8vtCgA) 39 | 40 | ### 游乐场 41 | 42 |
43 | 44 | 47 | 48 | ### 参考答案 49 | 50 | ```ts 51 | // answer 52 | ``` 53 | 54 | ## 参考资料 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/zh/type-assertion/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | 有时候你会比 `Typescript` 更了解你的值的类型, `Typescript` 允许你使用你想要的方式分析并覆盖它, 这种机制被称为 **「类型断言」**。 4 | 5 | ## 使用 6 | 7 | 类型断言有 **两种形式**: 8 | 9 | ### as 10 | 11 | ```ts 12 | const someValue: any = "this is a string"; 13 | 14 | const strLength: number = (someValue as string).length; 15 | ``` 16 | 17 | ### <> 尖括号 18 | 19 | ```ts 20 | const someValue: any = "this is a string"; 21 | 22 | const strLength: number = (someValue).length; 23 | ``` 24 | 25 | **Note:** 当你在 **`.jsx`** `or` **`.tsx`** 中使用 **尖括号** 的方式进行类型断言时, 会造成 **语言歧义**, 为了保持一致性, 推荐使用 `as` 语法来进行 **类型断言**。[相关体验](https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgApQPY2AGxQbwCgBIEOAWwgC5kBnMKUAcwG4S4nrkQBXcgI2jIAPnQbM2AX0KEEGEPWRweYABYYoyALzIAPOiy4IAPnyS2hZWo0A6MpW3IA5ACU4oAIwAmAAxPCQA) 26 | 27 | ## 双重断言 28 | 29 | 原理: 任何类型都可以被断言为 `any`, 而 `any` 可以被断言为任何类型。 30 | 31 | ```ts 32 | interface Person { 33 | name: string; 34 | } 35 | 36 | const mine = 'Rain120'; 37 | 38 | ((age as any) as Person).name; 39 | 40 | ``` 41 | 42 | **Note:** 双重断言极具破坏性, 而且它很可能会导致运行时错误, 慎用 !!! 43 | 44 | ## ! 后缀类型断言 45 | 46 | 我们知道 `Nullable` 类型实质上是 [**联合类型**](../advanced-types/union-types/README.md), 那么同样面临类型缩窄的问题。对此, `TypeScript` 也提供了符合直觉的类型保护。 47 | 48 | 自动类型保护无法处理的场景可以通过 `!` 后缀来去除 `Nullable`部分, 即 `null | undefined`。 49 | 50 | ```ts 51 | interface Profile { 52 | name: string; 53 | age?: number | string; 54 | } 55 | function getParentInfo(profile: Profile): number | string { 56 | return profile!.age!; 57 | } 58 | ``` 59 | 60 | 更多操作符相关, 请到 [Here](../operator/README.md) 61 | 62 | ## 类型断言 与 类型转换 63 | 64 | 在计算机科学中, **[类型转换 (type conversion)](https://zh.wikipedia.org/zh-cn/%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2)** 是指将数据从一种类型 **转换成** 另一种类型的过程。所以 **类型转换** 是在 **运行时** 转换的, 而 **类型断言** 只是一个编译时的语法, 为编译器提供关于如何分析代码的方法。 65 | 66 | 若要进行类型转换, 需要直接调用类型转换的方法: 67 | ```ts 68 | Boolean(); 69 | 70 | String(); 71 | 72 | parseInt(); 73 | 74 | // etc... 75 | ``` 76 | 77 | ## 断言判断 78 | 79 | - **C类型** 是 **P类型** 的 **子类型** 80 | 81 | - **P类型** 是 **C类型** 的 **子类型** 82 | 83 | **C类型** 能被断言为 **P类型**。 84 | 85 | ## 快来耍耍啊 86 | 87 | ### 🌰🌰 88 | 89 | 90 | 91 | 请解决👇👇👇报错 92 | 93 | ```ts 94 | interface Profile { 95 | name: string; 96 | age: number | string; 97 | } 98 | 99 | const author = {}; 100 | 101 | // Property 'name' does not exist on type '{}'.(2339) 102 | author.name = 'Rain120'; 103 | 104 | ``` 105 | 106 | ### 游乐场 107 | 108 |
109 | 110 | 113 | 114 | ### 参考答案 115 | 116 | ```ts 117 | 118 | interface Profile { 119 | name: string; 120 | age: number | string; 121 | } 122 | 123 | const author = {} as Profile; 124 | 125 | // const author = {}; 126 | 127 | author.name = 'Rain120'; 128 | 129 | ``` 130 | 131 | ## 参考资料 132 | 133 | [Handbook - type-assertion](https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions) 134 | 135 | [深入理解 Typescript](https://jkchao.github.io/typescript-book-chinese/typings/typeAssertion.html) 136 | 137 | [Typescript - type-assertion](https://ts.xcatliu.com/basics/type-assertion.html) 138 | -------------------------------------------------------------------------------- /docs/zh/utility-types/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | `Typescript` 提供了几种 **实用工具类型**, 方便进行常见的类型转换。这些**实用工具类型**在全局范围内都可以使用。 4 | 5 | ## 实用工具类型 6 | 7 | 变量 `K`, `T`, `V` 详见[常见的一些泛型变量含义](../generics/#常见的一些泛型变量含义) 8 | 9 | ### `Partial` 10 | 11 | [Typescript 2.1 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-1-2/) 12 | 13 | #### 定义 14 | 15 | 构造一个类型 `T`, 将类型 `T`的所有属性设置为 **可选属性**。该工具类方法将返回一个表示输入类型 `(T)` 的所有自己的类型。 16 | 17 | #### 使用 18 | 19 | ```ts 20 | interface Todo { 21 | title: string; 22 | description: string; 23 | } 24 | 25 | function updateTodo(todo: Todo, fieldsToUpdate: Partial) { 26 | return { ...todo, ...fieldsToUpdate }; 27 | } 28 | 29 | const todo1 = { 30 | title: 'organize desk', 31 | description: 'clear clutter', 32 | }; 33 | 34 | const todo2 = updateTodo(todo1, { 35 | description: 'throw out trash', 36 | }); 37 | 38 | ``` 39 | 40 | #### 源码实现 41 | 42 | ```ts 43 | type Partial = { 44 | [P in keyof T]?: T[P]; 45 | } 46 | 47 | ``` 48 | 49 | [直接体验](https://www.typescriptlang.org/play/#code/PTAEAUEMCcBcEtIBsBQL4DtYFNoDNIBjbUAFQHsATc0AbxQEgFYlsAuUAZ1mkwHMA3I0rZOhXgAcE5DB268MglAF80eAK4ZC0jKHUTKkHBWoAKWFXIcT5ADSg88bEkqcKAVQNH2EGAmQAPDYAfACUdIzQ2LDq0Lq0oAB0yRbU9smJjs6uHl44oMpCqiiEMtygqeQAjKAAvBFM8Cw+AOTk0HyQGPAAXiQinADWLbbCouLwUvAyHC2ErDCg8+qwONAjKkIlZbAVlgBMdXp52DbmllX29AwDE1MzoC2wABbQ5ADuoOQrFdCQnM8NspQgIgA) 50 | 51 | ### `Readonly` 52 | 53 | [Typescript 2.1 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-1-2/) 54 | 55 | #### 定义 56 | 57 | 构造一个所有属性都设置为 **只读** 属性的类型 `T`, 这意味着 **无法** 再次对所有构造类型的属性进行 **赋值**。 58 | 59 | #### 使用 60 | 61 | ```ts 62 | interface Properties { 63 | cute: boolean; 64 | handsome: boolean; 65 | } 66 | 67 | let mine: Readonly = { 68 | cute: true, 69 | handsome: true, 70 | } 71 | 72 | mine.handsome = false; 73 | // Cannot assign to 'handsome' because it is a read-only property.(2540) 74 | 75 | ``` 76 | 77 | 该工具对于表示在运行时会失败的赋值表达式很有用, 例如 [`Object freeze`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) 78 | 79 | ```ts 80 | function freeze(obj: T): Readonly; 81 | 82 | ``` 83 | 84 | #### 源码实现 85 | 86 | ```ts 87 | type Readonly = { 88 | readonly [P in keyof T]: T[P]; 89 | } 90 | ``` 91 | 92 | [直接体验](https://www.typescriptlang.org/play/?ssl=20&ssc=1&pln=1&pc=1#code/PTAECUFMEMBMHsB2AbAngKHQS0QF0gE4Bm0AxpKAAoHwAOhuWkAzqAN7oCQpArvgFygARvHjIYiANxcAFtESxm8ALaRBIsROkBfTONyhlONRBgIUqADzU6DJswB8oALzsuvAaFwEekADSy8ooqJt6+AbroRoiQAHRyCkqqLqAkyMyQkkA) 93 | 94 | ### `Record` 95 | 96 | [Typescript 2.1 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-1-2/) 97 | 98 | #### 定义 99 | 100 | 构造一个属性为 `K` 类型, 属性值为 `T` 类型的类型。可用于将一个类型的属性 **映射到** 另一个类型中。 101 | 102 | #### 使用 103 | 104 | ```ts 105 | // Record 106 | interface Page { 107 | title?: string | undefined; 108 | content?: string | undefined; 109 | } 110 | 111 | type PageType = 'home' | 'about' | 'contact'; 112 | 113 | const site: Record = { 114 | home: { 115 | content: 'home' 116 | }, 117 | about: { 118 | title: 'about', 119 | content: 'about' 120 | }, 121 | contact: { 122 | title: 'contact', 123 | // Error: Type '{ title: string; name: string; }' is not assignable to type 'Page'. 124 | // Object literal may only specify known properties, 125 | // and 'name' does not exist in type 'Page'. 126 | name: 'Rain120' 127 | }, 128 | } 129 | 130 | ``` 131 | 132 | #### 源码实现 133 | 134 | ```ts 135 | type Record = { 136 | [P in K]: T; 137 | } 138 | ``` 139 | 140 | [直接体验](https://www.typescriptlang.org/play?#code/PTAECUFMGMHsCcAmAoAlgOwC6XgMwIbSSgAK+A5sQN7ICQmqmANpAPwBcoAzpvBuaAA+oAK7pEkXBkiIA3HThZIWDt178ho8ZOlzkAX2TJMATwAOxMpQAq54gF5QAcgAWsALaQnmp-gBGsCKY3sJOipiEwfLIijzcjJCcUHBIADxWkLYWADSkFJAAfKCONLRunpyltOHKmJyuHl50+tl0-oF1oFUMzInO7UFOrbTVsEpY9QPBzcPhkZV09Iws9XPQwa2gW9tbIKBZxE5UoD0ranzo5LKg6PgV5-zX+t6oXDewmKD4XFyo5Ld+FgnWAnOzODJOAB0yB2Oz2AHk-AArGCfJgJeD4Jigdz4EygMZMfFcCzQVC4fEAa3QsAA7uhQGZ4LALPAGJAuJtYbswPhxM5bp5vIhYBz3p9IAAPV6fDCgizg-JQxaCvpOcD4DAARgATAAGJwzAxAA) 141 | 142 | ### `Pick` 143 | 144 | [Typescript 2.1 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-1-2/) 145 | 146 | #### 定义 147 | 148 | 通过从类型 `T` **选取** 属性 `K` 的集合来构造类型。 149 | 150 | #### 使用 151 | 152 | ```ts 153 | interface Todo { 154 | title: string; 155 | description: string; 156 | isCompleted: boolean; 157 | } 158 | 159 | type TodoWithDay = Pick 160 | 161 | const plan: TodoWithDay = { 162 | title: 'Writing for Typescript Guide', 163 | isCompleted: true 164 | } 165 | 166 | ``` 167 | 168 | #### 源码实现 169 | 170 | ```ts 171 | type Pick = { 172 | [P in K]: T[P]; 173 | } 174 | ``` 175 | 176 | [直接体验](https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=15&pc=1#code/PTAEAUEsGMGsCh6QHYBcCmAnAZgQ2uqACoD2AJiaAN7yh2iqSoA26AXKAM6qYoDmAblr0y6TtF4AHRiWQduvZIOF1InAMIkAtpNYYyHAEYkSrXMiEBfRKgCekwqQoB1JgAsAIrlugAvBBhYAB4nEgAaUAByRhZ0SNAAHyi1TR09dDJIgD5EaFluUF1zDlDXVE9vP2oVBiZWDkjnXkYlUGwSTGJ7MQlIaVAAcQBXSFFIsJqU7V10fQ4eIfR4ayA) 177 | 178 | ### `Omit` 179 | 180 | [Typescript 3.5 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-3-5/) 181 | 182 | #### 定义 183 | 184 | 通过从 类型 `T` 中 **选取** 所有属性, 然后 **删除** 传入的属性 `K` 来构造新类型。 185 | 186 | #### 使用 187 | 188 | ```ts 189 | interface Todo { 190 | title: string; 191 | description: string; 192 | isCompleted: boolean; 193 | } 194 | 195 | type TodoWithDay = Omit 196 | 197 | const plan: TodoWithDay = { 198 | title: 'Writing for Typescript Guide', 199 | isCompleted: true 200 | } 201 | ``` 202 | 203 | #### 源码实现 204 | 205 | ```ts 206 | type Omit = Pick> 207 | ``` 208 | 209 | [直接体验](https://www.typescriptlang.org/play/?ssl=9&ssc=32&pln=9&pc=43#code/PTAEHkFsEsBcCh7QHawKYCcBmBDAxmqACoD2AJiaAN7yh2ixwA2aAXKAM6wYoDmA3LXpk0HPDwAOjEsnZceyAULrQOAYRKQJLdGXYAjEiRY5kggL6JYATwmFSFAOpwAFgBEc10AF4IMWAA8DiQANKAA5CJiktLI4QB8iHgyXKDapuzBzrDunj7UygzMbBGOPIyKoFgkGMS2ouLQUqAA4gCu0CLhIYWqGlo6aHoMGG1o8JZAA) 210 | 211 | ### `Exclude` 212 | 213 | [Typescript 2.8 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-8-2/) 214 | 215 | #### 定义 216 | 217 | 通过从类型 `T` 中 **剔除** 可赋值给 `U` 的属性来构造一个新类型。 218 | 219 | #### 使用 220 | 221 | ```ts 222 | type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c" 223 | 224 | type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c" 225 | 226 | type T2 = Exclude void), Function>; // string | number 227 | 228 | ``` 229 | 230 | #### 源码实现 231 | 232 | ```ts 233 | type Exclude = T extends U ? never : T; 234 | ``` 235 | 236 | [直接体验](https://www.typescriptlang.org/play/?ssl=1&ssc=4&pln=1&pc=15#code/PTAEFEA8GMBsFcAmBTAUKgLgTwA7NACoAMoAvBDAigDwBEAhraAD6i0BGTrt0tANG0YA+ANyhQINpxZte6bHkIBGMhThJkdRjI5dZ-QXt2jxknrXm58BAEyqo6mgGcMAJwCWAOwDmMz-ABbdmRXGQAKMIBKMiFQADcAe3dESIEAMXhPaAx3BM8TCTAXDx8-QODXVCA) 237 | 238 | ### `Extract` 239 | 240 | [Typescript 2.8 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-8-2/) 241 | 242 | #### 定义 243 | 244 | 通过从类型 `T` 中 **挑选** 可赋值给 `U` 的属性来构造一个新类型。 245 | 246 | #### 使用 247 | 248 | ```ts 249 | type T0 = Extract<'a' | 'b', 'a'> // 'a' 250 | 251 | type T1 = Extract<'a' | 'b' | (() => void), Function> // () => void 252 | ``` 253 | 254 | #### 源码实现 255 | 256 | ```ts 257 | type Extract = T extends U ? T : never; 258 | ``` 259 | 260 | [直接体验](https://www.typescriptlang.org/play/?ssl=1&ssc=4&pln=1&pc=11#code/PTAEFEA8BcCcEMDG0BQLoE8AOBTUAVABlAF4IYFkAeAcnhtAB9QaAjGgGhfoD5QRuNNJlwEAjKXJwk0WvSYt2CgBTKAlKT4A3APYBLACZquAMQCuAO2R6dFvgPWbQuw0A) 261 | 262 | ### `NonNullable` 263 | 264 | [Typescript 2.8 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-8-2/) 265 | 266 | #### 定义 267 | 268 | #### 使用 269 | 270 | ```ts 271 | // NonNullable 272 | 273 | type T0 = NonNullable<'a' | null> // 'a' 274 | 275 | type T1 = NonNullable<'a' | null | undefined> // 'a' 276 | ``` 277 | 278 | #### 源码实现 279 | 280 | ```ts 281 | type NonNullable = T extends null | undefined ? never : T; 282 | ``` 283 | 284 | [直接体验](https://www.typescriptlang.org/play/?ssl=1&ssc=4&pln=1&pc=15#code/PTAEDkHsDtwVwDYIIYCMEFMBQWAuBPABw1ABUAGUAXghniTUwB4BnXAJwEtoBzUAH1DQ4AW1QZ2A0HGgATDADNuGWQD4A3KFAhQbLrynCxEnAWJkAjNVqxEKdBlYduPANoBdQ3akz5S6CoaWjp6Lh5AA) 285 | 286 | 287 | ### `Parameters` 288 | 289 | #### 定义 290 | 291 | 构造一个关于函数类型 `T` 的 **参数类型** 的元组类型。请到 [#26019](https://github.com/Microsoft/TypeScript/issues/26019) 292 | 293 | #### 使用 294 | 295 | ```ts 296 | declare function f1(arg: { a: number, b: string }): void 297 | 298 | type T0 = Parameters<() => string>; // [] 299 | 300 | type T1 = Parameters<(s: string) => void>; // [string] 301 | 302 | type T2 = Parameters<((arg: T) => T)>; // [unknown] 303 | 304 | type T4 = Parameters; // [{ a: number, b: string }] 305 | 306 | type T5 = Parameters; // unknown[] 307 | 308 | type T6 = Parameters; // never 309 | 310 | type T7 = Parameters; // Error 311 | 312 | type T8 = Parameters; // Error 313 | ``` 314 | 315 | #### 源码实现 316 | 317 | ```ts 318 | type Parameters = { 319 | T extends (...args: infer P) => any ? P : never 320 | } 321 | ``` 322 | 323 | [直接体验](https://www.typescriptlang.org/play/?ssl=3&ssc=1&pln=19&pc=42#code/PTAEAUEMCdIWwKYBcHQM4CgMBMEGMAbGBUAMwFcA7PJASwHtKyBGAChgHMAuUAb1Eg9K5OACNUAGlCieaJNFqUOoAL4BKHgDd6tbFiQBPAA4kAKgAZQAXggx4yVGgA8rNdYB8oOQqXuA3KCgIKAA2gC6+sZmzNa2sIgo6C5osvKKHG5Wntq6-oHBId7pERiGJqCmAEyxUPEOSaxOpu7s0NwVmZ6manlBYCFUANaU9ADulCVlZgAsNXYJjk5T9KQsvQX8gqDCYpLSqT7KKpNRFQCsc3WJzpCUButgQyPj4ZHlpgBsl-bXTpQImlQD22ANQbzMAHZvgskkVfAE+qAAKLQaD0aDgioADmh9WcADEqDQGJRgSi0dAgA) 324 | 325 | 326 | ### `ConstructorParameters` 327 | 328 | #### 定义 329 | 330 | 通过 `ConstructorParameters` 类型, 我们可以 **提取** 构造函数类型的 **所有参数类型**。 它会生成构造函数所具有的所有参数类型的元组类型(如果 `T` 不是函数, 则不返回)。 331 | 332 | #### 使用 333 | 334 | ```ts 335 | type T0 = ConstructorParameters; // [(string | undefined)?] 336 | 337 | type T1 = ConstructorParameters; // string[] 338 | 339 | type T2 = ConstructorParameters; // [string, (string | undefined)?] 340 | ``` 341 | 342 | #### 源码实现 343 | 344 | ```ts 345 | type ConstructorParameters = { 346 | T extends new (...args: infer P) => any ? P : never 347 | } 348 | ``` 349 | 350 | [直接体验](https://www.typescriptlang.org/play/?ssl=3&ssc=1&pln=7&pc=88#code/PTAEGEHsDsGcBcBOBXAxvSiAKBDROBbAU3iMVgCgL4BPAByNABUAGUAXghgRXU13zFS5ADwBRRIkxQ4SNBkQA+ANyhQIUAG0AFDwCW0AOagAPqGTQAJkQBmBopYCUAfgC6VWg2YBGDl1m8CgKEJGSwIgBiFuh6MDI88pgqahr6Rpru1PSMTABMfvFyfNh4IcLhAEpEhmIAHnSFgUmq6mCaaYYANKC6SAbGZhbWdtAOLq5AA) 351 | 352 | ### `ReturnType` 353 | 354 | [Typescript 2.8 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-8-2/) 355 | 356 | #### 定义 357 | 358 | 构造一个由函数 `T` 的返回类型组成的新类型。 359 | 360 | #### 使用 361 | 362 | ```ts 363 | declare function f1(): { a: number, b: string } 364 | 365 | type T0 = ReturnType<() => string>; // string 366 | 367 | type T1 = ReturnType<(s: string) => void>; // void 368 | 369 | type T2 = ReturnType<(() => T)>; // {} 370 | 371 | type T3 = ReturnType<(() => T)>; // number[] 372 | 373 | type T4 = ReturnType; // { a: number, b: string } 374 | 375 | type T5 = ReturnType; // any 376 | 377 | type T6 = ReturnType; // any 378 | 379 | type T7 = ReturnType; // Error 380 | 381 | type T8 = ReturnType; // Error 382 | ``` 383 | 384 | #### 源码实现 385 | 386 | ```ts 387 | type ReturnType< 388 | T extends (...args: any[]) => any 389 | > = T extends (...ages: any[]) => infer R ? R : any; 390 | ``` 391 | 392 | [直接体验](https://www.typescriptlang.org/play/?ssl=1&ssc=4&pln=1&pc=15#code/PTAECUFMBcFcCcB2AVAngB0gKCwE0gMYA2AhvJKAGayIHQCWA9olQIwAUAlAFygDeoEr0SwAtgCNI8ADShxvAM7R49RAHNQAXyzQMFZAAZQAXggwEKPQB4uJgHyglK9XYDcoUCEfLVanXtBkVhMzOCQ0TBsFRR91TntQADdGelw3Dy9k1P9MQIAmEKgwy0j2K2Q7W2MHZE50zzA+bV1c5ABmQvNw6zLkUEgAD2hIRFwFUABVWQn+oZGx0BEJKQBtAF1K+OrAuvcGxbFJeHWc-QAWTuKIyCsWyEZKNnqvASED5Zk5GOcNZoDkACslws1ysJEQqGeYHBqFOgQAbMDupFEJBElIoYIIXDkAB2JElG5OXyYgCi8HgjHgOIAHATQQAxGh0JiIMkUqlAA) 393 | 394 | ### `InstanceType` 395 | 396 | [Typescript 2.8 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-8-2/) 397 | 398 | #### 定义 399 | 400 | 构造y一个由构造函数 `T` 的 **实例类型** 组成的新类型。 401 | 402 | #### 使用 403 | 404 | ```ts 405 | class C { 406 | x = 0; 407 | y = 0; 408 | } 409 | 410 | 411 | type T0 = InstanceType; // C 412 | 413 | type T1 = InstanceType; // any 414 | 415 | type T2 = InstanceType; // any 416 | 417 | type T3 = InstanceType; // Error 418 | 419 | type T4 = InstanceType; // Error 420 | ``` 421 | 422 | #### 源码实现 423 | 424 | ```ts 425 | type InstanceType< 426 | T extends new (...args: any[]) => any 427 | > = T extends new (...args: any[]) => infer R : R : any; 428 | ``` 429 | 430 | [直接体验](https://www.typescriptlang.org/play/?ssl=17&ssc=39&pln=17&pc=44#code/PTAECUFMBcFcCcB2AVAngB0gKCwYwDYCGAzsaAMKgDeWodoAHqALygAMA3Lfai+1wF8cWaBkihkbPgElExaIUS5IaTAB5RmAPYAzCgD4OdEBRybxyAIwy5CpSrFrFqQ8bDOzYiQCYb8xcqqkGqIkABukPCuoCYeIl7IAMx+doGO8vAAlogA5tEmAKLw8FrwnpgSACwpAQ7qAGKwStCZWoj5YEUl8EA) 431 | 432 | ### `Required` 433 | 434 | [Typescript 2.8 rc 新增工具方法](https://devblogs.microsoft.com/typescript/announcing-typescript-2-8-rc/) 435 | 436 | #### 定义 437 | 438 | #### 使用 439 | 440 | ```ts 441 | interface Profile { 442 | name: string; 443 | age?: number; 444 | gender?: string; 445 | }; 446 | 447 | // OK 448 | const profile: Profile = { 449 | name: 'Rain120', 450 | }; 451 | 452 | // Type '{ name: string; }' is missing the following properties 453 | // from type 'Required': age, gender(2739) 454 | const ID_Card: Required = { 455 | name: 'Rain120', 456 | }; 457 | ``` 458 | 459 | #### 源码实现 460 | 461 | ```ts 462 | type Required = { 463 | [P in keyof T]-?: T[P]; 464 | } 465 | ``` 466 | 467 | 操作符相关问题请到 [Here](../operator/README.md) 468 | 469 | [直接体验](https://www.typescriptlang.org/play/#code/PTAECUFMEcFcEsBOkAmAoN8B2AXSiAzAQwGNJQAFRAewPgBtyBvNUN0LIgW0gC5QAzjkTYA5gG5W7IqMgB+fllhcARvkntQsrCnwLBwsZIC+ktCFAB5ANJoS1LENAAHGnUb8qtBuQC8oFk1OHn4AcnAibABGACYABlCAGjRTDDsHJwBJABEAfQBhIkQUfig4JFQAHi93SAA+UH8mUCk2YL5QcMisWITk0yA) 470 | 471 | 472 | ### `ThisParameterType` 473 | 474 | #### 定义 475 | 476 | 提取函数类型的 `this` 参数的类型, 如果函数类型没有 `this` 参数, 则 [未知](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type)。 477 | 478 | 注意: 仅当启用 `--strictFunctionTypes` 时, 此类型才能正常工作。 请到 [#32964](https://github.com/microsoft/TypeScript/issues/32964) 479 | 480 | #### 使用 481 | 482 | ```ts 483 | function toHex(this: Number) { 484 | return this.toString(16); 485 | } 486 | 487 | function numberToString(n: ThisParameterType) { 488 | return toHex.apply(n); 489 | } 490 | ``` 491 | 492 | [直接体验](https://www.typescriptlang.org/play/?ssl=3&ssc=1&pln=9&pc=2#code/PTAEBUAsEsGcAUCGAnRBbApgFw88BPABwwCgSAzAVwDsBjLaAe2tC0YAkMAPACixlgAuUADlKaAEa4AlKADeJUEtDJslZC35wAdGwDKWZNGoBzHgEYAbNIDcJAL5kqdBs1DVxUvIwNHTPamEoOCRUTBw8IgwAHiwoxnJWDm4APlkFZRU1DSTOLm1EQkIAG3wA2wcgA) 493 | 494 | 495 | ### `OmitThisParameter` 496 | 497 | #### 定义 498 | 499 | 从函数类型中删除 `this` 参数。 500 | 501 | 注意: 仅当启用 `--strictFunctionTypes` 时, 此类型才能正常工作。请到 [#32964](https://github.com/microsoft/TypeScript/issues/32964) 502 | 503 | #### 使用 504 | 505 | ```ts 506 | function toHex(this: Number) { 507 | return this.toString(16); 508 | } 509 | 510 | // The return type of `bind` is already using `OmitThisParameter`, this is just for demonstration. 511 | const fiveToHex: OmitThisParameter = toHex.bind(5); 512 | 513 | console.log(fiveToHex()); 514 | ``` 515 | 516 | [直接体验](https://www.typescriptlang.org/play/?ssl=8&ssc=18&pln=8&pc=35#code/PTAEHkFsEsBcBUAW0DOAFAhgJw5AprHlgFDEBmArgHYDGs0A9laLAwBJ4AeAFLMigC5QAOQqQARkQCUoAN7FQi0FgIUszPqgB0rAMqws0KgHNuARgBsUgNzEAvqRCgkeZavUsAngAdXDMqAABuJGACaBoKigGAA2KhihnqAUKEbGQVBwSKiYOPiEWIEANCz8kSigAFYpsKBkDFigoXiQTCgGGPRMWsQ0bbVk0ABuePDsXEKZCPy5uAREADywPnj+LOOcAHygALzrHJxaIVSh3ACsNqR9VCgMMXhaMQymgyNjB9xSNkA) 517 | 518 | 519 | ### `ThisType` 520 | 521 | #### 定义 522 | 523 | 该工具 **不会返回转换后** 的类型。 相反, 它是一个用作上下文类型中键入 `this` 类型的标记。 注意, 必须启用 `–noImplicitThis` 标志才能使用此工具。 524 | 525 | #### 使用 526 | 527 | ```ts 528 | // Compile with --noImplicitThis 529 | 530 | type ObjectDescriptor = { 531 | data?: D; 532 | methods?: M & ThisType; // Type of 'this' in methods is D & M 533 | } 534 | 535 | function makeObject(desc: ObjectDescriptor): D & M { 536 | let data: object = desc.data || {}; 537 | let methods: object = desc.methods || {}; 538 | return { ...data, ...methods } as D & M; 539 | } 540 | 541 | let obj = makeObject({ 542 | data: { x: 0, y: 0 }, 543 | methods: { 544 | moveBy(dx: number, dy: number) { 545 | this.x += dx; // Strongly typed this 546 | this.y += dy; // Strongly typed this 547 | } 548 | } 549 | }); 550 | 551 | obj.x = 10; 552 | obj.y = 20; 553 | obj.moveBy(5, 5); 554 | 555 | ``` 556 | 557 | - 在上面的示例中, `makeObject` 的参数中的 `methods` 对象具有包含 `ThisType` 的上下文类型; 因此, 在 `methods` 对象内的方法中, 方法的 `this` 类型为 `{x: number, y: number}&{moveBy (dx: number, dy: number) : number}`。 请注意 `methods` 属性的类型是如何同时成为方法中 `this` 类型的推断目标和来源的。 558 | - `ThisType` 标记接口仅仅是在 `lib.d.ts` 中声明的一个空接口。 除了在对象字面量的上下文类型中被识别外, 该接口的作用类似于任何空接口。 559 | 560 | [直接体验](https://www.typescriptlang.org/play/#code/PTAEBUAsEsGdwJ4AcCmAoNJQGED2BbJaAGxVAHdoAXSUAWjoDtcBJQ46AY2qjgyuRkA8gCMAVik5UAIilicATtCRVcCgDzSANKACyAPlABeUAG80oS6AAmAQyq2A-AC5Q0gNwWr+FDVzXYFz1QADIIGHhBTVC9fXdLLERUUFwAM1AAcho4DNBoRlAfPwC82DcY3TQAXwxUgFdGKWhcAvxbAGsUUQkpTR0DAAprOU5XbskZEaUVNT7YgEpXaQqzL0tSKht7W1dccQnjGxGAOjsHUAAfC7MqzytQDcLfSH9YXf2pQ+H5Y6KXkquNzuVgUvjqCgKplAxxhZ1sOhhv2er1AVVAtjKyzCuk8NTQjz2YkObU64ykA3M9zhrihAA9XAAGHQIRmorRrJ7FN6re73fC4ABuKAAQgghvTQIw6vgRCgFDprCzJdLZQp5jzeZrsrBjrTQABqEzWWnxUBYADKVAULQA5sQEKABKhrI6IhzNZZtccHYabAhTRarbb7Y7BC7te6rDV7jUqvNPGhCbrDgBGBmeJMOkwAJnTifEv0FIrFAFYdCX40A) 561 | 562 | 563 | ## 快来耍耍啊 564 | 565 | ### 🌰🌰 566 | 567 | 568 | 569 | ``` 570 | // template 571 | ``` 572 | 573 | ### 游乐场 574 | 575 |
576 | 577 | 580 | 581 | ### 参考答案 582 | 583 | ```ts 584 | // answer 585 | ``` 586 | 587 | ## 参考资料 588 | 589 | [handbook - utility-types](https://www.typescriptlang.org/docs/handbook/utility-types.html) 590 | 591 | [handbook - mapped-types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types) 592 | 593 | [Microsoft TypeScript wiki Road map](https://github.com/Microsoft/TypeScript/wiki/Roadmap) 594 | 595 | [Microsoft TypeScript #21316 Conditional Types](https://github.com/Microsoft/TypeScript/pull/21316) 596 | 597 | [Microsoft TypeScript #21496 infer pull request](https://github.com/Microsoft/TypeScript/pull/21496) 598 | 599 | [Conditional types in TypeScript](https://artsy.github.io/blog/2018/11/21/conditional-types-in-typescript/) 600 | -------------------------------------------------------------------------------- /docs/zh/utility-types/custom-utility-types/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | Typescript 提供的实用工具类型并不能完全满足我们的需求,很多时候,我们都需要自定义一些满足我们需求的工具类型。 4 | 5 | ### 集合的操作 6 | 7 | ### 交集 8 | 9 | **定义: 对于给定的两个集合,返回一个包含两个集合中共有元素的新集合。** 10 | 11 | 我们可以借助[Pick](https://rain120.github.io/typescript-guide/zh/utility-types/#pick-t-k) 和 [Extract](https://rain120.github.io/typescript-guide/zh/utility-types/#extract-t-u)来实现。 12 | 13 | ```ts 14 | type Intersection = Pick< 15 | T, 16 | Extract & Extract 17 | > 18 | ``` 19 | 20 | [直接体验](https://www.typescriptlang.org/play?#code/C4TwDgpgBACgjFAvFA3lAdgQwLYQFxQDOwATgJboDmANFJpfkaRZVAL4BQoksATEqgw5GxclVr1G6AK7YARhBK0G6ACaKColuw5dw0AJLpgiwhADGwMgHt0AHg5QnUACpQIADxNrCUa3IArC2BqR2cAVXcvCB8-QOCOAD4BGDJzAGsHZ1dQ7IBRLxJMSzt0iBBrADMcqDKK6vDkgDIoAtJi4FLyqqhw2jqel0Sk3W5oGAEjExIzSxt7eFoYXkSgA) 21 | 22 | ### 并集 23 | 24 | **定义: 对于给定的两个集合,返回一个包含两个集合中所有元素的新集合。** 25 | 26 | ```ts 27 | // 合并交叉类型 28 | type Compute = T extends Function 29 | ? T 30 | : { [K in keyof T]: T[K] } 31 | 32 | // P1: { name: string, age: string } 33 | // P2: { name: string, gender: string } 34 | // Res => { name: string, age: string } & { gender: string } 35 | // => { name: string, age: string, gender: string } 36 | type Merge = Compute< 37 | T & Omit 38 | > 39 | ``` 40 | 41 | #### demo 42 | 43 | ```ts 44 | type P1 = { 45 | name: string, 46 | age: string 47 | } 48 | type P2 = { 49 | name: string, 50 | age: number, 51 | gender: string 52 | } 53 | 54 | type Intersection< 55 | T extends object, 56 | U extends object 57 | > = Pick< 58 | T, 59 | Extract & Extract 60 | > 61 | 62 | // { name: string, age: string } 63 | type P = Intersection 64 | ``` 65 | 66 | #### demo 67 | 68 | ```ts 69 | type P1 = { 70 | name: string, 71 | age: string 72 | } 73 | type P2 = { 74 | name: string, 75 | age: number, 76 | gender: string 77 | } 78 | 79 | type Compute = T extends Function ? T : { 80 | [K in keyof T]: T[K] 81 | } 82 | 83 | type Merge = Compute< 84 | T & Omit 85 | > 86 | 87 | // { name: string; age: string; gender: string; } 88 | type P = Merge 89 | ``` 90 | 91 | [直接体验](https://www.typescriptlang.org/play?#code/C4TwDgpgBACgjFAvFA3lAdgQwLYQFxQDOwATgJboDmANFJpfkaRZVAL4BQoksATEqgw5GxclVr1G6AK7YARhBK0G6ACaKColuw5dw0AMIB7bGGnAIAHgAqUCAA8LawnXQgAfANsOnqlwDFpdABjYDIjdCgAfihbAhQOKCSoAG0AaSgKKABrCBAjADNYgF0Ca3Tijk49HgBZRQYbO0cIZygjOQArCFDaAFVm3xcO7tDPZGNTcytE5NsAMigAeWwyYEs+2lz8out3Dn2a6BgBepJG+FoYXn2gA) 92 | 93 | 这里合并之后会发现,age 属性是使用前面属性的类型,这里如何解决呢? 94 | 95 | ### Overwrite 96 | 97 | ```ts 98 | type Overwrite< 99 | T extends object, 100 | U extends object, 101 | I = Diff & Intersection 102 | > = Pick 103 | ``` 104 | 105 | #### demo 106 | 107 | ```ts 108 | type P1 = { 109 | name: string, 110 | age: string 111 | } 112 | type P2 = { 113 | name: string, 114 | age: number, 115 | gender: string 116 | } 117 | 118 | type Intersection< 119 | T extends object, 120 | U extends object 121 | > = Pick< 122 | T, 123 | Extract & Extract 124 | > 125 | 126 | type Diff< 127 | T extends object, 128 | U extends object 129 | > = Pick< 130 | T, 131 | Exclude 132 | > 133 | 134 | type Compute = T extends Function ? T : { 135 | [K in keyof T]: T[K] 136 | } 137 | 138 | type Merge = Compute< 139 | T & Omit 140 | > 141 | 142 | type Overwrite< 143 | T extends object, 144 | U extends object, 145 | I = Diff & Intersection 146 | > = Pick 147 | 148 | type P = Overwrite 149 | ``` 150 | 151 | [直接体验](https://www.typescriptlang.org/play?#code/C4TwDgpgBACgjFAvFA3lAdgQwLYQFxQDOwATgJboDmANFJpfkaRZVAL4BQoksATEqgw5GxclVr1G6AK7YARhBK0G6ACaKColuw5dw0AJLpgiwhADGwMgHt0AHg5QnUACpQIADxNrCUa3IArC2BqR2cAVXcvCB8-QOCOAD4BGDJzAGsHZ1dQ7IBRLxJMSzt0iBBrADMcqDKK6vDkgDIoAtJi4FLyqqhw2jqel0Sk3W5oABEySsqs5zdPb1VffyDLXIioxeX4yySUtMywpxd1pwLzABtpdS76moGG4eG9HgBha2wwaRM7eejYzDoEDJZB-LZQABi0nQlhs6CgAH5XFACCgjlAANoAaSgFFq3WqLgAugQXNiiRxOC9oABZRQMX6bGJLOKrEK9JmxFbBEFQd6fb4QWbHKAtADy2DInT6+LuQxG1NgAjpJAZ8FoMF4zzGUDFADdFAB3cg-MJg5nbNnrSILC2s4LrAwCSbTX60RqiqBGEwkMyw2x2GXy3mpDJ2Az9Ale7X6XUwAT6o0moXqviJIA) 152 | 153 | ### 差集 154 | 155 | **定义: 对于给定的两个集合,返回一个包含所有存在于第一个且不存在于第二个集合的元素的新集合。** 156 | 157 | ```ts 158 | type Diff = Pick< 159 | T, 160 | Exclude 161 | > 162 | ``` 163 | 164 | #### demo 165 | 166 | ```ts 167 | type P1 = { 168 | name: string, 169 | age: string 170 | } 171 | type P2 = { 172 | name: string, 173 | age: number, 174 | gender: string 175 | } 176 | 177 | type Diff< 178 | T extends object, 179 | U extends object 180 | > = Pick< 181 | T, 182 | Exclude 183 | > 184 | 185 | // { gender: string } 186 | type P = Diff 187 | ``` 188 | 189 | [直接体验](https://www.typescriptlang.org/play?#code/C4TwDgpgBACgjFAvFA3lAdgQwLYQFxQDOwATgJboDmANFJpfkaRZVAL4BQoksATEqgw5GxclVr1G6AK7YARhBK0G6ACaKColuw5dw0ACJkAZsYA8HKFagAVKBAAewCGsJQA9nIBWEAMbBqS2sAVXsnF1U3Tx9-DgA+ARgyXwBrC2tbQIyAUQdfABtpdTMUiBB3Y0yoUvLK4Lj43W5oGAEjUzMYXlp4OKA) 190 | 191 | ## 快来耍耍啊 192 | 193 | ### 🌰🌰 194 | 195 | 196 | 197 | ``` 198 | // template 199 | ``` 200 | 201 | ### 游乐场 202 | 203 |
204 | 205 | 208 | 209 | ### 参考答案 210 | 211 | ```ts 212 | // answer 213 | ``` 214 | 215 | ## 参考资料 216 | 217 | 218 | -------------------------------------------------------------------------------- /docs/zh/what-is-typescript/README.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | [TypeScript](https://www.typescriptlang.org/) 是一种由微软开发的自由和开源的编程语言。它是 `JavaScript` 的一个超集, 包含了 `JavaScript` 的所有元素, 可以载入 `JavaScript` 代码运行, 并扩展了 `JavaScript` 的语法, 而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。它可以编译成纯 `JavaScript` 。编译出来的 `JavaScript` 可以运行在任何浏览器上。`TypeScript `编译工具可以运行在任何服务器和任何系统上。 [TypeScript Github](https://github.com/Microsoft/TypeScript) 4 | 5 | ## Typescript 与 JavaScript 的区别 6 | 7 | | Typescript | Javascript | 8 | |---------|---------| 9 | |静态语言|动态语言| 10 | |一种面向对象的编程语言, 需要TypeScript编译器才能转换为JavaScript文件|一种脚本语言, 不需要编译器, 可以在浏览器上运行。| 11 | |强类型, 支持静态和动态类型|弱类型, 没有静态类型选项| 12 | |接口,重载等特性|不支持接口,同名函数会被最后定的覆盖| 13 | 14 | ## 为什么使用TypeScript 15 | 16 | `TypeScript` 有两个主要目标: 17 | 18 | - 提供 `JavaScript` 的可选类型系统。 19 | 20 | - 提供从将来的 `JavaScript` 版本到当前 `JavaScript` 引擎的计划功能 21 | 22 | ![2020-ts-download.png](./images/2020-ts-download.png) 23 | 24 | [npm 下载量](https://npm-stat.com/charts.html?package=typescript&from=2015-01-01) 25 | 26 | ### 为什么要向 JavaScript 添加类型 27 | 28 | 类型具有 **提高代码质量** 和 **可理解性** 的能力。大型团队(`Google`, `Microsoft`, `Facebook`)一直在得出这一结论。 特别: 29 | 30 | - 类型在进行重构时可以提高敏捷性。 对于编译器来说, **捕获错误** 比使事情在运行时失败更好。 31 | 32 | - 类型是您可以拥有的最佳文档形式之一。 函数签名是一个定理, 函数体是证明。 33 | 34 | 但是, 类型定义有时候不需要特别的正式。 `TypeScript` 会根据类型推导尽可能降低的我们定义类型的成本。 35 | 36 | ## 如何使用 37 | 38 | ### 安装 39 | 40 | ```sh 41 | npm install -g typescript 42 | ``` 43 | 44 | ### 新建文件 45 | ```sh 46 | echo hello_world.ts > const gender: string = 'Female'; 47 | ``` 48 | 49 | ### 编译 50 | ```sh 51 | tsc hello_world.ts 52 | ``` 53 | 54 | ## 直接尝试 55 | 56 | [TypeScript Playground](https://www.typescriptlang.org/play/index.html) 57 | 58 | 63 | 64 | ## 学习资料 65 | 66 | [《TypeScript Deep Dive》](https://basarat.gitbook.io/typescript/) 是一本很好的开源书, 从基础到深入, 很全面的阐述了 `TypeScript` 的各种魔法, 不管你是新手, 还是老鸟, 它都将适应你。此外, 它不同于 `TypeScript` 官方给出的文档(当然 `TypeScript` 给出的文档是很好的), 在此书中, 结合实际应用下的场景用例, 你将能更深入的理解 `TypeScript`。[中文版](https://jkchao.github.io/typescript-book-chinese/) 67 | 68 | [awesome-typescript](https://github.com/semlinker/awesome-typescript) 收集了很多 `Typescript` 的相关学习资料。 69 | 70 | ## 参考资料 71 | 72 | [TypeScript](https://www.typescriptlang.org/) 73 | 74 | [TypeScript Github](https://github.com/Microsoft/TypeScript) 75 | 76 | [typescript Announcing](https://devblogs.microsoft.com/typescript/) 77 | 78 | [Why Typescript](https://basarat.gitbook.io/typescript/getting-started/why-typescript) 79 | 80 | [TypeScript 入门教程](https://juejin.im/post/5edd8ad8f265da76fc45362c) 81 | 82 | [未来可期的 TypeScript](https://mp.weixin.qq.com/s?__biz=MzIxNjgwMDIzMA==&mid=2247485103&idx=1&sn=9063e21d824db34820e955967c5a8ea3&scene=21#wechat_redirect) 83 | 84 | [非官方中文版](http://s0www0typescriptlang0org.icopy.site/index.html) 85 | 86 | [type-challenges](https://github.com/type-challenges/type-challenges) 87 | -------------------------------------------------------------------------------- /docs/zh/what-is-typescript/images/2020-ts-download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/docs/zh/what-is-typescript/images/2020-ts-download.png -------------------------------------------------------------------------------- /how-to-write-docs.md: -------------------------------------------------------------------------------- 1 | ## 如何写文档? 2 | 3 | 文档的规范, 以及如何方便快捷的书写 ✍️ 文档 4 | 5 | ## 新建文件 6 | 7 | 在`docs/zh`中新建一个文件, 并新建一个 `README.md`的文件 8 | 9 | **请保证每一个文件夹都有一个 `README.md`文件** 10 | 11 | **手动创建** 12 | 13 | ```sh 14 | touch docs/zh/test/README.md 15 | ``` 16 | 17 | **自动生成 `docs model`** 18 | ```sh 19 | npm run docs 20 | ``` 21 | 22 | ```sh 23 | ? please input the docs model name: model 24 | ? please input the docs model alias name (default same as model name)? 25 | ? generator model path (etc: docs/zh/model) ? docs/zh 26 | ``` 27 | 28 | `Eg: File Path` 29 | 30 | ```sh 31 | ├── guide 32 | │   └── README.md 33 | ├── how-to-config-docs 34 | │   └── README.md 35 | └── how-to-write-docs 36 | └── README.md 37 | ``` 38 | 39 | ### Tips & FAQs 如何添加到子目录下 40 | 41 | #### Tips 42 | 43 | ```sh 44 | ? npm run docs 45 | 46 | ? please input the docs model name: tips-test 47 | ? please input the docs model alias name (default same as model name)? 测试新增 tips 48 | ? generator model path (etc: docs/zh/model) ? docs/zh/tips 49 | ``` 50 | 51 | #### FAQs 52 | 53 | ```sh 54 | ? npm run docs 55 | 56 | ? please input the docs model name: faqs-test 57 | ? please input the docs model alias name (default same as model name)? 测试新增 faqs 58 | ? generator model path (etc: docs/zh/model) ? docs/zh/faqs 59 | ``` 60 | 61 | ## 配置别名 62 | 63 | ### 简约配置方式 64 | 65 | 通过使用 [新建文件](#新建文件) 的脚本来动态配置 `alias`, 妈妈再也不用担心我找不到配置了。 66 | 67 | ## 图片 68 | 69 | `~@images`路径 `->` 根路径 70 | 71 | ```md 72 | ![images.png](~@images/src/xxx) 73 | ``` 74 | 75 | `Eg:` 76 | 77 | ```md 78 | ![wechat-zhifubao-pay.png](~@images/wechat-zhifubao-pay.png) 79 | ``` 80 | 81 | ## 导入代码块 82 | 83 | 你可以在文档中展示你的代码, 只需要使用下面方式即可 84 | 85 | ```md {highlight number} 86 | <<< @/filepath 87 | ``` 88 | 89 | **Note:** `filepath`是你文档的路径 90 | 91 | `Eg:` 92 | 93 | ```md {1} 94 | <<< @/scripts/deploy.sh 95 | ``` 96 | 97 | ## 数学公式 98 | 99 | 你可以在文档中使用 **`markdown`** 来书写一下数学公式 100 | 101 | ```md 102 | $$ 103 | y=\begin{cases} 104 | -x,\quad x\leq 0 \\\\ 105 | x,\quad x>0 106 | \end{cases} 107 | $$ 108 | ``` 109 | 110 | ## Badge 徽章 111 | 112 | - **Props:** 113 | 114 | - `text - string` 115 | 116 | - `type - string`, 可选值: `'tip' | 'warning' | 'error'`, 默认值是: `'tip'` 117 | 118 | - `vertical - string`, 可选值: `'top' | 'middle'`, 默认值是: `'top'` 119 | 120 | - **Usage:** 121 | 122 | 你可以在标题中, 使用这个组件来为某些 API 添加一些状态: 123 | 124 | ```md 125 | Badge 126 | ``` 127 | 128 | ## 自定义容器 129 | 130 | ```md 131 | ::: tip 132 | This is a tip 133 | ::: 134 | 135 | ::: warning 136 | This is a warning 137 | ::: 138 | 139 | ::: danger 140 | This is a dangerous warning 141 | ::: 142 | ``` 143 | 144 | ## Emoji 145 | 146 | ```md 147 | :tada: :100: 148 | ``` 149 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-guide", 3 | "author": "Rain120", 4 | "repository": { 5 | "type": "git", 6 | "url": "git+https://github.com/Rain120/typescript-guide.git" 7 | }, 8 | "version": "1.0.0", 9 | "description": "Awesome code implementation for Javascript", 10 | "main": "index.js", 11 | "scripts": { 12 | "lint-staged": "lint-staged", 13 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add .", 14 | "plop": "./node_modules/.bin/plop", 15 | "docs": "npm run plop docs", 16 | "docs:dev": "vuepress dev docs", 17 | "docs:build": "vuepress build docs", 18 | "deploy": "bash ./scripts/deploy.sh", 19 | "remote": "bash ./scripts/remote.sh" 20 | }, 21 | "keywords": [ 22 | "docs", 23 | "vuepress", 24 | "template", 25 | "vuepress-docs", 26 | "docs-template", 27 | "typescript", 28 | "typescript-guide" 29 | ], 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/Rain120/typescript-guide/issues" 33 | }, 34 | "homepage": "https://github.com/Rain120/typescript-guide#readme", 35 | "lint-staged": { 36 | "{src}/**/**.ts": [ 37 | "git add" 38 | ] 39 | }, 40 | "husky": { 41 | "hooks": { 42 | "pre-commit": "npm run changelog && lint-staged", 43 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 44 | } 45 | }, 46 | "dependencies": { 47 | "monaco-editor": "^0.20.0" 48 | }, 49 | "devDependencies": { 50 | "@commitlint/cli": "^11.0.0", 51 | "@commitlint/config-conventional": "^11.0.0", 52 | "@vuepress/plugin-back-to-top": "^1.2.0", 53 | "@vuepress/plugin-blog": "^1.9.2", 54 | "@vuepress/plugin-google-analytics": "^1.2.0", 55 | "@vuepress/plugin-medium-zoom": "^1.5.2", 56 | "@vuepress/plugin-pwa": "^1.3.0", 57 | "conventional-changelog-cli": "^2.0.27", 58 | "husky": "^3.1.0", 59 | "lint-staged": "^9.5.0", 60 | "markdown-it-imsize": "^2.0.1", 61 | "markdown-it-katex": "^2.0.3", 62 | "markdown-it-task-lists": "^2.1.1", 63 | "moment": "^2.24.0", 64 | "monaco-editor-webpack-plugin": "^1.9.0", 65 | "plop": "^2.6.0", 66 | "vuepress": "^1.5.2", 67 | "vuepress-plugin-awesome-gitalk": "^0.0.4", 68 | "vuepress-plugin-container": "^2.1.4", 69 | "vuepress-plugin-mathjax": "^1.2.8" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /plop-templates/README.md.hbs: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | ## 使用 4 | 5 | ## 快来耍耍啊 6 | 7 | ### 🌰🌰 8 | 9 | 10 | 11 | ``` 12 | // template 13 | ``` 14 | 15 | ### 游乐场 16 | 17 |
18 | 19 | 22 | 23 | ### 参考答案 24 | 25 | ```ts 26 | // answer 27 | ``` 28 | 29 | ## 参考资料 30 | 31 | 32 | -------------------------------------------------------------------------------- /plopfile.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Rainy 3 | * @Date: 2020-03-04 17:43:25 4 | * @LastEditors: Rainy 5 | * @LastEditTime: 2020-08-06 19:34:34 6 | */ 7 | 8 | const path = require('path'); 9 | const fs = require('fs'); 10 | 11 | const aliasPath = path.resolve('docs/.vuepress/utils/alias.json') 12 | const last = ['tips', 'faqs']; 13 | 14 | /** 15 | * 16 | * @param {string} key modal name 17 | * @param {string} value modal alias 18 | */ 19 | function addAlias({ name, alias }) { 20 | const data = fs.readFileSync(aliasPath, 'utf-8'); 21 | const content = JSON.parse(data); 22 | if (!alias) { 23 | alias = name; 24 | } 25 | if (!content[name]) { 26 | content[name] = alias; 27 | } else { 28 | throw new Error('The name is exist'); 29 | } 30 | 31 | const value = {}; 32 | Object.keys(content).forEach(name => { 33 | if (!last.includes(name)) { 34 | value[name] = content[name]; 35 | } 36 | }); 37 | 38 | last.forEach(name => { 39 | value[name] = content[name]; 40 | }); 41 | 42 | const file = JSON.stringify(value, null, 2); 43 | 44 | fs.writeFileSync(aliasPath, new Buffer(file)) 45 | } 46 | 47 | module.exports = plop => { 48 | plop.setGenerator('docs', { 49 | description: 'Create zh docs', 50 | prompts: [ 51 | { 52 | type: 'input', 53 | name: 'name', 54 | message: 'please input the docs model name: ', 55 | default: 'model' 56 | }, 57 | { 58 | type: 'input', 59 | name: 'alias', 60 | message: 'please input the docs model alias name (default same as model name)?' 61 | }, 62 | { 63 | type: 'input', 64 | name: 'path', 65 | message: 'generator model path (etc: docs/zh/model) ?', 66 | default: 'docs/zh' 67 | } 68 | ], 69 | actions: answer => { 70 | addAlias(answer); 71 | return [ 72 | { 73 | type: 'add', 74 | path: '{{path}}/{{name}}/README.md', 75 | templateFile: 'plop-templates//README.md.hbs' 76 | } 77 | ]; 78 | } 79 | }); 80 | }; 81 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -e 4 | 5 | npm run docs:build 6 | 7 | cd docs/.vuepress/dist 8 | 9 | git init 10 | git add -A 11 | git commit -m 'deploy vuepress docs gh-pages' 12 | 13 | git push -f git@github.com:Rain120/typescript-guide.git master:gh-pages 14 | 15 | cd - 16 | -------------------------------------------------------------------------------- /scripts/remote.sh: -------------------------------------------------------------------------------- 1 | ### 2 | # @Author: Rainy 3 | # @Date: 2020-07-05 15:59:16 4 | # @LastEditors: Rainy 5 | # @LastEditTime: 2020-07-05 15:59:17 6 | ### 7 | 8 | #!/usr/bin/env sh 9 | 10 | # git@github.com:Rain120/vuepress-docs-template.git 11 | 12 | set -e 13 | 14 | if [[ -n "$1" ]];then 15 | 16 | git remote -v 17 | 18 | echo "Old Origin" 19 | 20 | git remote remove origin 21 | 22 | echo "Add origin $1" 23 | 24 | git remote add origin $1 25 | 26 | echo "New Origin" 27 | git remote -v 28 | 29 | else 30 | 31 | echo "Please add the Origin Address" 32 | 33 | fi 34 | -------------------------------------------------------------------------------- /wechat-zhifubao-pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rain120/typescript-guide/90432f8d4e8b7b20a76d678886f7e1075c3ae6ff/wechat-zhifubao-pay.png --------------------------------------------------------------------------------