├── .gitignore ├── README.md ├── jest.config.js ├── package.json ├── src ├── book │ ├── BookController.ts │ ├── BookRepository.ts │ └── BookService.ts └── index.ts ├── tests ├── book │ └── BookController.test.ts └── jest.setup.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | build 4 | dist 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # typescript-dependency-injection 2 | 3 | Created for [this YouTube tutorial](https://youtu.be/D1kM5W9r85Q). 4 | 5 | Basic project using https://www.npmjs.com/package/tsyringe to help with dependency injection. 6 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | modulePathIgnorePatterns: ['/build/'], 5 | setupFilesAfterEnv: ['./tests/jest.setup.ts'], 6 | }; 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-dependency-injection", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "tsc && node dist/index.js", 8 | "dev": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts", 9 | "test": "jest" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/node": "^14.14.31", 15 | "jest": "^26.6.3", 16 | "nodemon": "^2.0.7", 17 | "sinon": "^9.2.4", 18 | "ts-jest": "^26.5.2", 19 | "ts-node": "^9.1.1", 20 | "typescript": "^4.2.2" 21 | }, 22 | "dependencies": { 23 | "express": "^4.17.1", 24 | "reflect-metadata": "^0.1.13", 25 | "tsyringe": "^4.4.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/book/BookController.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import { autoInjectable } from 'tsyringe'; 3 | import BookService from './BookService'; 4 | 5 | @autoInjectable() 6 | export default class BookController { 7 | bookService: BookService; 8 | router: Router; 9 | 10 | constructor(bookService: BookService) { 11 | this.bookService = bookService; 12 | this.router = new Router(); 13 | } 14 | 15 | getBooksRoute() { 16 | return this.bookService.getBooks(); 17 | } 18 | 19 | routes() { 20 | this.router.get('/', (_req, res) => res.send(this.getBooksRoute())); 21 | return this.router; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/book/BookRepository.ts: -------------------------------------------------------------------------------- 1 | export default class BookRepository { 2 | books = [ 3 | { id: 1, name: 'The Pragmatic Programmer' }, 4 | { id: 2, name: 'Poems that Solve Puzzles' }, 5 | ]; 6 | 7 | getBooks() { 8 | return this.books; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/book/BookService.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from 'tsyringe'; 2 | import BookRepository from './BookRepository'; 3 | 4 | @injectable() 5 | export default class BookService { 6 | bookRepository: BookRepository; 7 | 8 | constructor(bookRepository: BookRepository) { 9 | this.bookRepository = bookRepository; 10 | } 11 | 12 | getBooks() { 13 | return this.bookRepository.getBooks(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import express from 'express'; 3 | import { container } from 'tsyringe'; 4 | import BookController from './book/BookController'; 5 | const port = process.env.port || 5000; 6 | 7 | const app = express(); 8 | 9 | app.use('/books', container.resolve(BookController).routes()); 10 | app.listen(port, () => console.log(`listening on port: ${port}`)); 11 | -------------------------------------------------------------------------------- /tests/book/BookController.test.ts: -------------------------------------------------------------------------------- 1 | import sinon from 'sinon'; 2 | import BookController from '../../src/book/BookController'; 3 | import BookRepository from '../../src/book/BookRepository'; 4 | import BookService from '../../src/book/BookService'; 5 | 6 | describe('BookController >', () => { 7 | 8 | let bookService; 9 | 10 | beforeEach(() => { 11 | bookService = new BookService(new BookRepository()); 12 | }); 13 | 14 | test('no books >', () => { 15 | // setup 16 | sinon.stub(bookService, 'getBooks').returns([]); 17 | const bookController = new BookController(bookService); 18 | // act 19 | const books = bookController.getBooksRoute(); 20 | // assert 21 | expect(books.length).toBe(0); 22 | }); 23 | 24 | test('one book >', () => { 25 | // setup 26 | sinon.stub(bookService, 'getBooks').returns([{ id: 2, name: 'Poems that Solve Puzzles' }]); 27 | const bookController = new BookController(bookService); 28 | // act 29 | const books = bookController.getBooksRoute(); 30 | // assert 31 | expect(books.length).toBe(1); 32 | expect(books[0].id).toBe(2); 33 | expect(books[0].name).toBe('Poems that Solve Puzzles'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /tests/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true, 4 | "emitDecoratorMetadata": true, 5 | "target": "es6", 6 | "module": "commonjs", 7 | "rootDir": "src", 8 | "outDir": "dist", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "lib": ["es6", "dom"], 12 | "esModuleInterop": true 13 | }, 14 | "include": [ 15 | "src/**/*.ts" 16 | ], 17 | "exclude": [ 18 | "node_modules" 19 | ] 20 | } 21 | --------------------------------------------------------------------------------