├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── prettier.config.js ├── src ├── font │ └── Caveat │ │ ├── Caveat-VariableFont_wght.ttf │ │ ├── OFL.txt │ │ ├── README.txt │ │ └── static │ │ ├── Caveat-Bold.ttf │ │ ├── Caveat-Medium.ttf │ │ ├── Caveat-Regular.ttf │ │ └── Caveat-SemiBold.ttf ├── img │ └── note.svg ├── index.ts ├── random.ts ├── style │ ├── main.css │ └── main.scss ├── template.html ├── types │ └── globals.d.ts └── userData.ts ├── tsconfig.json ├── typescript ├── 1.datatypes.ts ├── 2.functions.ts ├── 3.classes-interfaces.ts ├── 3.classes.js ├── 4.narrowing.ts └── 5.generics.ts └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false 13 | max_line_length = 80 -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | webpack.config.js 3 | 4 | # src/*.js 5 | # !src/index.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | node: false 5 | }, 6 | extends: [ 7 | 'eslint:recommended', 8 | 'plugin:unicorn/recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | 'prettier' 11 | ], 12 | globals: {}, 13 | overrides: [], 14 | parser: '@typescript-eslint/parser', 15 | parserOptions: { 16 | ecmaVersion: 'latest', 17 | sourceType: 'module', 18 | ecmaFeatures: { 19 | jsx: true 20 | } 21 | }, 22 | ignorePatterns: [ 23 | '.eslintrc.js', 24 | 'prettier.config.js' 25 | ], 26 | plugins: [ 27 | 'unicorn', 28 | '@typescript-eslint', 29 | 'prettier' 30 | ], 31 | rules: { 32 | '@typescript-eslint/no-inferrable-types': 'off', 33 | 'unicorn/no-null': 'off', 34 | 'prettier/prettier': 'error', 35 | 'arrow-body-style': 'off', 36 | 'prefer-arrow-callback': 'off', 37 | 'no-console': [ 38 | 'error', 39 | { 40 | allow: [ 41 | 'info', 42 | 'error' 43 | ] 44 | } 45 | ], 46 | 'no-var': 'error', 47 | 'no-use-before-define': 'error', 48 | eqeqeq: 'warn', 49 | camelcase: 'error', 50 | 'unicorn/filename-case': 'off' 51 | } 52 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # OS generated files 107 | .DS_Store -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts: 2 | dist 3 | coverage 4 | 5 | # Ignore all HTML files: 6 | # *.html -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // Вариант 1 3 | // "prettier.enable": true, 4 | // "eslint.enable": true, 5 | // "eslint.format.enable": true, 6 | // "eslint.run": "onType", 7 | // "[javascript]": { 8 | // "editor.defaultFormatter": "rvest.vs-code-prettier-eslint", 9 | // "editor.formatOnPaste": false, // required 10 | // "editor.formatOnType": false, // required 11 | // "editor.formatOnSave": true, // optional 12 | // "editor.formatOnSaveMode": "file", // required to format on save 13 | // }, 14 | 15 | // Вариант 2 16 | "eslint.enable": true, 17 | "eslint.format.enable": true, 18 | "eslint.run": "onType", 19 | "eslint.probe": [ 20 | "javascript", 21 | "javascriptreact", 22 | "typescript", 23 | "typescriptreact", 24 | ], 25 | "eslint.rules.customizations": [ 26 | {"rule": "prettier/prettier", "severity": "info"} 27 | ], 28 | "[javascript]": { 29 | "editor.defaultFormatter": "dbaeumer.vscode-eslint", 30 | "editor.formatOnPaste": true, 31 | // "editor.formatOnSave": true, 32 | "editor.codeActionsOnSave": [ "source.fixAll.eslint" ], 33 | }, 34 | "[typescript]": { 35 | "editor.defaultFormatter": "dbaeumer.vscode-eslint", 36 | "editor.formatOnPaste": true, 37 | // "editor.formatOnSave": true, 38 | "editor.codeActionsOnSave": [ "source.fixAll.eslint" ], 39 | }, 40 | 41 | "workbench.colorCustomizations": { 42 | // "editorError.foreground": "#f90000", 43 | "editorInfo.foreground": "#15c804", 44 | "editorWarning.foreground": "#fca80b", 45 | }, 46 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Igor Filimonov 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Файлы проекта 2 | Основные файлы проекта находятся в каталоге `./src`. 3 | Примеры использования Typescript находятся в `./typescript`. 4 | 5 | В файл `.vscode/settings.json` добавлены необходимые настройки `VS Code` для интеграции с ESLint и Prettier. 6 | `Prettier` запускается с помощью плагина [eslint-plugin-prettier](https://www.npmjs.com/package/eslint-plugin-prettier). 7 | 8 | ## Плагин для VS Code 9 | Для подсветки ошибок в IDE во время процесса веб-разработки необходимо дополнительно установить расширение [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) для VS Code. 10 | 11 | ## Установка зависимостей проекта 12 | ```sh 13 | npm install 14 | ``` 15 | 16 | ## Запуск проекта с помощью сервера 17 | ```sh 18 | npm run serve # Development mode only (webpack-dev-server) 19 | ``` 20 | 21 | ## Запуск сборки проекта 22 | ```sh 23 | npm run dev # Development mode 24 | npm run build # Production mode 25 | ``` 26 | 27 | ## Проверка форматирования кода проекта 28 | ```sh 29 | npm run prettier 30 | ``` 31 | 32 | ## Исправление форматирования кода с помощью Prettier 33 | ```sh 34 | npm run prettier:fix 35 | ``` 36 | 37 | ## Проверка качества кода с помощью ESLint 38 | ```sh 39 | npm run lint 40 | ``` 41 | 42 | ## Исправление кода с использованием ESLint и Prettier 43 | ```sh 44 | npm run lint:fix 45 | ``` 46 | 47 | ## Лицензия 48 | ![GitHub](https://img.shields.io/github/license/iwebexpert/js-middle-typescript) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-middle-typescript", 3 | "version": "1.0.0", 4 | "description": "Web application using TypeScript", 5 | "main": "./src/index.ts", 6 | "scripts": { 7 | "prettier": "prettier --write ./src/**/*.ts", 8 | "prettier:check": "prettier --check ./src/**/*.ts", 9 | "lint": "eslint . --ext .ts", 10 | "lint:fix": "eslint --fix . --ext .ts", 11 | "build": "webpack --mode production --node-env=production", 12 | "dev": "webpack --mode development --node-env=development", 13 | "watch": "webpack --watch --mode development --node-env=development", 14 | "serve": "webpack serve --mode development --node-env=development", 15 | "test": "echo \"Error: no test specified\" && exit 1" 16 | }, 17 | "keywords": [], 18 | "author": "Igor Filimonov", 19 | "license": "MIT", 20 | "private": true, 21 | "bugs": { 22 | "url": "https://github.com/iwebexpert/js-middle-typescript/issues" 23 | }, 24 | "homepage": "https://github.com/iwebexpert/js-middle-typescript#readme", 25 | "devDependencies": { 26 | "@babel/core": "^7.20.12", 27 | "@babel/eslint-parser": "^7.19.1", 28 | "@babel/preset-env": "^7.20.2", 29 | "@typescript-eslint/eslint-plugin": "^5.53.0", 30 | "@typescript-eslint/parser": "^5.53.0", 31 | "babel-loader": "^9.1.2", 32 | "clean-webpack-plugin": "^4.0.0", 33 | "css-loader": "^6.7.3", 34 | "eslint": "^8.33.0", 35 | "eslint-config-prettier": "^8.6.0", 36 | "eslint-plugin-prettier": "^4.2.1", 37 | "eslint-plugin-unicorn": "^45.0.2", 38 | "eslint-webpack-plugin": "^4.0.0", 39 | "html-webpack-plugin": "^5.5.0", 40 | "mini-css-extract-plugin": "^2.7.2", 41 | "prettier": "2.8.3", 42 | "sass": "^1.57.1", 43 | "sass-loader": "^13.2.0", 44 | "style-loader": "^3.3.1", 45 | "ts-loader": "^9.4.2", 46 | "typescript": "^4.9.5", 47 | "webpack": "^5.75.0", 48 | "webpack-bundle-analyzer": "^4.7.0", 49 | "webpack-cli": "^5.0.1", 50 | "webpack-dev-server": "^4.11.1" 51 | }, 52 | "dependencies": { 53 | "axios": "^1.2.3" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'es5', // es5, all, none 3 | // tabWidth: 2, 4 | // useTabs: false, 5 | // printWidth: 80, 6 | semi: false, 7 | singleQuote: true, 8 | bracketSpacing: true, 9 | arrowParens: 'always', // always, avoid 10 | // endOfLine: 'lf', // lf, crlf, cr, auto 11 | 12 | // requirePragma: true, 13 | // insertPragma: true, 14 | 15 | // HTML, Vue, JSX 16 | singleAttributePerLine: true, 17 | bracketSameLine: false, 18 | } 19 | -------------------------------------------------------------------------------- /src/font/Caveat/Caveat-VariableFont_wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwebexpert/js-middle-typescript/9a85d640a177cafbc370f1a30ee9b56dd8cda021/src/font/Caveat/Caveat-VariableFont_wght.ttf -------------------------------------------------------------------------------- /src/font/Caveat/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2014 The Caveat Project Authors (https://github.com/googlefonts/caveat) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /src/font/Caveat/README.txt: -------------------------------------------------------------------------------- 1 | Caveat Variable Font 2 | ==================== 3 | 4 | This download contains Caveat as both a variable font and static fonts. 5 | 6 | Caveat is a variable font with this axis: 7 | wght 8 | 9 | This means all the styles are contained in a single file: 10 | Caveat-VariableFont_wght.ttf 11 | 12 | If your app fully supports variable fonts, you can now pick intermediate styles 13 | that aren’t available as static fonts. Not all apps support variable fonts, and 14 | in those cases you can use the static font files for Caveat: 15 | static/Caveat-Regular.ttf 16 | static/Caveat-Medium.ttf 17 | static/Caveat-SemiBold.ttf 18 | static/Caveat-Bold.ttf 19 | 20 | Get started 21 | ----------- 22 | 23 | 1. Install the font files you want to use 24 | 25 | 2. Use your app's font picker to view the font family and all the 26 | available styles 27 | 28 | Learn more about variable fonts 29 | ------------------------------- 30 | 31 | https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts 32 | https://variablefonts.typenetwork.com 33 | https://medium.com/variable-fonts 34 | 35 | In desktop apps 36 | 37 | https://theblog.adobe.com/can-variable-fonts-illustrator-cc 38 | https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts 39 | 40 | Online 41 | 42 | https://developers.google.com/fonts/docs/getting_started 43 | https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide 44 | https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts 45 | 46 | Installing fonts 47 | 48 | MacOS: https://support.apple.com/en-us/HT201749 49 | Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux 50 | Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows 51 | 52 | Android Apps 53 | 54 | https://developers.google.com/fonts/docs/android 55 | https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts 56 | 57 | License 58 | ------- 59 | Please read the full license text (OFL.txt) to understand the permissions, 60 | restrictions and requirements for usage, redistribution, and modification. 61 | 62 | You can use them in your products & projects – print or digital, 63 | commercial or otherwise. 64 | 65 | This isn't legal advice, please consider consulting a lawyer and see the full 66 | license for all details. 67 | -------------------------------------------------------------------------------- /src/font/Caveat/static/Caveat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwebexpert/js-middle-typescript/9a85d640a177cafbc370f1a30ee9b56dd8cda021/src/font/Caveat/static/Caveat-Bold.ttf -------------------------------------------------------------------------------- /src/font/Caveat/static/Caveat-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwebexpert/js-middle-typescript/9a85d640a177cafbc370f1a30ee9b56dd8cda021/src/font/Caveat/static/Caveat-Medium.ttf -------------------------------------------------------------------------------- /src/font/Caveat/static/Caveat-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwebexpert/js-middle-typescript/9a85d640a177cafbc370f1a30ee9b56dd8cda021/src/font/Caveat/static/Caveat-Regular.ttf -------------------------------------------------------------------------------- /src/font/Caveat/static/Caveat-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwebexpert/js-middle-typescript/9a85d640a177cafbc370f1a30ee9b56dd8cda021/src/font/Caveat/static/Caveat-SemiBold.ttf -------------------------------------------------------------------------------- /src/img/note.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import updateUser from './userData' 2 | import './style/main.scss' 3 | 4 | import noteImg from './img/note.svg' 5 | 6 | // const mainImg = document.querySelector('.main-img') 7 | const mainImg = document.querySelector('.main-img') as HTMLImageElement | null 8 | if (mainImg) { 9 | mainImg.src = noteImg 10 | } 11 | 12 | const mainButton = document.querySelector('.main-btn') 13 | if (mainButton) { 14 | mainButton.addEventListener('click', updateUser) 15 | } 16 | 17 | updateUser() 18 | -------------------------------------------------------------------------------- /src/random.ts: -------------------------------------------------------------------------------- 1 | export function getRandomInt(min: number, max: number): number { 2 | min = Math.ceil(min) 3 | max = Math.floor(max) 4 | 5 | // debugger 6 | return Math.floor(Math.random() * (max - min + 1)) + min 7 | } 8 | -------------------------------------------------------------------------------- /src/style/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: brown; 3 | } -------------------------------------------------------------------------------- /src/style/main.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Caveat'; 3 | src: url('../font/Caveat/Caveat-VariableFont_wght.ttf') format('truetype'); 4 | font-weight: 400; 5 | font-style: normal; 6 | } 7 | 8 | $bg-color: #66ba7c; 9 | $page-color: #eeecec; 10 | $box-shadow: 0 12px 20px rgba(0, 0, 0, 0.15), 0 8px 8px rgba(0, 0, 0, 0.15); 11 | 12 | 13 | body { 14 | background-color: $bg-color; 15 | font-family: 'Caveat', sans-serif; 16 | display: flex; 17 | align-items: center; 18 | justify-content: center; 19 | height: 100vh; 20 | // overflow: hidden; 21 | padding: 30px; 22 | margin: 0; 23 | box-sizing: border-box; 24 | } 25 | 26 | .container { 27 | width: 768px; 28 | background-color: $page-color; 29 | box-shadow: $box-shadow; 30 | border-radius: 10px; 31 | padding: 40px 15px; 32 | text-align: center; 33 | } 34 | 35 | img.main-img { 36 | width: 108px; 37 | margin-bottom: 25px; 38 | } 39 | 40 | .header { 41 | font-size: 24px; 42 | color: #999; 43 | letter-spacing: 2px; 44 | } 45 | 46 | .user-info { 47 | font-size: 28px; 48 | letter-spacing: 1.5px; 49 | margin: 25px auto; 50 | } 51 | 52 | .main-btn { 53 | margin-top: 30px; 54 | background-color: $bg-color; 55 | color: $page-color; 56 | border: 0; 57 | border-radius: 12px; 58 | padding: 12px 35px; 59 | font-size: 18px; 60 | cursor: pointer; 61 | 62 | &:hover { 63 | transform: scale(1.05); 64 | } 65 | } -------------------------------------------------------------------------------- /src/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 13 | <%= htmlWebpackPlugin.options.title %> 14 | 15 | 16 |
17 | 21 | 22 |
Имя пользователя
23 | 24 | 25 |
Сумма
26 | 27 | 28 |
E-mail
29 | 30 | 31 | 32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /src/types/globals.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const content: string 3 | export default content 4 | } 5 | -------------------------------------------------------------------------------- /src/userData.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { getRandomInt } from './random' 3 | 4 | interface IView { 5 | name: string 6 | amount: number 7 | email: string 8 | } 9 | 10 | function updateView(data: IView): void { 11 | const elementName = document.querySelector('.user-name') 12 | if (elementName) { 13 | elementName.textContent = data.name 14 | } 15 | 16 | const elementAmount = document.querySelector('.user-amount') 17 | if (elementAmount) { 18 | elementAmount.innerHTML = data.amount + ' ₽' 19 | } 20 | 21 | const elementEmail = document.querySelector('.user-email') 22 | if (elementEmail) { 23 | elementEmail.textContent = data.email 24 | } 25 | } 26 | 27 | function updateUser() { 28 | // fetch(`https://jsonplaceholder.typicode.com/users/${getRandomInt(1, 10)}`) 29 | // .then((result) => result.json()) 30 | // .then((result) => { 31 | // updateView({ 32 | // name: result.name, 33 | // amount: getRandomInt(1000, 10_000), 34 | // email: result.email, 35 | // }) 36 | // }) 37 | 38 | axios 39 | .get(`https://jsonplaceholder.typicode.com/users/${getRandomInt(1, 10)}`) 40 | .then((result) => { 41 | updateView({ 42 | name: result.data.name, 43 | amount: getRandomInt(1000, 10_000), 44 | email: result.data.email, 45 | }) 46 | }) 47 | } 48 | 49 | export default updateUser 50 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | // "rootDir": "./src", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "resolveJsonModule": true, /* Enable importing .json files. */ 39 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 40 | 41 | /* JavaScript Support */ 42 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 43 | // "checkJs": false, /* Enable error reporting in type-checked JavaScript files. */ 44 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 45 | 46 | /* Emit */ 47 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 48 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 49 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 50 | "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 51 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 52 | // "outDir": "./dist", /* Specify an output folder for all emitted files. */ 53 | // "removeComments": true, /* Disable emitting comments. */ 54 | // "noEmit": true, /* Disable emitting files from a compilation. */ 55 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 56 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 57 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 58 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 59 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 60 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 61 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 62 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 63 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 64 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 65 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 66 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 67 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 68 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 69 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 70 | 71 | /* Interop Constraints */ 72 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 73 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 74 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 75 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 76 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 77 | 78 | /* Type Checking */ 79 | "strict": true, /* Enable all strict type-checking options. */ 80 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 81 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 82 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 83 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 84 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 85 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 86 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 87 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 88 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 89 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 90 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 91 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 92 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 93 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 94 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 95 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 96 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 97 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 98 | 99 | /* Completeness */ 100 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 101 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /typescript/1.datatypes.ts: -------------------------------------------------------------------------------- 1 | // Базовые типы данных 2 | const userName: string = 'Olga' 3 | const userAge: number = 28 4 | const userAccount: bigint = BigInt(255) 5 | // const userAccount: bigint = 255n // ES2020+ 6 | 7 | const isNull: null = null 8 | const isUndefined: undefined = undefined 9 | 10 | const isAdmin: boolean = true 11 | 12 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 13 | const userTest: any = [] 14 | 15 | console.info( 16 | userName, 17 | userAge, 18 | userAccount, 19 | isNull, 20 | isUndefined, 21 | isAdmin, 22 | userTest 23 | ) 24 | 25 | // Массивы и кортежи 26 | const arrayNums: number[] = [1, 2, 3] 27 | const arrayBoolean: boolean[] = [true, false, true] 28 | const arrayBoolean2: Array = [true, false, true] 29 | const arrayNumsAndStrings: (number | string)[] = [1, '2', 3, '4'] 30 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 31 | const arrayAny: any[] = [1, true, 'Oleg'] 32 | 33 | const arrayUser1: [number, boolean, string] = [1, true, 'Oleg'] 34 | arrayUser1[0] = 10 35 | arrayUser1[1] = false 36 | arrayUser1[2] = 'Олег' 37 | 38 | console.info( 39 | arrayNums, 40 | arrayBoolean, 41 | arrayBoolean2, 42 | arrayNumsAndStrings, 43 | arrayAny, 44 | arrayUser1 45 | ) 46 | 47 | // Объединения и перечисления (Enums) 48 | // Пример 1 49 | function myId(id: number | string) { 50 | if (typeof id === 'string') { 51 | console.info(id.toLocaleLowerCase()) 52 | } else { 53 | console.info(id) 54 | } 55 | } 56 | 57 | myId('5') 58 | myId(5) 59 | myId('Test') 60 | 61 | // Пример 2 62 | function printColors(color: string | string[]) { 63 | if (Array.isArray(color)) { 64 | console.info('Цвета: ' + color.join(' и ')) 65 | } else { 66 | console.info('Цвет: ' + color) 67 | } 68 | } 69 | 70 | printColors('красный') 71 | printColors(['красный', 'белый']) 72 | 73 | // Пример 3 74 | function getItemFirst(items: number[] | string) { 75 | return items.slice(0, 1) 76 | } 77 | 78 | console.info(getItemFirst([1, 2, 3, 4])) 79 | console.info(getItemFirst('Test')) 80 | 81 | // Перечисления 82 | const ANSWER_YES = 'YES' 83 | 84 | // Пример 1 85 | enum Answer { 86 | Yes = 'YES', 87 | No = 'NO', 88 | // No = '1234'.length, 89 | } 90 | 91 | console.info(ANSWER_YES, Answer.Yes, Answer.No) 92 | 93 | // Пример 2 94 | enum FileAccess { 95 | // Read = 2, 96 | // Write = 4, 97 | Read = 1 << 1, 98 | Write = 1 << 2, 99 | ReadWrite = Read | Write, 100 | } 101 | 102 | console.info(FileAccess.Read, FileAccess.Write, FileAccess.ReadWrite) 103 | 104 | // Псевдонимы типов данных (пользовательские типы данных) 105 | type BasePoint = { 106 | x: number 107 | y: number 108 | } 109 | const point1: BasePoint = { 110 | x: 10, 111 | y: 10, 112 | } 113 | 114 | function printPointCoords(point: BasePoint) { 115 | console.info(`x=${point.x}; y=${point.y}`) 116 | } 117 | 118 | console.info(point1) 119 | printPointCoords(point1) 120 | 121 | type FullPoint = BasePoint & { 122 | readonly title: string 123 | description?: string 124 | } 125 | 126 | const point2: FullPoint = { 127 | x: 100, 128 | y: 100, 129 | title: 'point2', 130 | description: 'Описание point2', 131 | } 132 | 133 | // point2.title = 'Test' 134 | 135 | console.info(point2) 136 | -------------------------------------------------------------------------------- /typescript/2.functions.ts: -------------------------------------------------------------------------------- 1 | // Базовая работа с функциями 2 | console.info('Базовая работа с функциями') 3 | function plus(x: number = 1, y?: number): number { 4 | return x + (y || 1) 5 | } 6 | 7 | console.info(plus(10, 20)) 8 | console.info(plus()) 9 | 10 | function printNumber(x: number): void { 11 | console.info(`x=${x}`) 12 | } 13 | 14 | printNumber(10) 15 | 16 | // Остаточные параметры (rest parameters) 17 | function multiply(m: number, ...parameters: number[]) { 18 | // console.info(parameters) 19 | return parameters.map(function (item) { 20 | return m * item 21 | }) 22 | } 23 | 24 | console.info(multiply(100, 1, 10, 20, 50)) 25 | 26 | // Деструктуризация параметров (parameter destructuring) 27 | type PlusParameters = { 28 | x: number 29 | y: number 30 | } 31 | function plus2({ x = 1, y }: { x: number; y: number }): number { 32 | return x + (y || 1) 33 | } 34 | 35 | console.info(plus2({ x: 10, y: 20 })) 36 | 37 | function plus3({ x = 1, y }: PlusParameters): number { 38 | return x + (y || 1) 39 | } 40 | 41 | console.info(plus3({ x: 10, y: 20 })) 42 | 43 | function plus4(items: PlusParameters): number { 44 | return items.x + (items.y || 1) 45 | } 46 | 47 | console.info(plus4({ x: 10, y: 20 })) 48 | 49 | // Тип возвращаемого значения Never 50 | function getMessage(message: string): never { 51 | // while (true) {} 52 | throw new Error(message) 53 | } 54 | 55 | try { 56 | getMessage('Error 1234') 57 | } catch (error) { 58 | if (error instanceof Error) { 59 | console.info(error.message) 60 | } 61 | 62 | console.info((error as Error).message) 63 | console.info((error).message) 64 | } finally { 65 | console.info('finally') 66 | } 67 | 68 | // Функции обратного вызова. Стрелочные функции 69 | function printMessage(callback: (message: string) => void) { 70 | callback('Привет!') 71 | } 72 | 73 | function callback1(text: string) { 74 | console.info(text) 75 | } 76 | 77 | printMessage(callback1) 78 | 79 | // Стрелочные функции 80 | const callback2 = (text: string): void => console.info(text) 81 | printMessage(callback2) 82 | 83 | printMessage((text) => console.info(text)) 84 | 85 | type CallbackParameters = { 86 | (text: string): void 87 | } 88 | 89 | const callback3: CallbackParameters = (text) => console.info(text) 90 | printMessage(callback3) 91 | 92 | // Перегрузка функций 93 | // Сигнатуры перегрузки 94 | function createDate(timestamp: number): Date 95 | function createDate(timestamp: number, month: number, year: number): Date 96 | // Сигнатура реализации 97 | function createDate( 98 | dayOrTimestamp: number, 99 | month?: number, 100 | year?: number 101 | ): Date { 102 | return month !== undefined && year !== undefined 103 | ? new Date(year, month, dayOrTimestamp) 104 | : new Date(dayOrTimestamp * 1000) 105 | } 106 | 107 | console.info(createDate(1_677_935_727)) 108 | console.info(createDate(5, 2, 2023)) 109 | // console.info(createDate(5, 2)) 110 | 111 | // Перегрузка стрелочных функций 112 | type CreateDate = { 113 | (timestamp: number): Date 114 | (timestamp: number, month: number, year: number): Date 115 | } 116 | const createDate2: CreateDate = ( 117 | dayOrTimestamp: number, 118 | month?: number, 119 | year?: number 120 | ): Date => { 121 | return month !== undefined && year !== undefined 122 | ? new Date(year, month, dayOrTimestamp) 123 | : new Date(dayOrTimestamp * 1000) 124 | } 125 | 126 | console.info(createDate2(1_677_935_727)) 127 | console.info(createDate2(5, 2, 2023)) 128 | // console.info(createDate2(5, 2)) 129 | -------------------------------------------------------------------------------- /typescript/3.classes-interfaces.ts: -------------------------------------------------------------------------------- 1 | // Классы в TypeScript 2 | console.info('Классы в TypeScript') 3 | abstract class Figure { 4 | info() { 5 | console.info('Это метод info() класса Figure') 6 | } 7 | abstract printInfo(isShow: boolean): string 8 | } 9 | 10 | // abstract class Figure2 extends Figure { 11 | // abstract printInfo2(isShow: boolean): string 12 | // } 13 | 14 | // const figure1 = new Figure() 15 | // figure1.info() 16 | 17 | class Circle extends Figure { 18 | private radius: number = 25 19 | public static readonly PI: number = 3.14 20 | public setRadius(radius: number): void { 21 | if (radius > 0) { 22 | this.radius = radius 23 | } 24 | } 25 | 26 | public getRadius() { 27 | return this.radius 28 | } 29 | 30 | info() { 31 | console.info('Это метод info() класса Circle') 32 | super.info() 33 | } 34 | 35 | printInfo(isShow: boolean = false): string { 36 | const message = `Радиус круга равен ${this.radius}` 37 | if (isShow) { 38 | console.info(message) 39 | } 40 | 41 | return message 42 | } 43 | } 44 | 45 | interface IRect { 46 | width: number 47 | info(): void 48 | printInfo(isShow: boolean): string 49 | } 50 | 51 | // interface IRect { 52 | // title: string 53 | // } 54 | 55 | interface IRectTitle extends IRect { 56 | title: string 57 | } 58 | 59 | interface IRect2 { 60 | readonly description: string 61 | } 62 | 63 | // type ExamleType = { 64 | // title: string 65 | // } 66 | 67 | // type ExamleType2 = ExamleType & { 68 | // description: string 69 | // } 70 | 71 | // type ExamleType3 = string 72 | 73 | class Rect extends Figure implements IRectTitle, IRect2 { 74 | public width: number 75 | protected height: number 76 | title: string = 'Название прямоугольника' 77 | description: string = 'Описание прямоугольника' 78 | constructor(width: number, height: number) { 79 | super() 80 | this.width = width 81 | this.height = height 82 | } 83 | 84 | info() { 85 | console.info('Это метод info() класса Rect') 86 | super.info() 87 | } 88 | 89 | printInfo(isShow: boolean = false): string { 90 | const message = `Ширина фигуры равна ${this.width}, высота ${this.height}` 91 | if (isShow) { 92 | console.info(message) 93 | } 94 | 95 | return message 96 | } 97 | } 98 | 99 | class Square extends Rect { 100 | constructor(side: number) { 101 | super(side, side) 102 | 103 | // this.height = 2000 104 | // this.width = 20 105 | } 106 | 107 | info() { 108 | console.info('Это метод info() класса Square') 109 | super.info() 110 | } 111 | } 112 | 113 | const circle1 = new Circle() 114 | circle1.info() 115 | console.info('Radius=' + circle1.getRadius()) 116 | circle1.setRadius(200) 117 | console.info('Radius=' + circle1.getRadius()) 118 | circle1.printInfo(true) 119 | console.info(Circle.PI) 120 | // Circle.PI = 3.1415 121 | console.info(Circle.PI) 122 | 123 | const rect1 = new Rect(200, 100) 124 | rect1.info() 125 | rect1.printInfo(true) 126 | 127 | const square1 = new Square(500) 128 | square1.info() 129 | console.info(square1.printInfo()) 130 | 131 | // Интерфейсы для объектов, массивов и функций 132 | interface IRectItem { 133 | readonly width: number 134 | readonly height: number 135 | printInfo(isShow?: boolean): string 136 | } 137 | 138 | const rect2: IRectItem = { 139 | width: 100, 140 | height: 120, 141 | printInfo(isShow: boolean = false) { 142 | const message = `Ширина фигуры равна ${this.width}, высота ${this.height}` 143 | if (isShow) { 144 | console.info(message) 145 | } 146 | 147 | return message 148 | }, 149 | } 150 | 151 | console.info(rect2, rect2.printInfo()) 152 | 153 | interface DictionaryColor { 154 | [index: string]: string 155 | } 156 | 157 | const color1: DictionaryColor = {} 158 | color1['red'] = 'Красный' 159 | color1['blue'] = 'Синий' 160 | console.info(color1, color1['red']) 161 | 162 | interface DictionaryColor2 { 163 | [index: number]: string 164 | } 165 | 166 | const color2: DictionaryColor2[] = [] 167 | color2[0] = 'Красный' 168 | color2[1] = 'Синий' 169 | color2.push('Белый') 170 | console.info(color2, color2[1]) 171 | 172 | const color3: string[] = [] 173 | color3.push('Белый') 174 | console.info(color3) 175 | 176 | interface IUserBuilder { 177 | (name: string, age: number): string 178 | (name: string, age: number, department: string): string 179 | } 180 | 181 | const createUser: IUserBuilder = (name, age, department = '') => 182 | `Пользователь ${name}; возраст ${age}; ${department}` 183 | 184 | console.info(createUser('Иван', 30)) 185 | console.info(createUser('Иван', 30, 'Front-end')) -------------------------------------------------------------------------------- /typescript/3.classes.js: -------------------------------------------------------------------------------- 1 | class User { 2 | #name = 'Olga' 3 | age = 28 4 | static PI = 3.14 5 | getName() { 6 | return this.#name 7 | } 8 | 9 | static info() { 10 | return new Date() 11 | } 12 | } 13 | 14 | // const user1 = new User() 15 | // user1.getName() 16 | console.info(User.PI) 17 | console.info(User.info()) 18 | -------------------------------------------------------------------------------- /typescript/4.narrowing.ts: -------------------------------------------------------------------------------- 1 | // Что такое Narrowing 2 | console.info('Что такое Narrowing') 3 | // Пример 1 4 | function getId(id: number | string) { 5 | if (typeof id === 'string') { 6 | console.info(id.toLocaleLowerCase()) 7 | } else { 8 | console.info(id) 9 | } 10 | } 11 | 12 | getId('5') 13 | getId(5) 14 | getId('Test') 15 | 16 | // Пример 2 17 | function showAllColors(colors: string | string[] | null) { 18 | if (colors && typeof colors === 'object') { 19 | for (const s of colors) { 20 | console.info(s) 21 | } 22 | } else if (typeof colors === 'string') { 23 | console.info(colors) 24 | } 25 | } 26 | 27 | console.info(typeof null, typeof {}) 28 | showAllColors(['red', 'blue']) 29 | showAllColors('red') 30 | showAllColors(null) 31 | 32 | // Пример 3 33 | function showAllColors2(colors: string | string[] | null) { 34 | if (colors !== null) { 35 | if (typeof colors === 'object') { 36 | for (const s of colors) { 37 | console.info(s) 38 | } 39 | } else if (typeof colors === 'string') { 40 | console.info(colors) 41 | } 42 | } 43 | } 44 | 45 | showAllColors2(['red', 'blue']) 46 | showAllColors2('red') 47 | showAllColors2(null) 48 | 49 | // Пример 4 50 | interface MultiplyParameters { 51 | value: number | null | undefined 52 | } 53 | function multiply2(object: MultiplyParameters, n: number) { 54 | // eslint-disable-next-line eqeqeq 55 | if (object.value != null) { 56 | console.info(object.value) 57 | object.value *= n 58 | console.info(object.value) 59 | } 60 | } 61 | 62 | multiply2({ value: 10 }, 2) 63 | // eslint-disable-next-line eqeqeq 64 | console.info(null == undefined, null === undefined) 65 | 66 | // Сужение типов с помощью оператора in и instanceof 67 | type Fish = { swim: () => void; title: string } 68 | type Bird = { fly: () => void; title: string } 69 | 70 | function go(animal: Fish | Bird) { 71 | if ('swim' in animal) { 72 | return animal.swim() 73 | } 74 | return animal.fly() 75 | } 76 | 77 | const fish1: Fish | Bird = { 78 | title: 'fish1', 79 | swim() { 80 | console.info('Рыба плывет') 81 | }, 82 | } 83 | 84 | console.info(go(fish1)) 85 | 86 | // instanceof 87 | function writeToLog(value: Date | string) { 88 | if (value instanceof Date) { 89 | console.info(value.toUTCString()) 90 | } else { 91 | console.info(value.toUpperCase()) 92 | } 93 | } 94 | 95 | writeToLog(new Date()) 96 | writeToLog('Test') 97 | 98 | // Присвоения. Анализ потока управления 99 | let userId = Math.random() < 0.5 ? 1 : 'One' 100 | 101 | userId = 2 102 | console.info(userId) 103 | 104 | userId = 'two' 105 | console.info(userId) 106 | 107 | // userId = true // Error 108 | 109 | function test() { 110 | let id: string | number | boolean 111 | 112 | id = Math.random() < 0.5 113 | console.info(id) 114 | 115 | if (id) { 116 | id = 'One' 117 | console.info(id) 118 | } else { 119 | id = 1 120 | console.info(id) 121 | } 122 | 123 | return id 124 | } 125 | 126 | let userId2 = test() 127 | userId2 = 2 128 | console.info(userId2) 129 | 130 | userId2 = 'two' 131 | console.info(userId2) 132 | 133 | // userId2 = true // Error 134 | 135 | // Пользовательские защитники типов 136 | function isFish(pet: Fish | Bird): pet is Fish { 137 | return (pet as Fish).swim !== undefined 138 | } 139 | 140 | function getFishOrBird(): Fish | Bird { 141 | const fish: Fish = { 142 | title: `fish ${Math.random()}`, 143 | swim() { 144 | console.info('Рыба плывет') 145 | }, 146 | } 147 | 148 | const bird: Bird = { 149 | title: `bird ${Math.random()}`, 150 | fly() { 151 | console.info('Птица летит') 152 | }, 153 | } 154 | 155 | return Math.random() < 0.5 ? fish : bird 156 | } 157 | 158 | const pet = getFishOrBird() 159 | 160 | if (isFish(pet)) { 161 | pet.swim() 162 | } else { 163 | pet.fly() 164 | } 165 | 166 | const pets: (Fish | Bird)[] = [ 167 | getFishOrBird(), 168 | getFishOrBird(), 169 | getFishOrBird(), 170 | getFishOrBird(), 171 | getFishOrBird(), 172 | getFishOrBird(), 173 | getFishOrBird(), 174 | ] 175 | 176 | // eslint-disable-next-line unicorn/no-array-callback-reference 177 | const fishOnly: Fish[] = pets.filter(isFish) 178 | console.info(fishOnly) 179 | 180 | const fishOnly2: Fish[] = pets.filter((element) => isFish(element)) as Fish[] 181 | console.info(fishOnly2) 182 | 183 | // Более сложный случай 184 | const fishTitleItem1 = fishOnly2[0]?.title || 'fish1' 185 | console.info(fishTitleItem1) 186 | const fishOnly3: Fish[] = pets.filter((pet): pet is Fish => { 187 | // Пользовательские условия поиска 188 | if (pet.title === fishTitleItem1) return false 189 | return isFish(pet) 190 | }) 191 | console.info(fishOnly3) 192 | 193 | // Исключающие объединения 194 | // interface Figure { 195 | // type: 'circle' | 'square' 196 | // radius?: number 197 | // side?: number 198 | // } 199 | 200 | // function getArea(figure: Figure) { 201 | // if (figure.type === 'circle') { 202 | // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 203 | // return Math.PI * figure.radius! ** 2 204 | // } 205 | // } 206 | 207 | interface FigureCircle { 208 | type: 'circle' 209 | radius: number 210 | } 211 | 212 | interface FigureSquare { 213 | type: 'square' 214 | side: number 215 | } 216 | 217 | interface FigureRect { 218 | type: 'rect' 219 | width: number 220 | height: number 221 | } 222 | 223 | type MyFigure = FigureCircle | FigureSquare | FigureRect 224 | 225 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 226 | function getArea(figure: MyFigure) { 227 | if (figure.type === 'circle') { 228 | return Math.PI * figure.radius ** 2 229 | } 230 | } 231 | 232 | function getArea2(figure: MyFigure) { 233 | switch (figure.type) { 234 | case 'circle': { 235 | return Math.PI * figure.radius ** 2 236 | } 237 | case 'square': { 238 | return figure.side ** 2 239 | } 240 | case 'rect': { 241 | return figure.width * figure.height 242 | } 243 | default: { 244 | const _check: never = figure 245 | return _check 246 | } 247 | } 248 | } 249 | 250 | const figure1: FigureCircle = { 251 | type: 'circle', 252 | radius: 10, 253 | } 254 | console.info(getArea2(figure1)) 255 | -------------------------------------------------------------------------------- /typescript/5.generics.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | // Введение в Дженерики 3 | console.info('Введение в Дженерики') 4 | 5 | function searchString(array: string[], query: string): boolean { 6 | for (const value of array) { 7 | if (value === query) { 8 | return true 9 | } 10 | } 11 | return false 12 | } 13 | 14 | function searchNumber(array: number[], query: number): boolean { 15 | for (const value of array) { 16 | if (value === query) { 17 | return true 18 | } 19 | } 20 | return false 21 | } 22 | 23 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 24 | function searchAny(array: any[], query: any): boolean { 25 | for (const value of array) { 26 | if (value === query) { 27 | return true 28 | } 29 | } 30 | return false 31 | } 32 | 33 | searchAny(['Test', 1234, undefined, {}], 'Test') 34 | 35 | function search(array: T[], query: T): boolean { 36 | for (const value of array) { 37 | if (value === query) { 38 | return true 39 | } 40 | } 41 | return false 42 | } 43 | 44 | console.info(search(['Test', 'Red'], 'Test')) 45 | console.info(search([1, 2], 3)) 46 | 47 | console.info(search([1, 2], 3)) 48 | 49 | // Необходимо указание типов данных 50 | function swapExample(a: T, b: T): void { 51 | const temporary = a 52 | a = b 53 | b = temporary 54 | } 55 | 56 | const userInfoA: number = 1 57 | const userInfoB: string = 'One' 58 | swapExample(userInfoA, userInfoB) 59 | 60 | // Дженерики. Типы и интерфейсы 61 | type CartInfo = { 62 | id: number 63 | products: string[] 64 | currency: T 65 | } 66 | 67 | const cart1: CartInfo = { 68 | id: 1, 69 | products: [], 70 | currency: 1, 71 | } 72 | console.info(cart1) 73 | 74 | const cart2: CartInfo = { 75 | id: 1, 76 | products: [], 77 | currency: 'Ruble', 78 | } 79 | console.info(cart2) 80 | 81 | interface ICartInfo { 82 | id: number 83 | products: string[] 84 | currency: T 85 | } 86 | 87 | const cart3: ICartInfo = { 88 | id: 1, 89 | products: [], 90 | currency: 1, 91 | } 92 | console.info(cart3) 93 | 94 | const cart4: ICartInfo = { 95 | id: 1, 96 | products: [], 97 | currency: 'Ruble', 98 | } 99 | console.info(cart4) 100 | 101 | // Оператор keyof 102 | interface IUser { 103 | name: string 104 | age: number 105 | } 106 | 107 | type UserKeys = keyof IUser 108 | 109 | const userName2: UserKeys = 'name' 110 | console.info(userName2) 111 | 112 | const user = { 113 | name: 'Иван', 114 | age: 30, 115 | department: 'Front-end', 116 | } 117 | 118 | type UserKeys2 = keyof typeof user 119 | 120 | // eslint-disable-next-line unicorn/no-array-for-each 121 | Object.keys(user).forEach((key) => { 122 | console.info(user[key as UserKeys2]) 123 | console.info(user[key]) 124 | }) 125 | 126 | interface ObjectConstructor { 127 | keys(o: T): (keyof T)[] 128 | } 129 | 130 | for (const key of Object.keys(user)) { 131 | console.info(user[key]) 132 | } 133 | 134 | // Дженерики и Классы 135 | // Пример 1 136 | interface ICheckId { 137 | getId(): T 138 | } 139 | 140 | class CheckId implements ICheckId { 141 | constructor(private readonly id: T) { 142 | this.id = id 143 | } 144 | 145 | getId(): T { 146 | return this.id 147 | } 148 | } 149 | 150 | const checkId = new CheckId(1) 151 | console.info(checkId) 152 | 153 | // Пример 2 154 | class Queue { 155 | private data: T[] = [] 156 | 157 | public push = (item: T) => this.data.push(item) 158 | public pop = (): T | undefined => this.data.shift() 159 | } 160 | 161 | const queue1 = new Queue() 162 | queue1.push(1) 163 | console.info(queue1.pop()) 164 | queue1.push(2) 165 | console.info(queue1.pop()) 166 | 167 | // Ограничения Дженериков 168 | // Пример 1 169 | interface ILength { 170 | length: number 171 | } 172 | 173 | function getLength(value: T): number { 174 | return value.length 175 | } 176 | 177 | console.info(getLength(['Красный', 'Синий'])) 178 | console.info(getLength('Красный')) 179 | // console.info(getLength(1)) 180 | 181 | // Пример 2 182 | function getValueOfObject(object: T, key: K): T[K] { 183 | return object[key] 184 | } 185 | 186 | console.info(getValueOfObject(user, 'name')) 187 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const HtmlWebpackPlugin = require('html-webpack-plugin') 3 | const MiniCssExtractPlugin = require("mini-css-extract-plugin") 4 | // const { CleanWebpackPlugin } = require('clean-webpack-plugin') 5 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 6 | const ESLintPlugin = require('eslint-webpack-plugin') 7 | const isProduction = process.env.NODE_ENV === 'production' 8 | // console.log('isProduction', isProduction) 9 | 10 | const styleLoaderHandler = isProduction ? MiniCssExtractPlugin.loader : 'style-loader' 11 | 12 | module.exports = { 13 | // mode: 'production', 14 | entry: path.resolve(__dirname, 'src', 'index.ts'), 15 | // entry: path.resolve(__dirname, 'typescript', '5.generics.ts'), 16 | output: { 17 | path: path.resolve(__dirname, 'dist'), 18 | filename: '[name][contenthash].js', 19 | clean: true, 20 | assetModuleFilename: 'assets/[name][hash][ext]' 21 | }, 22 | resolve: { 23 | // Add `.ts` and `.tsx` as a resolvable extension. 24 | extensions: [".ts", ".tsx", ".js"], 25 | // Add support for TypeScripts fully qualified ESM imports. 26 | extensionAlias: { 27 | ".js": [".js", ".ts"], 28 | ".cjs": [".cjs", ".cts"], 29 | ".mjs": [".mjs", ".mts"] 30 | } 31 | }, 32 | devtool: (isProduction) ? 'source-map' : 'inline-source-map', 33 | devServer: { 34 | static: { 35 | directory: path.resolve(__dirname, 'dist'), 36 | }, 37 | host: 'localhost', 38 | port: 3000, 39 | open: true, 40 | hot: true, 41 | compress: true, 42 | historyApiFallback: true, 43 | onListening: function(devServer){ 44 | if(isProduction){ 45 | throw new Error('webpack-dev-server is not allowed') 46 | } 47 | 48 | const port = devServer.server.address().port 49 | console.log(`Port: ${port}`) 50 | }, 51 | }, 52 | module: { 53 | rules: [ 54 | { 55 | test: /\.s?css$/i, 56 | use: [styleLoaderHandler, "css-loader", 'sass-loader'], 57 | }, 58 | { 59 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 60 | type: 'asset/resource', 61 | }, 62 | { 63 | test: /\.(woff|woff2|eot|ttf|otf)$/i, 64 | type: 'asset/resource', 65 | generator: { 66 | filename: 'fonts/[hash][ext]', 67 | }, 68 | }, 69 | // all files with a `.ts`, `.cts`, `.mts` or `.tsx` extension will be handled by `ts-loader` 70 | { test: /\.([cm]?ts|tsx)$/, loader: "ts-loader" }, 71 | { 72 | test: /\.m?js$/, 73 | exclude: /node_modules/, 74 | use: { 75 | loader: "babel-loader", 76 | options: { 77 | cacheDirectory: true, 78 | presets: ['@babel/preset-env'] 79 | } 80 | } 81 | }, 82 | ], 83 | }, 84 | plugins: [ 85 | new HtmlWebpackPlugin({ 86 | template: path.resolve(__dirname, 'src', 'template.html'), 87 | filename: 'index.html', 88 | favicon: path.resolve(__dirname, 'src', 'img', 'note.svg'), 89 | title: 'Приложение для электронных чеков v1.0.0', 90 | }), 91 | // new CleanWebpackPlugin(), 92 | new MiniCssExtractPlugin({ 93 | filename: 'css/[name][contenthash].css' 94 | }), 95 | // new BundleAnalyzerPlugin({ 96 | // analyzerMode: 'static', 97 | // defaultSizes: 'gzip', 98 | // analyzerPort: 3001, 99 | // reportTitle: 'Основной отчет', 100 | // reportFilename: 'stats.html', 101 | // openAnalyzer: false, 102 | // generateStatsFile: true, 103 | // statsFilename: 'stats.json', 104 | // }), 105 | new ESLintPlugin({ 106 | extensions: ['js', 'ts'], 107 | // fix: true, 108 | }), 109 | ], 110 | } --------------------------------------------------------------------------------