├── Chapter01 ├── 01-WhyTypeScript │ ├── 01-CatchingErrorsEarly │ │ ├── 01 │ │ │ └── utils.js │ │ ├── 02 │ │ │ └── utils.ts │ │ └── 03 │ │ │ └── utils.ts │ └── 02-UsingFutureJavaScriptFeatures │ │ └── future.ts ├── 02-BasicTypes │ ├── 01-TypeAnnotations │ │ └── code.ts │ ├── 02-TypeInference │ │ └── code.ts │ ├── 03-Any │ │ └── code.ts │ ├── 04-Void │ │ ├── 01 │ │ │ └── code.ts │ │ └── 02 │ │ │ └── code.ts │ ├── 05-Never │ │ ├── 01 │ │ │ └── code.ts │ │ ├── 02 │ │ │ └── code.ts │ │ └── 03 │ │ │ └── code.ts │ ├── 06-Enum │ │ ├── 01 │ │ │ └── code.ts │ │ ├── 02 │ │ │ └── code.ts │ │ └── 03 │ │ │ └── code.ts │ ├── 07-Object │ │ └── code.ts │ └── 08-Array │ │ └── code.ts ├── 03-InterfacesTypeAliasesClasses │ ├── 01-Intro │ │ └── code.ts │ ├── 02-Interfaces │ │ ├── 01-Properties │ │ │ └── code.ts │ │ ├── 02-Properties │ │ │ └── code.ts │ │ ├── 03-MethodSignatures-Intro │ │ │ └── code.ts │ │ ├── 04-MethodSignatures-ParamName │ │ │ └── code.ts │ │ ├── 05-MethodSignatures-MethodName │ │ │ └── code.ts │ │ ├── 06-MethodSignatures-ReturnType │ │ │ └── code.ts │ │ ├── 07-MethodSignature-ParamType │ │ │ └── code.ts │ │ ├── 08-Properties-MethodSignature-NoParamName │ │ │ └── code.ts │ │ ├── 09-Optional-Property │ │ │ └── code.ts │ │ ├── 10-Optional-MethodParam │ │ │ └── code.ts │ │ ├── 11-Readonly │ │ │ └── code.ts │ │ └── 12-Extending │ │ │ └── code.ts │ └── 03-TypeAliases │ │ ├── 01 │ │ └── code.ts │ │ └── 02 │ │ └── code.ts ├── 04-Classes │ ├── 01-BasicClass │ │ └── code.ts │ ├── 02-ImplementingInterfaces │ │ └── code.ts │ ├── 03-Constructors │ │ ├── 01 │ │ │ └── code.ts │ │ ├── 02 │ │ │ └── code.ts │ │ └── 03 │ │ │ └── code.ts │ ├── 05-Extending │ │ ├── 01 │ │ │ └── code.ts │ │ └── 02 │ │ │ └── code.ts │ ├── 06-Abstract │ │ ├── 01 │ │ │ └── code.ts │ │ ├── 02 │ │ │ └── code.ts │ │ └── 03 │ │ │ └── code.ts │ ├── 07-AccessModifiers │ │ └── code.ts │ ├── 08-PropertyGettersSetters │ │ └── code.ts │ └── 09-Static │ │ ├── 01 │ │ └── code.ts │ │ └── 02 │ │ └── code.ts ├── 05-Modules │ ├── 01-Intro │ │ ├── orderDetail.ts │ │ └── product.ts │ ├── 02-Exporting │ │ ├── 01 │ │ │ └── product.ts │ │ ├── 02 │ │ │ └── product.ts │ │ └── 03 │ │ │ └── product.ts │ ├── 03-Importing │ │ ├── 01 │ │ │ ├── orderDetail.ts │ │ │ └── product.ts │ │ └── 02 │ │ │ ├── orderDetail.ts │ │ │ └── product.ts │ └── 04-DefaultExports │ │ ├── orderDetail.ts │ │ └── product.ts ├── 06-ConfiguringCompilation │ ├── 01-CommonOptions │ │ └── code.ts │ └── 02-tsconfig.json │ │ ├── 01 │ │ ├── code.ts │ │ └── tsconfig.json │ │ ├── 02 │ │ ├── orderDetail.ts │ │ ├── product.ts │ │ └── tsconfig.json │ │ └── 03 │ │ ├── src │ │ ├── orderDetail.ts │ │ └── product.ts │ │ └── tsconfig.json └── 07-TypeScriptLinting │ ├── 01-member-access │ ├── code.ts │ └── tslint.json │ ├── 02-member-access-fix │ ├── code.ts │ └── tslint.json │ ├── 03-BuiltIn │ ├── code.ts │ └── tslint.json │ └── 04-ExcludingFiles │ ├── code.ts │ └── tslint.json ├── Chapter02 ├── 01-Tuples │ ├── 01-Intro │ │ └── code.ts │ ├── 02-Rest │ │ └── code.ts │ ├── 03-Spread │ │ └── code.ts │ ├── 04-OpenEndedTuples │ │ └── code.ts │ ├── 05-TupleRestParameters │ │ └── code.ts │ ├── 06-SpreadingTuples │ │ └── code.ts │ ├── 07-EmptyTuples │ │ └── code.ts │ └── 08-OptionalTuples │ │ └── code.ts ├── 02-Unknown │ ├── 01-intro.ts │ ├── 02-type-predicate.ts │ ├── 03-instanceof.ts │ └── 04-typeassertion.ts ├── 03-ProjectReferences │ ├── ProjectA │ │ ├── dist │ │ │ ├── person.js │ │ │ └── person.js.map │ │ ├── src │ │ │ └── person.ts │ │ └── tsconfig.json │ └── Shared │ │ ├── dist │ │ ├── utils.d.ts │ │ ├── utils.d.ts.map │ │ ├── utils.js │ │ └── utils.js.map │ │ ├── src │ │ └── utils.ts │ │ └── tsconfig.json └── 04-DefaultProps │ ├── 01-App.tsx │ └── 02-App.tsx ├── Chapter03 ├── 01-CreatingAProjectManually │ ├── dist │ │ └── index.html │ ├── package.json │ ├── src │ │ └── index.tsx │ ├── tsconfig.json │ ├── tslint.json │ └── webpack.config.js └── 02-ConfirmComponent │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── Confirm.css │ ├── Confirm.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── react-app-env.d.ts │ └── serviceWorker.ts │ ├── tsconfig.json │ └── tslint.json ├── Chapter04 ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── src │ ├── AdminPage.tsx │ ├── Header.tsx │ ├── LoginPage.tsx │ ├── NotFoundPage.tsx │ ├── ProductPage.tsx │ ├── ProductsData.ts │ ├── ProductsPage.tsx │ ├── Routes.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ └── react-app-env.d.ts ├── tsconfig.json └── tslint.json ├── Chapter05 ├── 01-UnionTypes │ ├── 01-StringLiterals.ts │ ├── 02-StringLiteralUnion.ts │ └── 03-DiscriminatedUnion.ts ├── 02-TypeGuards │ ├── 01-typeof.ts │ ├── 02-instanceof.ts │ ├── 03-in.ts │ └── 04-TypePredicate.ts ├── 03-Generics │ ├── 01-GenericFunction.ts │ └── 02-GenericClass.ts ├── 05-OverloadSignatures.ts ├── 06-Keyof.ts └── 07-MappedTypes.ts ├── Chapter06 ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── src │ ├── AdminPage.tsx │ ├── Header.tsx │ ├── LoginPage.tsx │ ├── NotFoundPage.tsx │ ├── Product.tsx │ ├── ProductPage.tsx │ ├── ProductsData.ts │ ├── ProductsPage.tsx │ ├── Routes.tsx │ ├── Tabs.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── react-app-env.d.ts │ └── withLoader.tsx ├── tsconfig.json └── tslint.json ├── Chapter07 ├── 01-CreatingAFormWithControlledComponents │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── src │ │ ├── AdminPage.tsx │ │ ├── ContactUs.tsx │ │ ├── ContactUsPage.tsx │ │ ├── Header.tsx │ │ ├── LoginPage.tsx │ │ ├── NotFoundPage.tsx │ │ ├── Product.tsx │ │ ├── ProductPage.tsx │ │ ├── ProductsData.ts │ │ ├── ProductsPage.tsx │ │ ├── Routes.tsx │ │ ├── Tabs.tsx │ │ ├── index.css │ │ ├── index.tsx │ │ ├── logo.svg │ │ └── withLoader.tsx │ ├── tsconfig.json │ └── tslint.json ├── 02-ReducingBoilerplateWithGenericComponents │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── src │ │ ├── AdminPage.tsx │ │ ├── ContactUs.tsx │ │ ├── ContactUsPage.tsx │ │ ├── Form.tsx │ │ ├── Header.tsx │ │ ├── LoginPage.tsx │ │ ├── NotFoundPage.tsx │ │ ├── Product.tsx │ │ ├── ProductPage.tsx │ │ ├── ProductsData.ts │ │ ├── ProductsPage.tsx │ │ ├── Routes.tsx │ │ ├── Tabs.tsx │ │ ├── index.css │ │ ├── index.tsx │ │ ├── logo.svg │ │ └── withLoader.tsx │ ├── tsconfig.json │ └── tslint.json ├── 03-ValidatingForms │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── src │ │ ├── AdminPage.tsx │ │ ├── ContactUs.tsx │ │ ├── ContactUsPage.tsx │ │ ├── Form.tsx │ │ ├── Header.tsx │ │ ├── LoginPage.tsx │ │ ├── NotFoundPage.tsx │ │ ├── Product.tsx │ │ ├── ProductPage.tsx │ │ ├── ProductsData.ts │ │ ├── ProductsPage.tsx │ │ ├── Routes.tsx │ │ ├── Tabs.tsx │ │ ├── index.css │ │ ├── index.tsx │ │ ├── logo.svg │ │ └── withLoader.tsx │ ├── tsconfig.json │ └── tslint.json └── 04-FormSubmission │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ ├── src │ ├── AdminPage.tsx │ ├── ContactUs.tsx │ ├── ContactUsPage.tsx │ ├── Form.tsx │ ├── Header.tsx │ ├── LoginPage.tsx │ ├── NotFoundPage.tsx │ ├── Product.tsx │ ├── ProductPage.tsx │ ├── ProductsData.ts │ ├── ProductsPage.tsx │ ├── Routes.tsx │ ├── Tabs.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ └── withLoader.tsx │ ├── tsconfig.json │ └── tslint.json ├── Chapter08 ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── src │ ├── AdminPage.tsx │ ├── BasketActions.ts │ ├── BasketReducer.ts │ ├── BasketSummary.tsx │ ├── BasketTypes.ts │ ├── ContactUs.tsx │ ├── ContactUsPage.tsx │ ├── Form.tsx │ ├── Header.tsx │ ├── LoginPage.tsx │ ├── NotFoundPage.tsx │ ├── Product.tsx │ ├── ProductPage.tsx │ ├── ProductsActions.ts │ ├── ProductsData.ts │ ├── ProductsList.tsx │ ├── ProductsPage.tsx │ ├── ProductsReducer.ts │ ├── ProductsTypes.ts │ ├── Routes.tsx │ ├── Store.ts │ ├── Tabs.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── react-app-env.d.ts │ └── withLoader.tsx ├── tsconfig.json └── tslint.json ├── Chapter09 ├── 01-AsyncCode │ ├── 01-callbacks.ts │ ├── 02-promises.ts │ └── 03-async-await.ts ├── 02-Fetch │ └── fetch.ts ├── 03-AxiosWithClass │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── src │ │ ├── App.css │ │ ├── App.test.tsx │ │ ├── App.tsx │ │ ├── index.css │ │ ├── index.tsx │ │ ├── logo.svg │ │ ├── react-app-env.d.ts │ │ ├── registerServiceWorker.ts │ │ └── serviceWorker.ts │ ├── tsconfig.json │ └── tslint.json └── 04-AxiosWithFunction │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── react-app-env.d.ts │ └── serviceWorker.ts │ ├── tsconfig.json │ └── tslint.json ├── Chapter10 ├── 01-QuerySyntax │ └── Queries.txt ├── 02-MutationSyntax │ └── Mutations.txt ├── 03-Axios │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── src │ │ ├── App.css │ │ ├── App.test.tsx │ │ ├── App.tsx │ │ ├── Header.tsx │ │ ├── index.css │ │ ├── index.tsx │ │ ├── logo.svg │ │ ├── react-app-env.d.ts │ │ └── serviceWorker.ts │ ├── tsconfig.json │ └── tslint.json └── 04-Apollo │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── Header.tsx │ ├── RepoSearch.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── react-app-env.d.ts │ └── serviceWorker.ts │ ├── tsconfig.json │ └── tslint.json ├── Chapter11 ├── 01-ReactShop │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── src │ │ ├── AdminPage.tsx │ │ ├── BasketActions.ts │ │ ├── BasketReducer.ts │ │ ├── BasketSummary.tsx │ │ ├── BasketTypes.ts │ │ ├── ContactUs.test.tsx │ │ ├── ContactUs.tsx │ │ ├── ContactUsPage.tsx │ │ ├── Form.test.tsx │ │ ├── Form.tsx │ │ ├── Header.tsx │ │ ├── LoginPage.tsx │ │ ├── NotFoundPage.tsx │ │ ├── Product.tsx │ │ ├── ProductPage.tsx │ │ ├── ProductsActions.ts │ │ ├── ProductsData.ts │ │ ├── ProductsList.tsx │ │ ├── ProductsPage.tsx │ │ ├── ProductsReducer.ts │ │ ├── ProductsTypes.ts │ │ ├── Routes.tsx │ │ ├── Store.ts │ │ ├── Tabs.tsx │ │ ├── __snapshots__ │ │ │ └── ContactUs.test.tsx.snap │ │ ├── index.css │ │ ├── index.tsx │ │ ├── logo.svg │ │ ├── react-app-env.d.ts │ │ └── withLoader.tsx │ ├── tsconfig.json │ └── tslint.json └── 02-MockingRESTAPI │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── __snapshots__ │ │ └── App.test.tsx.snap │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── react-app-env.d.ts │ ├── registerServiceWorker.ts │ └── serviceWorker.ts │ ├── tsconfig.json │ └── tslint.json ├── LICENSE └── README.md /Chapter01/01-WhyTypeScript/01-CatchingErrorsEarly/01/utils.js: -------------------------------------------------------------------------------- 1 | function calculateTotalPrice(product, quantity, discount) { 2 | var priceWithoutDiscount = product.price * quantity; 3 | var discountAmount = priceWithoutDiscount * discount; 4 | return priceWithoutDiscount - discountAmount; 5 | } 6 | -------------------------------------------------------------------------------- /Chapter01/01-WhyTypeScript/01-CatchingErrorsEarly/02/utils.ts: -------------------------------------------------------------------------------- 1 | interface IProduct { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | function calculateTotalPrice( 7 | product: IProduct, 8 | quantity: number, 9 | discount: number 10 | ): number { 11 | var priceWithoutDiscount: number = product.price * quantity; 12 | var discountAmount: number = priceWithoutDiscount * discount; 13 | return priceWithoutDiscount - discountAmount; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter01/01-WhyTypeScript/01-CatchingErrorsEarly/03/utils.ts: -------------------------------------------------------------------------------- 1 | interface IProduct { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | function calculateTotalPrice( 7 | product: IProduct, 8 | quantity: number, 9 | discount: number 10 | ): number { 11 | var priceWithoutDiscount: number = product.unitPrice * quantity; 12 | var discountAmount: number = priceWithoutDiscount * discount; 13 | return priceWithoutDiscount - discountAmount; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter01/01-WhyTypeScript/02-UsingFutureJavaScriptFeatures/future.ts: -------------------------------------------------------------------------------- 1 | var threeSquared: number = 3 ** 2; 2 | console.log(threeSquared); 3 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/01-TypeAnnotations/code.ts: -------------------------------------------------------------------------------- 1 | let unitPrice: number; 2 | unitPrice = "Table"; 3 | 4 | function getTotal( 5 | unitPrice: number, 6 | quantity: number, 7 | discount: number 8 | ): number { 9 | const priceWithoutDiscount = unitPrice * quantity; 10 | const discountAmount = priceWithoutDiscount * discount; 11 | return priceWithoutDiscount - discountAmount; 12 | } 13 | 14 | let total: string = getTotal(500, "one", 0.1); 15 | 16 | // Correction 17 | // let total: string = getTotal(500, 1, 0.1); 18 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/02-TypeInference/code.ts: -------------------------------------------------------------------------------- 1 | let flag = false; 2 | flag = "Table"; 3 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/03-Any/code.ts: -------------------------------------------------------------------------------- 1 | let flag; 2 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/04-Void/01/code.ts: -------------------------------------------------------------------------------- 1 | function logText(text: string): void { 2 | console.log(text); 3 | } 4 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/04-Void/02/code.ts: -------------------------------------------------------------------------------- 1 | function logText(text: string) { 2 | console.log(text); 3 | } 4 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/05-Never/01/code.ts: -------------------------------------------------------------------------------- 1 | function foreverTask(taskName: string): never { 2 | while (true) { 3 | console.log(`Doing ${taskName} over and over again ...`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/05-Never/02/code.ts: -------------------------------------------------------------------------------- 1 | function foreverTask(taskName: string): never { 2 | while (true) { 3 | console.log(`Doing ${taskName} over and over again ...`); 4 | break; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/05-Never/03/code.ts: -------------------------------------------------------------------------------- 1 | function foreverTask(taskName: string) { 2 | while (true) { 3 | console.log(`Doing ${taskName} over and over again ...`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/06-Enum/01/code.ts: -------------------------------------------------------------------------------- 1 | enum OrderStatus { 2 | Paid, 3 | Shipped, 4 | Completed, 5 | Cancelled 6 | } 7 | 8 | let status = OrderStatus.Shipped; 9 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/06-Enum/02/code.ts: -------------------------------------------------------------------------------- 1 | enum OrderStatus { 2 | Paid = 1, 3 | Shipped, 4 | Completed, 5 | Cancelled 6 | } 7 | 8 | let status = OrderStatus.Shipped; 9 | console.log(status); 10 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/06-Enum/03/code.ts: -------------------------------------------------------------------------------- 1 | enum OrderStatus { 2 | Paid = 1, 3 | Shipped = 2, 4 | Completed = 3, 5 | Cancelled = 0 6 | } 7 | 8 | let status = OrderStatus.Shipped; 9 | console.log(status); 10 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/07-Object/code.ts: -------------------------------------------------------------------------------- 1 | const customer = { 2 | name: "Lamps Ltd", 3 | turnover: 2000134, 4 | active: true 5 | }; 6 | 7 | customer.turnover = 500000; 8 | 9 | customer.profit = 10000; 10 | -------------------------------------------------------------------------------- /Chapter01/02-BasicTypes/08-Array/code.ts: -------------------------------------------------------------------------------- 1 | const numbers: number[] = []; 2 | 3 | numbers.push(1); 4 | 5 | const numbers = [1, 3, 5]; 6 | 7 | console.log(numbers[0]); 8 | console.log(numbers[1]); 9 | console.log(numbers[2]); 10 | 11 | for (let i in numbers) { 12 | console.log(numbers[i]); 13 | } 14 | 15 | numbers.forEach(function(num) { 16 | console.log(num); 17 | }); 18 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/01-Intro/code.ts: -------------------------------------------------------------------------------- 1 | let customer: object; 2 | customer = { 3 | name: "Lamps Ltd", 4 | turnover: 2000134, 5 | active: true 6 | }; 7 | customer.turnover = 2000200; 8 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/01-Properties/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | const table: Product = { 7 | name: "Table", 8 | unitPrice: 500 9 | }; 10 | 11 | const chair: Product = { 12 | productName: "Table", 13 | price: 70 14 | }; 15 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/02-Properties/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | } 10 | 11 | const table: Product = { 12 | name: "Table", 13 | unitPrice: 500 14 | }; 15 | 16 | const tableOrder: OrderDetail = { 17 | product: table, 18 | quantity: 1 19 | }; 20 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/03-MethodSignatures-Intro/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number; 10 | } 11 | 12 | const tableOrder: OrderDetail = { 13 | product: table, 14 | quantity: 1, 15 | getTotal(discount: number): number { 16 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 17 | const discountAmount = priceWithoutDiscount * discount; 18 | return priceWithoutDiscount - discountAmount; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/04-MethodSignatures-ParamName/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number; 10 | } 11 | 12 | const tableOrder: OrderDetail = { 13 | product: table, 14 | quantity: 1, 15 | getTotal(discountPercentage: number): number { 16 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 17 | const discountAmount = priceWithoutDiscount * discountPercentage; 18 | return priceWithoutDiscount - discountAmount; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/05-MethodSignatures-MethodName/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number; 10 | } 11 | 12 | const tableOrder: OrderDetail = { 13 | product: table, 14 | quantity: 1, 15 | total(discountPercentage: number): number { 16 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 17 | const discountAmount = priceWithoutDiscount * discountPercentage; 18 | return priceWithoutDiscount - discountAmount; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/06-MethodSignatures-ReturnType/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number; 10 | } 11 | 12 | const tableOrder: OrderDetail = { 13 | product: table, 14 | quantity: 1, 15 | getTotal(discountPercentage: number): string { 16 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 17 | const discountAmount = priceWithoutDiscount * discountPercentage; 18 | return (priceWithoutDiscount - discountAmount).toString(); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/07-MethodSignature-ParamType/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number; 10 | } 11 | 12 | const tableOrder: OrderDetail = { 13 | product: table, 14 | quantity: 1, 15 | getTotal(discountPercentage: string): number { 16 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 17 | const discountAmount = priceWithoutDiscount * discountPercentage; 18 | return priceWithoutDiscount - discountAmount; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/08-Properties-MethodSignature-NoParamName/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(number): number; 10 | } 11 | 12 | const tableOrder: OrderDetail = { 13 | product: table, 14 | quantity: 1, 15 | getTotal(discountPercentage: number): number { 16 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 17 | const discountAmount = priceWithoutDiscount * discountPercentage; 18 | return priceWithoutDiscount - discountAmount; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/09-Optional-Property/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | dateAdded?: Date; 10 | getTotal(discount: number): number; 11 | } 12 | 13 | const tableOrder: OrderDetail = { 14 | product: table, 15 | quantity: 1, 16 | getTotal(discount: number): number { 17 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 18 | const discountAmount = priceWithoutDiscount * discount; 19 | return priceWithoutDiscount - discountAmount; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/10-Optional-MethodParam/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | dateAdded?: Date; 10 | getTotal(discount?: number): number; 11 | } 12 | 13 | const tableOrder: OrderDetail = { 14 | product: table, 15 | quantity: 1, 16 | getTotal(discount?: number): number { 17 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 18 | const discountAmount = priceWithoutDiscount * (discount || 0); 19 | return priceWithoutDiscount - discountAmount; 20 | } 21 | }; 22 | 23 | tableOrder.getTotal(); 24 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/11-Readonly/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | readonly name: string; 3 | unitPrice: number; 4 | } 5 | 6 | const table: Product = { 7 | name: "Table", 8 | unitPrice: 500 9 | }; 10 | 11 | table.name = "Better Table"; 12 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/02-Interfaces/12-Extending/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface DiscountCode { 7 | code: string; 8 | percentage: number; 9 | } 10 | 11 | interface ProductWithDiscountCodes extends Product { 12 | discountCodes: DiscountCode[]; 13 | } 14 | 15 | const table: ProductWithDiscountCodes = { 16 | name: "Table", 17 | unitPrice: 500, 18 | discountCodes: [ 19 | { code: "SUMMER10", percentage: 0.1 }, 20 | { code: "BFRI", percentage: 0.2 } 21 | ] 22 | }; 23 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/03-TypeAliases/01/code.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | type GetTotal = (discount: number) => number; 7 | 8 | interface OrderDetail { 9 | product: Product; 10 | quantity: number; 11 | getTotal: GetTotal; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter01/03-InterfacesTypeAliasesClasses/03-TypeAliases/02/code.ts: -------------------------------------------------------------------------------- 1 | type Product = { 2 | name: string; 3 | unitPrice: number; 4 | }; 5 | 6 | type OrderDetail = { 7 | product: Product; 8 | quantity: number; 9 | getTotal: (discount: number) => number; 10 | }; 11 | 12 | const table: Product = { 13 | name: "Table", 14 | unitPrice: 500 15 | }; 16 | 17 | const orderDetail: OrderDetail = { 18 | product: table, 19 | quantity: 1, 20 | getTotal(discount: number): number { 21 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 22 | const discountAmount = priceWithoutDiscount * discount; 23 | return priceWithoutDiscount - discountAmount; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/01-BasicClass/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | class OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | 10 | getTotal(discount: number): number { 11 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 12 | const discountAmount = priceWithoutDiscount * discount; 13 | return priceWithoutDiscount - discountAmount; 14 | } 15 | } 16 | 17 | const table = new Product(); 18 | table.name = "Table"; 19 | table.unitPrice = 500; 20 | 21 | const orderDetail = new OrderDetail(); 22 | orderDetail.product = table; 23 | orderDetail.quantity = 2; 24 | 25 | const total = orderDetail.getTotal(0.1); 26 | 27 | console.log(total); 28 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/02-ImplementingInterfaces/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface IOrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number; 10 | } 11 | 12 | class OrderDetail implements IOrderDetail { 13 | product: Product; 14 | quantity: number; 15 | 16 | getTotal(discount: number): number { 17 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 18 | const discountAmount = priceWithoutDiscount * discount; 19 | return priceWithoutDiscount - discountAmount; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/03-Constructors/01/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface IOrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number; 10 | } 11 | 12 | class OrderDetail implements IOrderDetail { 13 | product: Product; 14 | quantity: number; 15 | 16 | constructor(product: Product, quantity: number) { 17 | this.product = product; 18 | this.quantity = quantity; 19 | } 20 | 21 | getTotal(discount: number): number { 22 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 23 | const discountAmount = priceWithoutDiscount * discount; 24 | return priceWithoutDiscount - discountAmount; 25 | } 26 | } 27 | 28 | const table = new Product(); 29 | table.name = "Table"; 30 | table.unitPrice = 500; 31 | 32 | const orderDetail = new OrderDetail(table, 2); 33 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/03-Constructors/02/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface IOrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number; 10 | } 11 | 12 | class OrderDetail implements IOrderDetail { 13 | product: Product; 14 | quantity: number; 15 | 16 | constructor(product: Product, quantity: number = 1) { 17 | this.product = product; 18 | this.quantity = quantity; 19 | } 20 | 21 | getTotal(discount: number): number { 22 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 23 | const discountAmount = priceWithoutDiscount * discount; 24 | return priceWithoutDiscount - discountAmount; 25 | } 26 | } 27 | 28 | const table = new Product(); 29 | table.name = "Table"; 30 | table.unitPrice = 500; 31 | 32 | const orderDetail = new OrderDetail(table); 33 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/03-Constructors/03/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface IOrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number; 10 | } 11 | 12 | class OrderDetail implements IOrderDetail { 13 | constructor(public product: Product, public quantity: number = 1) { 14 | this.product = product; 15 | this.quantity = quantity; 16 | } 17 | 18 | getTotal(discount: number): number { 19 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 20 | const discountAmount = priceWithoutDiscount * discount; 21 | return priceWithoutDiscount - discountAmount; 22 | } 23 | } 24 | 25 | const table = new Product(); 26 | table.name = "Table"; 27 | table.unitPrice = 500; 28 | 29 | const orderDetail = new OrderDetail(table); 30 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/05-Extending/01/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | interface DiscountCode { 7 | code: string; 8 | percentage: number; 9 | } 10 | 11 | class ProductWithDiscountCodes extends Product { 12 | discountCodes: DiscountCode[]; 13 | } 14 | 15 | const table = new ProductWithDiscountCodes(); 16 | table.name = "Table"; 17 | table.unitPrice = 500; 18 | table.discountCodes = [ 19 | { code: "SUMMER10", percentage: 0.1 }, 20 | { code: "BFRI", percentage: 0.2 } 21 | ]; 22 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/05-Extending/02/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | constructor(public name: string, public unitPrice: number) {} 3 | } 4 | 5 | interface DiscountCode { 6 | code: string; 7 | percentage: number; 8 | } 9 | 10 | class ProductWithDiscountCodes extends Product { 11 | constructor(public name: string, public unitPrice: number) { 12 | super(name, unitPrice); 13 | } 14 | discountCodes: DiscountCode[]; 15 | } 16 | 17 | const table = new ProductWithDiscountCodes("Table", 500); 18 | table.discountCodes = [ 19 | { code: "SUMMER10", percentage: 0.1 }, 20 | { code: "BFRI", percentage: 0.2 } 21 | ]; 22 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/06-Abstract/01/code.ts: -------------------------------------------------------------------------------- 1 | abstract class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | const bread = new Product(); 7 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/06-Abstract/02/code.ts: -------------------------------------------------------------------------------- 1 | abstract class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | class Food extends Product { 7 | constructor(public bestBefore: Date) { 8 | super(); 9 | } 10 | } 11 | 12 | const bread = new Food(new Date(2019, 6, 1)); 13 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/06-Abstract/03/code.ts: -------------------------------------------------------------------------------- 1 | abstract class Product { 2 | name: string; 3 | unitPrice: number; 4 | abstract delete(): void; 5 | } 6 | 7 | class Food extends Product { 8 | deleted: boolean; 9 | 10 | constructor(public bestBefore: Date) { 11 | super(); 12 | } 13 | 14 | delete() { 15 | this.deleted = false; 16 | } 17 | } 18 | 19 | const bread = new Food(new Date(2019, 6, 1)); 20 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/07-AccessModifiers/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | class OrderDetail { 7 | public product: Product; 8 | public quantity: number; 9 | private deleted: boolean; 10 | 11 | public getTotal(discount: number): number { 12 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 13 | const discountAmount = priceWithoutDiscount * discount; 14 | return priceWithoutDiscount - discountAmount; 15 | } 16 | 17 | public delete(): void { 18 | this.deleted = true; 19 | } 20 | } 21 | 22 | const orderDetail = new OrderDetail(); 23 | orderDetail.deleted = true; 24 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/08-PropertyGettersSetters/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | 4 | private _unitPrice: number; 5 | get unitPrice(): number { 6 | return this._unitPrice || 0; 7 | } 8 | set unitPrice(value: number) { 9 | if (value < 0) { 10 | value = 0; 11 | } 12 | this._unitPrice = value; 13 | } 14 | } 15 | 16 | const table = new Product(); 17 | table.name = "Table"; 18 | console.log(table.unitPrice); 19 | table.unitPrice = -10; 20 | console.log(table.unitPrice); 21 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/09-Static/01/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | class OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | 10 | static getTotal(discount: number): number { 11 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 12 | const discountAmount = priceWithoutDiscount * discount; 13 | return priceWithoutDiscount - discountAmount; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Chapter01/04-Classes/09-Static/02/code.ts: -------------------------------------------------------------------------------- 1 | class Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | class OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | 10 | static getTotal( 11 | unitPrice: number, 12 | quantity: number, 13 | discount: number 14 | ): number { 15 | const priceWithoutDiscount = unitPrice * quantity; 16 | const discountAmount = priceWithoutDiscount * discount; 17 | return priceWithoutDiscount - discountAmount; 18 | } 19 | } 20 | 21 | const total = OrderDetail.getTotal(500, 2, 0.1); 22 | console.log(total); 23 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/01-Intro/orderDetail.ts: -------------------------------------------------------------------------------- 1 | class OrderDetail { 2 | product: Product; 3 | quantity: number; 4 | getTotal(discount: number): number { 5 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 6 | const discountAmount = priceWithoutDiscount * discount; 7 | return priceWithoutDiscount - discountAmount; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/01-Intro/product.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/02-Exporting/01/product.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/02-Exporting/02/product.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | export { Product }; 7 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/02-Exporting/03/product.ts: -------------------------------------------------------------------------------- 1 | interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | export { Product as Stock }; 7 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/03-Importing/01/orderDetail.ts: -------------------------------------------------------------------------------- 1 | import { Product } from "./product"; 2 | 3 | class OrderDetail { 4 | product: Product; 5 | quantity: number; 6 | getTotal(discount: number): number { 7 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 8 | const discountAmount = priceWithoutDiscount * discount; 9 | return priceWithoutDiscount - discountAmount; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/03-Importing/01/product.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/03-Importing/02/orderDetail.ts: -------------------------------------------------------------------------------- 1 | import { Product as Stock } from "./product"; 2 | 3 | class OrderDetail { 4 | product: Stock; 5 | quantity: number; 6 | getTotal(discount: number): number { 7 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 8 | const discountAmount = priceWithoutDiscount * discount; 9 | return priceWithoutDiscount - discountAmount; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/03-Importing/02/product.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/04-DefaultExports/orderDetail.ts: -------------------------------------------------------------------------------- 1 | import Product from "./product"; 2 | 3 | class OrderDetail { 4 | product: Product; 5 | quantity: number; 6 | getTotal(discount: number): number { 7 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 8 | const discountAmount = priceWithoutDiscount * discount; 9 | return priceWithoutDiscount - discountAmount; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter01/05-Modules/04-DefaultExports/product.ts: -------------------------------------------------------------------------------- 1 | export default interface { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter01/06-ConfiguringCompilation/01-CommonOptions/code.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | export class OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number { 10 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 11 | const discountAmount = priceWithoutDiscount * discount; 12 | return priceWithoutDiscount - discountAmount; 13 | } 14 | } -------------------------------------------------------------------------------- /Chapter01/06-ConfiguringCompilation/02-tsconfig.json/01/code.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | export class OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number { 10 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 11 | const discountAmount = priceWithoutDiscount * discount; 12 | return priceWithoutDiscount - discountAmount; 13 | } 14 | } -------------------------------------------------------------------------------- /Chapter01/06-ConfiguringCompilation/02-tsconfig.json/01/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "outDir": "dist", 5 | "module": "es6", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "noImplicitReturns": true, 9 | "noImplicitAny": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter01/06-ConfiguringCompilation/02-tsconfig.json/02/orderDetail.ts: -------------------------------------------------------------------------------- 1 | import { Product } from "./product"; 2 | 3 | export class OrderDetail { 4 | product: Product; 5 | quantity: number; 6 | getTotal(discount: number): number { 7 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 8 | const discountAmount = priceWithoutDiscount * discount; 9 | return priceWithoutDiscount - discountAmount; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter01/06-ConfiguringCompilation/02-tsconfig.json/02/product.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter01/06-ConfiguringCompilation/02-tsconfig.json/02/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "outDir": "dist", 5 | "module": "es6", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "noImplicitReturns": true, 9 | "noImplicitAny": true 10 | }, 11 | "files": ["product.ts", "orderDetail.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /Chapter01/06-ConfiguringCompilation/02-tsconfig.json/03/src/orderDetail.ts: -------------------------------------------------------------------------------- 1 | import { Product } from "./product"; 2 | 3 | export class OrderDetail { 4 | product: Product; 5 | quantity: number; 6 | getTotal(discount: number): number { 7 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 8 | const discountAmount = priceWithoutDiscount * discount; 9 | return priceWithoutDiscount - discountAmount; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter01/06-ConfiguringCompilation/02-tsconfig.json/03/src/product.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter01/06-ConfiguringCompilation/02-tsconfig.json/03/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "outDir": "dist", 5 | "module": "es6", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "noImplicitReturns": true, 9 | "noImplicitAny": true 10 | }, 11 | "include": ["src/**/*"] 12 | } 13 | -------------------------------------------------------------------------------- /Chapter01/07-TypeScriptLinting/01-member-access/code.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | export class OrderDetail { 7 | product: Product; 8 | quantity: number; 9 | getTotal(discount: number): number { 10 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 11 | const discountAmount = priceWithoutDiscount * discount; 12 | return priceWithoutDiscount - discountAmount; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter01/07-TypeScriptLinting/01-member-access/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "member-access": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Chapter01/07-TypeScriptLinting/02-member-access-fix/code.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | export class OrderDetail { 7 | public product: Product; 8 | public quantity: number; 9 | public getTotal(discount: number): number { 10 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 11 | const discountAmount = priceWithoutDiscount * discount; 12 | return priceWithoutDiscount - discountAmount; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter01/07-TypeScriptLinting/02-member-access-fix/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "member-access": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Chapter01/07-TypeScriptLinting/03-BuiltIn/code.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | export class OrderDetail { 7 | public product: Product; 8 | public quantity: number; 9 | public getTotal(discount: number): number { 10 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 11 | const discountAmount = priceWithoutDiscount * discount; 12 | return priceWithoutDiscount - discountAmount; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter01/07-TypeScriptLinting/03-BuiltIn/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended"], 3 | "rules": { 4 | "interface-name": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter01/07-TypeScriptLinting/04-ExcludingFiles/code.ts: -------------------------------------------------------------------------------- 1 | export interface IProduct { 2 | name: string; 3 | unitPrice: number; 4 | } 5 | 6 | export class OrderDetail { 7 | public product: IProduct; 8 | public quantity: number; 9 | public getTotal(discount: number): number { 10 | const priceWithoutDiscount = this.product.unitPrice * this.quantity; 11 | const discountAmount = priceWithoutDiscount * discount; 12 | return priceWithoutDiscount - discountAmount; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter01/07-TypeScriptLinting/04-ExcludingFiles/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended"], 3 | "linterOptions": { 4 | "exclude": ["node_modules/**/*.ts"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter02/01-Tuples/01-Intro/code.ts: -------------------------------------------------------------------------------- 1 | let product: [string, number]; 2 | 3 | product = ["Table", 500]; 4 | 5 | product = [500, "Table"]; 6 | 7 | // Fairly readable 8 | let flag: [string, boolean]; 9 | flag = ["Active", false]; 10 | 11 | // Fairly readable 12 | let last3Scores: [string, number, number, number]; 13 | last3Scores = ["Billy", 60, 70, 75]; 14 | 15 | // Fairly readable 16 | let point: [number, number, number]; 17 | point = [100, 200, 100]; 18 | 19 | // Not readable - what are those 2 numbers? 20 | let customer: [string, number, number]; 21 | customer = ["Tables Ltd", 500100, 10500]; 22 | 23 | // Accessing tuple elements 24 | product = ["Table", 500]; 25 | console.log(product[0]); // "Table" 26 | console.log(product[1]); // 500 27 | 28 | // Iterating tuples 29 | product = ["Table", 500]; 30 | for (let element in product) { 31 | console.log(product[element]); // Table, 500 32 | } 33 | 34 | product.forEach(function(element) { 35 | console.log(element); // Table, 500 36 | }); 37 | -------------------------------------------------------------------------------- /Chapter02/01-Tuples/02-Rest/code.ts: -------------------------------------------------------------------------------- 1 | function logScores(...scores) { 2 | console.log(scores); 3 | } 4 | 5 | logScores(50, 85, 75); // [50, 85, 75] 6 | -------------------------------------------------------------------------------- /Chapter02/01-Tuples/03-Spread/code.ts: -------------------------------------------------------------------------------- 1 | function logScore(score1, score2, score3) { 2 | console.log(score1 + ", " + score2 + ", " + score3); 3 | } 4 | 5 | const scores = [75, 65, 80]; 6 | 7 | logScore(...scores); // 75, 65, 80 8 | -------------------------------------------------------------------------------- /Chapter02/01-Tuples/04-OpenEndedTuples/code.ts: -------------------------------------------------------------------------------- 1 | type Scores = [string, ...number[]]; 2 | 3 | // Okay 4 | const billyScores: Scores = ["Billy", 60, 70, 75]; 5 | 6 | // Still okay! 7 | const sallyScores: Scores = ["Sally", 60, 70, 75, 70]; 8 | -------------------------------------------------------------------------------- /Chapter02/01-Tuples/05-TupleRestParameters/code.ts: -------------------------------------------------------------------------------- 1 | function logScores(...scores: [...number[]]) { 2 | console.log(scores); 3 | } 4 | 5 | logScores(50, 85, 75); // [50, 85, 75] 6 | 7 | type Scores = [string, ...number[]]; 8 | 9 | function logNameAndScores(...scores: Scores) { 10 | console.log(scores); 11 | } 12 | 13 | logNameAndScores("Billy", 60, 70, 75); 14 | 15 | logNameAndScores("Sally", 60, 70, 75, 70); 16 | -------------------------------------------------------------------------------- /Chapter02/01-Tuples/06-SpreadingTuples/code.ts: -------------------------------------------------------------------------------- 1 | function logScore(score1: number, score2: number, score3: number) { 2 | console.log(score1, score2, score3); 3 | } 4 | 5 | const scores: [number, number, number] = [75, 65, 80]; 6 | 7 | logScore(...scores); 8 | 9 | const scoresUnlimited: [...number[]] = [75, 65, 80]; 10 | 11 | logScore(...scoresUnlimited); 12 | -------------------------------------------------------------------------------- /Chapter02/01-Tuples/07-EmptyTuples/code.ts: -------------------------------------------------------------------------------- 1 | type Empty = []; 2 | 3 | // Okay 4 | const empty: Empty = []; 5 | 6 | // Error 7 | const notEmpty: Empty = ["Billy"]; 8 | 9 | type Scores = [] | [number] | [number, number] | [number, number, number]; 10 | 11 | const benScores: Scores = []; 12 | const samScores: Scores = [55]; 13 | const bobScores: Scores = [95, 75]; 14 | const jayneScores: Scores = [65, 50, 70]; 15 | const sarahScores: Scores = [95, 50, 75, 75]; 16 | -------------------------------------------------------------------------------- /Chapter02/01-Tuples/08-OptionalTuples/code.ts: -------------------------------------------------------------------------------- 1 | type Scores = [number, number?, number?]; 2 | 3 | // Okay 4 | const samScores: Scores = [55]; 5 | const bobScores: Scores = [95, 75]; 6 | const jayneScores: Scores = [65, 50, 70]; 7 | 8 | // Error 9 | const sarahScores: Scores = [95, 50, 75, 75]; 10 | const benScores: Scores = []; 11 | 12 | // Can't have required elements after optional elements 13 | type ProblematicScores = [number?, number?, number]; 14 | 15 | function logScores(...scores: Scores) { 16 | console.log(scores); 17 | } 18 | 19 | // Okay 20 | logScores(60, 70, 75); 21 | logScores(45, 80); 22 | logScores(95); 23 | 24 | // Error 25 | logScores(); 26 | logScores(45, 70, 80, 65); 27 | 28 | function logScoresEnhanced(...scores: Scores) { 29 | console.log(`${scores.length - 1} score(s) passed`); 30 | if (scores.length === 3) { 31 | console.log(scores, "Thank you for logging all 3 scores"); 32 | } else { 33 | console.log(scores); 34 | } 35 | } 36 | 37 | logScoresEnhanced(60, 70, 75); // Thank you for logging all 3 scores 38 | logScoresEnhanced(45, 80); 39 | logScoresEnhanced(95); 40 | -------------------------------------------------------------------------------- /Chapter02/02-Unknown/01-intro.ts: -------------------------------------------------------------------------------- 1 | function logScores(scores: any) { 2 | console.log(scores.firstName); 3 | console.log(scores.scores); 4 | } 5 | 6 | logScores({ 7 | name: "Billy", 8 | scores: [60, 70, 75] 9 | }); 10 | // undefined; [60, 70, 75] 11 | 12 | function logScoresBetter(scores: unknown) { 13 | console.log(scores.firstName); 14 | console.log(scores.scores); 15 | } 16 | -------------------------------------------------------------------------------- /Chapter02/02-Unknown/02-type-predicate.ts: -------------------------------------------------------------------------------- 1 | type Scores = { name: string; scores: number[] }; 2 | 3 | const scoresCheck = (scores: any): scores is Scores => { 4 | return "name" in scores && "scores" in scores; 5 | }; 6 | 7 | function logScoresWithPredicate(scores: unknown) { 8 | if (scoresCheck(scores)) { 9 | console.log(scores.firstName); 10 | console.log(scores.scores); 11 | } 12 | } 13 | 14 | logScoresWithPredicate({ 15 | name: "Billy", 16 | scores: [60, 70, 75] 17 | }); 18 | -------------------------------------------------------------------------------- /Chapter02/02-Unknown/03-instanceof.ts: -------------------------------------------------------------------------------- 1 | class Scores { 2 | name: string; 3 | scores: number[]; 4 | } 5 | 6 | function logScores(scores: unknown) { 7 | if (scores instanceof Scores) { 8 | console.log(scores.firstName); 9 | console.log(scores.scores); 10 | } 11 | } 12 | 13 | logScores({ 14 | name: "Billy", 15 | scores: [60, 70, 75] 16 | }); 17 | -------------------------------------------------------------------------------- /Chapter02/02-Unknown/04-typeassertion.ts: -------------------------------------------------------------------------------- 1 | type Scores = { name: string; scores: number[] }; 2 | 3 | function logScores(scores: unknown) { 4 | console.log((scores as Scores).firstName); 5 | console.log((scores as Scores).scores); 6 | } 7 | -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/ProjectA/dist/person.js: -------------------------------------------------------------------------------- 1 | import { randomString } from "../../Shared/dist/utils"; 2 | var Person = /** @class */ (function () { 3 | function Person() { 4 | this.id = randomString(); 5 | } 6 | return Person; 7 | }()); 8 | //# sourceMappingURL=person.js.map -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/ProjectA/dist/person.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"person.js","sourceRoot":"","sources":["../src/person.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD;IAGE;QACE,IAAI,CAAC,EAAE,GAAG,YAAY,EAAE,CAAC;IAC3B,CAAC;IACH,aAAC;AAAD,CAAC,AAND,IAMC"} -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/ProjectA/src/person.ts: -------------------------------------------------------------------------------- 1 | import { randomString } from "../../Shared/dist/utils"; 2 | 3 | class Person { 4 | id: string; 5 | name: string; 6 | constructor() { 7 | this.id = randomString(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/ProjectA/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "outDir": "dist", 5 | "module": "es6", 6 | "sourceMap": true, 7 | "noImplicitReturns": true, 8 | "noImplicitAny": true 9 | }, 10 | "include": ["src/**/*"], 11 | "references": [{ "path": "../shared" }] 12 | } 13 | -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/Shared/dist/utils.d.ts: -------------------------------------------------------------------------------- 1 | export declare function randomString(): string; 2 | //# sourceMappingURL=utils.d.ts.map -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/Shared/dist/utils.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,WAE3B"} -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/Shared/dist/utils.js: -------------------------------------------------------------------------------- 1 | export function randomString() { 2 | return Math.floor((2 + Math.random()) * 0x10000).toString(16); 3 | } 4 | //# sourceMappingURL=utils.js.map -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/Shared/dist/utils.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChE,CAAC"} -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/Shared/src/utils.ts: -------------------------------------------------------------------------------- 1 | export function randomString() { 2 | return Math.floor((2 + Math.random()) * 0x10000).toString(16); 3 | } 4 | -------------------------------------------------------------------------------- /Chapter02/03-ProjectReferences/Shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "declaration": true, 5 | "declarationMap": true, 6 | 7 | "target": "es5", 8 | "outDir": "dist", 9 | "module": "es6", 10 | "sourceMap": true, 11 | "noImplicitReturns": true, 12 | "noImplicitAny": true, 13 | "rootDir": "src" 14 | }, 15 | "include": ["src/**/*"] 16 | } 17 | -------------------------------------------------------------------------------- /Chapter02/04-DefaultProps/01-App.tsx: -------------------------------------------------------------------------------- 1 | // TypeScript 3 2 | 3 | import * as React from "react"; 4 | import "./App.css"; 5 | 6 | interface IProps { 7 | text: string; 8 | delimiter: string; 9 | } 10 | 11 | class SplitText extends React.Component { 12 | static defaultProps = { 13 | delimiter: "," 14 | }; 15 | render() { 16 | const bits = this.props.text.split(this.props.delimiter); 17 | return ( 18 | 23 | ); 24 | } 25 | } 26 | 27 | const App = () => ( 28 |
29 | 30 |
31 | ); 32 | 33 | export default App; 34 | -------------------------------------------------------------------------------- /Chapter02/04-DefaultProps/02-App.tsx: -------------------------------------------------------------------------------- 1 | // TypeScript 2.9 2 | 3 | import * as React from "react"; 4 | import "./App.css"; 5 | 6 | interface IProps { 7 | text: string; 8 | delimiter?: string; // Need to make prop optional 9 | } 10 | 11 | class SplitText extends React.Component { 12 | static defaultProps = { 13 | delimiter: "," 14 | }; 15 | render() { 16 | const bits = this.props.text.split(this.props.delimiter!); // Need to use bang because compiler thinks delimiter prop can be undefined 17 | return ( 18 | 23 | ); 24 | } 25 | } 26 | 27 | const App = () => ( 28 |
29 | 30 |
31 | ); 32 | 33 | export default App; 34 | -------------------------------------------------------------------------------- /Chapter03/01-CreatingAProjectManually/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Chapter03/01-CreatingAProjectManually/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-react-3", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --env development", 8 | "build": "webpack --env production" 9 | }, 10 | "author": "", 11 | "license": "MIT", 12 | "dependencies": { 13 | "react": "^16.5.1", 14 | "react-dom": "^16.5.1" 15 | }, 16 | "devDependencies": { 17 | "@types/react": "^16.4.14", 18 | "@types/react-dom": "^16.0.7", 19 | "ts-loader": "^5.1.1", 20 | "tslint": "^5.11.0", 21 | "typescript": "^3.0.3", 22 | "webpack": "^4.19.0", 23 | "webpack-cli": "^3.1.0", 24 | "webpack-dev-server": "^3.1.8" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Chapter03/01-CreatingAProjectManually/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | 4 | const App: React.SFC = () => { 5 | return

My React App!

; 6 | }; 7 | 8 | ReactDOM.render(, document.getElementById("root") as HTMLElement); 9 | -------------------------------------------------------------------------------- /Chapter03/01-CreatingAProjectManually/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "lib": ["es6", "dom"], 7 | "sourceMap": true, 8 | "jsx": "react", 9 | "strict": true, 10 | "noImplicitReturns": true, 11 | "rootDir": "src", 12 | "outDir": "dist" 13 | }, 14 | "include": ["**/*.ts", "**/*.tsx"], 15 | "exclude": ["node_modules"] 16 | } 17 | -------------------------------------------------------------------------------- /Chapter03/01-CreatingAProjectManually/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "linterOptions": { 4 | "exclude": ["node_modules/**/*.ts"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter03/01-CreatingAProjectManually/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./src/index.tsx", 5 | module: { 6 | rules: [ 7 | { 8 | test: /\.tsx?$/, 9 | use: "ts-loader", 10 | exclude: /node_modules/ 11 | } 12 | ] 13 | }, 14 | resolve: { 15 | extensions: [".tsx", ".ts", ".js"] 16 | }, 17 | output: { 18 | path: path.resolve(__dirname, "dist"), 19 | filename: "bundle.js" 20 | }, 21 | devServer: { 22 | contentBase: path.join(__dirname, "dist"), 23 | port: 9000 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the confirmation component built in chapter 3. 2 | To restore this: 3 | 4 | - Copy the contents of the `02-ConfirmComponent` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-components", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "^16.7.3", 9 | "@types/react-dom": "16.0.9", 10 | "react": "^16.7.0-alpha.0", 11 | "react-dom": "^16.7.0-alpha.0", 12 | "react-scripts": "2.1.1", 13 | "typescript": "3.1.6" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": "react-app" 23 | }, 24 | "browserslist": [ 25 | ">0.2%", 26 | "not dead", 27 | "not ie <= 11", 28 | "not op_mini all" 29 | ], 30 | "devDependencies": { 31 | "tslint": "^5.11.0", 32 | "tslint-config-prettier": "^1.15.0", 33 | "tslint-react": "^3.6.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter03/02-ConfirmComponent/public/favicon.ico -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | height: 200px; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: 16px; 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/src/Confirm.css: -------------------------------------------------------------------------------- 1 | .confirm-wrapper { 2 | position: fixed; 3 | left: 0; 4 | top: 0; 5 | width: 100%; 6 | height: 100%; 7 | background-color: gray; 8 | opacity: 0; 9 | visibility: hidden; 10 | transform: scale(1.1); 11 | transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s; 12 | z-index: 1; 13 | } 14 | .confirm-visible { 15 | opacity: 1; 16 | visibility: visible; 17 | transform: scale(1); 18 | transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s; 19 | } 20 | .confirm-container { 21 | background-color: #fff; 22 | position: absolute; 23 | top: 50%; 24 | left: 50%; 25 | transform: translate(-50%, -50%); 26 | border-radius: 0.2em; 27 | min-width: 300px; 28 | } 29 | .confirm-title-container { 30 | font-size: 1.3em; 31 | padding: 10px; 32 | border-top-left-radius: 0.2em; 33 | border-top-right-radius: 0.2em; 34 | } 35 | .confirm-content-container { 36 | padding: 0px 10px 15px 10px; 37 | } 38 | .confirm-buttons-container { 39 | padding: 5px 15px 10px 15px; 40 | text-align: right; 41 | } 42 | .confirm-buttons-container button { 43 | margin-left: 10px; 44 | min-width: 80px; 45 | line-height: 20px; 46 | border-style: solid; 47 | border-radius: 0.2em; 48 | padding: 3px 6px; 49 | cursor: pointer; 50 | } 51 | .confirm-cancel { 52 | background-color: #fff; 53 | border-color: #848e97; 54 | } 55 | .confirm-cancel:hover { 56 | border-color: #6c757d; 57 | } 58 | .confirm-ok { 59 | background-color: #848e97; 60 | border-color: #848e97; 61 | color: #fff; 62 | } 63 | .confirm-ok:hover { 64 | background-color: #6c757d; 65 | border-color: #6c757d; 66 | } 67 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "allowJs": true, 5 | "skipLibCheck": false, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "preserve" 16 | }, 17 | "include": [ 18 | "src" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Chapter03/02-ConfirmComponent/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "no-debugger": false, 7 | "no-console": false 8 | }, 9 | "linterOptions": { 10 | "exclude": [ 11 | "config/**/*.js", 12 | "node_modules/**/*.ts", 13 | "coverage/lcov-report/*.js" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Chapter04/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the React shop built in chapter 4. 2 | To restore this: 3 | 4 | - Copy the contents of the `04-ReactRouter` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter04/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactshop", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "^16.7.3", 9 | "@types/react-dom": "16.0.9", 10 | "react": "^16.7.0-alpha.0", 11 | "react-dom": "^16.7.0-alpha.0", 12 | "react-router-dom": "^4.3.1", 13 | "react-scripts": "2.1.1", 14 | "react-transition-group": "^2.5.0", 15 | "typescript": "3.1.6", 16 | "url-search-params-polyfill": "^5.0.0" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": "react-app" 26 | }, 27 | "browserslist": [ 28 | ">0.2%", 29 | "not dead", 30 | "not ie <= 11", 31 | "not op_mini all" 32 | ], 33 | "devDependencies": { 34 | "@types/react-router-dom": "^4.3.1", 35 | "@types/react-transition-group": "^2.0.14", 36 | "tslint": "^5.11.0", 37 | "tslint-config-prettier": "^1.15.0", 38 | "tslint-react": "^3.6.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Chapter04/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter04/public/favicon.ico -------------------------------------------------------------------------------- /Chapter04/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Chapter04/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter04/src/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const LoginPage: React.SFC = () => { 4 | return ( 5 |
6 |

Login

7 |

You need to login ...

8 |
9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /Chapter04/src/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const NotFoundPage: React.SFC = () => { 4 | return ( 5 |
6 |

Sorry, this page cannot be found

7 |
8 | ); 9 | }; 10 | 11 | export default NotFoundPage; 12 | -------------------------------------------------------------------------------- /Chapter04/src/ProductsData.ts: -------------------------------------------------------------------------------- 1 | export interface IProduct { 2 | id: number; 3 | name: string; 4 | description: string; 5 | price: number; 6 | } 7 | 8 | export const products: IProduct[] = [ 9 | { 10 | description: 11 | "A collection of navigational components that compose declaratively with your app", 12 | id: 1, 13 | name: "React Router", 14 | price: 8 15 | }, 16 | { 17 | description: "A library that helps manage state across your app", 18 | id: 2, 19 | name: "React Redux", 20 | price: 12 21 | }, 22 | { 23 | description: "A library that helps you interact with a GraphQL backend", 24 | id: 3, 25 | name: "React Apollo", 26 | price: 12 27 | } 28 | ]; 29 | -------------------------------------------------------------------------------- /Chapter04/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import Routes from "./Routes"; 5 | 6 | ReactDOM.render(, document.getElementById("root")); 7 | -------------------------------------------------------------------------------- /Chapter04/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter04/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6", "dom"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter04/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "no-debugger": false, 7 | "no-console": false 8 | }, 9 | "linterOptions": { 10 | "exclude": [ 11 | "config/**/*.js", 12 | "node_modules/**/*.ts", 13 | "coverage/lcov-report/*.js" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Chapter05/01-UnionTypes/01-StringLiterals.ts: -------------------------------------------------------------------------------- 1 | type Control = "Textbox"; 2 | 3 | let notes: Control; 4 | notes = "Textbox"; 5 | notes = "DropDown"; 6 | notes = null; 7 | notes = undefined; 8 | -------------------------------------------------------------------------------- /Chapter05/01-UnionTypes/02-StringLiteralUnion.ts: -------------------------------------------------------------------------------- 1 | type Control = "Textbox" | "DropDown" | "DatePicker" | "NumberSlider"; 2 | 3 | let notes: Control; 4 | notes = "Textbox"; 5 | notes = "DropDown"; 6 | notes = "DatePicker"; 7 | notes = "NumberSlider"; 8 | -------------------------------------------------------------------------------- /Chapter05/01-UnionTypes/03-DiscriminatedUnion.ts: -------------------------------------------------------------------------------- 1 | interface ITextbox { 2 | control: "Textbox"; 3 | value: string; 4 | multiline: boolean; 5 | } 6 | 7 | interface IDatePicker { 8 | control: "DatePicker"; 9 | value: Date; 10 | } 11 | 12 | interface INumberSlider { 13 | control: "NumberSlider"; 14 | value: number; 15 | } 16 | 17 | interface ICheckbox { 18 | control: "Checkbox"; 19 | value: boolean; 20 | } 21 | 22 | type Field = ITextbox | IDatePicker | INumberSlider | ICheckbox; 23 | 24 | function intializeValue(field: Field) { 25 | switch (field.control) { 26 | case "Textbox": 27 | field.value = ""; 28 | break; 29 | case "DatePicker": 30 | field.value = new Date(); 31 | break; 32 | case "NumberSlider": 33 | field.value = 0; 34 | break; 35 | case "Checkbox": 36 | field.value = false; 37 | break; 38 | default: 39 | const shouldNotReach: never = field; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Chapter05/02-TypeGuards/01-typeof.ts: -------------------------------------------------------------------------------- 1 | type StringOrStringArray = string | string[]; 2 | function first(stringOrArray: StringOrStringArray): string { 3 | if (typeof stringOrArray === "string") { 4 | return stringOrArray.substr(0, 1); 5 | } else { 6 | return stringOrArray[0]; 7 | } 8 | } 9 | 10 | console.log(first("The")); 11 | console.log(first(["The", "cat"])); 12 | 13 | function firstEnhanced(stringOrArray: StringOrStringArray): string { 14 | if (typeof stringOrArray === "string") { 15 | return stringOrArray.substr(0, 1); 16 | } else if (typeof stringOrArray === "object") { 17 | return stringOrArray[0]; 18 | } else { 19 | const shouldNotReach: never = stringOrArray; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Chapter05/02-TypeGuards/02-instanceof.ts: -------------------------------------------------------------------------------- 1 | class Person { 2 | id: number; 3 | firstName: string; 4 | surname: string; 5 | } 6 | 7 | class Company { 8 | id: number; 9 | name: string; 10 | } 11 | 12 | type PersonOrCompany = Person | Company; 13 | 14 | function logName(personOrCompany: PersonOrCompany) { 15 | if (personOrCompany instanceof Person) { 16 | console.log(`${personOrCompany.firstName} ${personOrCompany.surname}`); 17 | } else { 18 | console.log(personOrCompany.name); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Chapter05/02-TypeGuards/03-in.ts: -------------------------------------------------------------------------------- 1 | interface IPerson { 2 | id: number; 3 | firstName: string; 4 | surname: string; 5 | } 6 | 7 | interface ICompany { 8 | id: number; 9 | name: string; 10 | } 11 | 12 | type PersonOrCompany = IPerson | ICompany; 13 | 14 | function logName(personOrCompany: PersonOrCompany) { 15 | if ("firstName" in personOrCompany) { 16 | console.log(`${personOrCompany.firstName} ${personOrCompany.surname}`); 17 | } else { 18 | console.log(personOrCompany.name); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Chapter05/02-TypeGuards/04-TypePredicate.ts: -------------------------------------------------------------------------------- 1 | interface IPerson { 2 | id: number; 3 | firstName: string; 4 | surname: string; 5 | } 6 | 7 | interface ICompany { 8 | id: number; 9 | name: string; 10 | } 11 | 12 | type PersonOrCompany = IPerson | ICompany; 13 | 14 | function isPerson( 15 | personOrCompany: PersonOrCompany 16 | ): personOrCompany is IPerson { 17 | return "firstName" in personOrCompany; 18 | } 19 | 20 | function logName(personOrCompany: PersonOrCompany) { 21 | if (isPerson(personOrCompany)) { 22 | console.log(`${personOrCompany.firstName} ${personOrCompany.surname}`); 23 | } else { 24 | console.log(personOrCompany.name); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Chapter05/03-Generics/01-GenericFunction.ts: -------------------------------------------------------------------------------- 1 | function getData(url: string): Promise { 2 | return fetch(url).then(response => { 3 | if (!response.ok) { 4 | throw new Error(response.statusText); 5 | } 6 | return response.json(); 7 | }); 8 | } 9 | 10 | interface IPerson { 11 | id: number; 12 | name: string; 13 | } 14 | 15 | getData("/people/1").then(person => console.log(person)); 16 | -------------------------------------------------------------------------------- /Chapter05/03-Generics/02-GenericClass.ts: -------------------------------------------------------------------------------- 1 | class List { 2 | private data = []; 3 | public getList(): T[] { 4 | return this.data; 5 | } 6 | public add(item: T) { 7 | this.data.push(item); 8 | } 9 | public remove(item: T) { 10 | this.data = this.data.filter((dataItem: T) => { 11 | return !this.equals(item, dataItem); 12 | }); 13 | } 14 | private equals(obj1: T, obj2: T) { 15 | return Object.keys(obj1).every(key => { 16 | return obj1[key] === obj2[key]; 17 | }); 18 | } 19 | } 20 | 21 | interface IPerson { 22 | id: number; 23 | name: string; 24 | } 25 | const billy: IPerson = { id: 1, name: "Billy" }; 26 | 27 | const people = new List(); 28 | people.add(billy); 29 | people.remove(billy); 30 | const items = people.getList(); 31 | -------------------------------------------------------------------------------- /Chapter05/05-OverloadSignatures.ts: -------------------------------------------------------------------------------- 1 | function condenseString(string: string): string { 2 | return string.split(" ").join(""); 3 | } 4 | 5 | console.log("condenseString", condenseString("the cat sat on the mat")); 6 | 7 | function condenseArray(array: string[]): string[] { 8 | return array.map(item => item.split(" ").join("")); 9 | } 10 | 11 | console.log( 12 | "condenseArray", 13 | condenseArray(["the ", "cat ", " sat ", "on ", "the", "mat"]) 14 | ); 15 | 16 | function condense(string: string): string; 17 | function condense(array: string[]): string[]; 18 | function condense(stringOrArray: string | string[]): string | string[] { 19 | return typeof stringOrArray === "string" 20 | ? stringOrArray.split(" ").join("") 21 | : stringOrArray.map(item => item.split(" ").join("")); 22 | } 23 | 24 | const condensedText = condense("The cat sat on the mat"); 25 | console.log("condensedText", condensedText); 26 | 27 | const condensedArray = condense(["the ", "cat ", " sat ", "on ", "the", "mat"]); 28 | console.log("condense with array", condensedArray); 29 | -------------------------------------------------------------------------------- /Chapter05/06-Keyof.ts: -------------------------------------------------------------------------------- 1 | interface IPerson { 2 | id: number; 3 | name: string; 4 | age: number; 5 | } 6 | 7 | type PersonProps = keyof IPerson; 8 | 9 | class Field { 10 | name: K; 11 | label: string; 12 | defaultValue: T[K]; 13 | } 14 | 15 | const idField: Field = new Field(); 16 | idField.defaultValue = 2; 17 | 18 | const nameField: Field = new Field(); 19 | nameField.defaultValue = "Billy"; 20 | -------------------------------------------------------------------------------- /Chapter05/07-MappedTypes.ts: -------------------------------------------------------------------------------- 1 | interface IPerson { 2 | id: number; 3 | name: string; 4 | } 5 | 6 | type ReadonlyPerson = { readonly [P in keyof IPerson]: IPerson[P] }; 7 | 8 | let billy: ReadonlyPerson = { 9 | id: 1, 10 | name: "Billy" 11 | }; 12 | billy.name = "Sally"; 13 | 14 | let sally: Readonly = { 15 | id: 1, 16 | name: "Sally" 17 | }; 18 | sally.name = "Billy"; 19 | 20 | type Stringify = { [P in keyof T]: string }; 21 | let tim: Stringify = { 22 | id: "1", 23 | name: "Tim" 24 | }; 25 | -------------------------------------------------------------------------------- /Chapter06/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the React shop built in chapter 6. 2 | To restore this: 3 | 4 | - Copy the contents of the `06-ComponentPatterns` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter06/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactshop", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "^16.7.3", 9 | "@types/react-dom": "16.0.9", 10 | "react": "^16.7.0-alpha.0", 11 | "react-dom": "^16.7.0-alpha.0", 12 | "react-router-dom": "^4.3.1", 13 | "react-scripts": "2.1.1", 14 | "react-transition-group": "^2.5.0", 15 | "typescript": "3.1.6", 16 | "url-search-params-polyfill": "^5.0.0" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": "react-app" 26 | }, 27 | "browserslist": [ 28 | ">0.2%", 29 | "not dead", 30 | "not ie <= 11", 31 | "not op_mini all" 32 | ], 33 | "devDependencies": { 34 | "@types/react-router-dom": "^4.3.1", 35 | "@types/react-transition-group": "^2.0.14", 36 | "tslint": "^5.11.0", 37 | "tslint-config-prettier": "^1.15.0", 38 | "tslint-react": "^3.6.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Chapter06/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter06/public/favicon.ico -------------------------------------------------------------------------------- /Chapter06/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Chapter06/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter06/src/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const LoginPage: React.SFC = () => { 4 | return ( 5 |
6 |

Login

7 |

You need to login ...

8 |
9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /Chapter06/src/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const NotFoundPage: React.SFC = () => { 4 | return ( 5 |
6 |

Sorry, this page cannot be found

7 |
8 | ); 9 | }; 10 | 11 | export default NotFoundPage; 12 | -------------------------------------------------------------------------------- /Chapter06/src/Product.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { IProduct } from "./ProductsData"; 3 | import Tabs from "./Tabs"; 4 | import withLoader from "./withLoader"; 5 | 6 | interface IProps { 7 | product?: IProduct; 8 | inBasket: boolean; 9 | onAddToBasket: () => void; 10 | } 11 | 12 | const Product: React.SFC = props => { 13 | const product = props.product; 14 | 15 | const handleAddClick = () => { 16 | props.onAddToBasket(); 17 | }; 18 | 19 | if (!product) { 20 | return null; 21 | } 22 | 23 | return ( 24 | 25 |

{product.name}

26 | 27 | Description} 31 | > 32 |

{product.description}

33 |
34 | 35 | "Reviews"}> 36 |
    37 | {product.reviews.map(review => ( 38 |
  • 39 | "{review.comment}" - {review.reviewer} 40 |
  • 41 | ))} 42 |
43 |
44 |
45 |

46 | {new Intl.NumberFormat("en-US", { 47 | currency: "USD", 48 | style: "currency" 49 | }).format(product.price)} 50 |

51 | {!props.inBasket && ( 52 | 53 | )} 54 |
55 | ); 56 | }; 57 | 58 | export default withLoader(Product); 59 | -------------------------------------------------------------------------------- /Chapter06/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import Routes from "./Routes"; 5 | 6 | ReactDOM.render(, document.getElementById("root")); 7 | -------------------------------------------------------------------------------- /Chapter06/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter06/src/withLoader.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | interface IProps { 4 | loading: boolean; 5 | } 6 | 7 | const withLoader =

( 8 | Component: React.ComponentType

9 | ): React.SFC

=> ({ loading, ...props }: IProps) => 10 | loading ? ( 11 |

12 |
13 |
14 |
15 |
16 | ) : ( 17 | 18 | ); 19 | export default withLoader; 20 | -------------------------------------------------------------------------------- /Chapter06/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6", "dom"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter06/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "no-debugger": false, 7 | "no-console": false, 8 | "jsx-no-lambda": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the React shop built in the first section of chapter 7. 2 | To restore this: 3 | 4 | - Copy the contents of the `01-CreatingAFormWithControlledComponents` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactshop", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "^16.7.3", 9 | "@types/react-dom": "16.0.9", 10 | "react": "^16.7.0-alpha.0", 11 | "react-dom": "^16.7.0-alpha.0", 12 | "react-router-dom": "^4.3.1", 13 | "react-scripts": "2.1.1", 14 | "react-transition-group": "^2.5.0", 15 | "typescript": "3.1.6", 16 | "url-search-params-polyfill": "^5.0.0" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": "react-app" 26 | }, 27 | "browserslist": [ 28 | ">0.2%", 29 | "not dead", 30 | "not ie <= 11", 31 | "not op_mini all" 32 | ], 33 | "devDependencies": { 34 | "@types/react-router-dom": "^4.3.1", 35 | "@types/react-transition-group": "^2.0.14", 36 | "tslint": "^5.11.0", 37 | "tslint-config-prettier": "^1.15.0", 38 | "tslint-react": "^3.6.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter07/01-CreatingAFormWithControlledComponents/public/favicon.ico -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/src/ContactUsPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import ContactUs from "./ContactUs"; 3 | 4 | interface IState { 5 | name: string; 6 | email: string; 7 | reason: string; 8 | notes: string; 9 | } 10 | 11 | class ContactUsPage extends React.Component<{}, IState> { 12 | public constructor(props: {}) { 13 | super(props); 14 | this.state = { 15 | email: "", 16 | name: "", 17 | notes: "", 18 | reason: "" 19 | }; 20 | } 21 | public render() { 22 | return ( 23 |
24 |

Contact Us

25 |

26 | If you enter your details we'll get back to you as soon as we can. 27 |

28 | 38 |
39 | ); 40 | } 41 | 42 | private handleNameChange = (name: string) => { 43 | this.setState({ name }); 44 | }; 45 | private handleEmailChange = (email: string) => { 46 | this.setState({ email }); 47 | }; 48 | private handleReasonChange = (reason: string) => { 49 | this.setState({ reason }); 50 | }; 51 | private handleNotesChange = (notes: string) => { 52 | this.setState({ notes }); 53 | }; 54 | } 55 | export default ContactUsPage; 56 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/src/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const LoginPage: React.SFC = () => { 4 | return ( 5 |
6 |

Login

7 |

You need to login ...

8 |
9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/src/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const NotFoundPage: React.SFC = () => { 4 | return ( 5 |
6 |

Sorry, this page cannot be found

7 |
8 | ); 9 | }; 10 | 11 | export default NotFoundPage; 12 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/src/Product.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { IProduct } from "./ProductsData"; 3 | import Tabs from "./Tabs"; 4 | import withLoader from "./withLoader"; 5 | 6 | interface IProps { 7 | product?: IProduct; 8 | inBasket: boolean; 9 | onAddToBasket: () => void; 10 | } 11 | 12 | const Product: React.SFC = props => { 13 | const product = props.product; 14 | 15 | const handleAddClick = () => { 16 | props.onAddToBasket(); 17 | }; 18 | if (!product) { 19 | return null; 20 | } 21 | 22 | return ( 23 | 24 |

{product.name}

25 | 26 | 27 | Description} 31 | > 32 |

{product.description}

33 |
34 | "Reviews"}> 35 |
    36 | {product.reviews.map(review => ( 37 |
  • 38 | "{review.comment}" - {review.reviewer} 39 |
  • 40 | ))} 41 |
42 |
43 |
44 | 45 |

46 | {new Intl.NumberFormat("en-US", { 47 | currency: "USD", 48 | style: "currency" 49 | }).format(product.price)} 50 |

51 | {!props.inBasket && ( 52 | 53 | )} 54 |
55 | ); 56 | }; 57 | export default withLoader(Product); 58 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import Routes from "./Routes"; 5 | 6 | ReactDOM.render(, document.getElementById("root") as HTMLElement); 7 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/src/withLoader.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | interface IProps { 3 | loading: boolean; 4 | } 5 | const withLoader =

( 6 | Component: React.ComponentType

7 | ): React.SFC

=> ({ loading, ...props }: IProps) => 8 | loading ? ( 9 |

10 |
11 |
12 |
13 |
14 | ) : ( 15 | 16 | ); 17 | export default withLoader; 18 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6", "dom"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter07/01-CreatingAFormWithControlledComponents/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "no-debugger": false, 7 | "no-console": false, 8 | "jsx-no-lambda": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the React shop built in the second section of chapter 7. 2 | To restore this: 3 | 4 | - Copy the contents of the `02-ReducingBoilerplateWithGenericComponents` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactshop", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "^16.7.3", 9 | "@types/react-dom": "16.0.9", 10 | "react": "^16.7.0-alpha.0", 11 | "react-dom": "^16.7.0-alpha.0", 12 | "react-router-dom": "^4.3.1", 13 | "react-scripts": "2.1.1", 14 | "react-transition-group": "^2.5.0", 15 | "typescript": "3.1.6", 16 | "url-search-params-polyfill": "^5.0.0" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": "react-app" 26 | }, 27 | "browserslist": [ 28 | ">0.2%", 29 | "not dead", 30 | "not ie <= 11", 31 | "not op_mini all" 32 | ], 33 | "devDependencies": { 34 | "@types/react-router-dom": "^4.3.1", 35 | "@types/react-transition-group": "^2.0.14", 36 | "tslint": "^5.11.0", 37 | "tslint-config-prettier": "^1.15.0", 38 | "tslint-react": "^3.6.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter07/02-ReducingBoilerplateWithGenericComponents/public/favicon.ico -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/src/ContactUs.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Form } from "./Form"; 3 | 4 | const ContactUs: React.SFC = () => { 5 | return ( 6 |
7 | 8 | 9 | 15 | 16 | 17 | ); 18 | }; 19 | export default ContactUs; 20 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/src/ContactUsPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import ContactUs from "./ContactUs"; 3 | 4 | class ContactUsPage extends React.Component<{}, {}> { 5 | public constructor(props: {}) { 6 | super(props); 7 | this.state = { 8 | email: "", 9 | name: "", 10 | notes: "", 11 | reason: "" 12 | }; 13 | } 14 | public render() { 15 | return ( 16 |
17 |

Contact Us

18 |

19 | If you enter your details we'll get back to you as soon as we can. 20 |

21 | 22 |
23 | ); 24 | } 25 | } 26 | export default ContactUsPage; 27 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/src/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const LoginPage: React.SFC = () => { 4 | return ( 5 |
6 |

Login

7 |

You need to login ...

8 |
9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/src/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const NotFoundPage: React.SFC = () => { 4 | return ( 5 |
6 |

Sorry, this page cannot be found

7 |
8 | ); 9 | }; 10 | 11 | export default NotFoundPage; 12 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/src/Product.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { IProduct } from "./ProductsData"; 3 | import Tabs from "./Tabs"; 4 | import withLoader from "./withLoader"; 5 | 6 | interface IProps { 7 | product?: IProduct; 8 | inBasket: boolean; 9 | onAddToBasket: () => void; 10 | } 11 | 12 | const Product: React.SFC = props => { 13 | const product = props.product; 14 | 15 | const handleAddClick = () => { 16 | props.onAddToBasket(); 17 | }; 18 | if (!product) { 19 | return null; 20 | } 21 | 22 | return ( 23 | 24 |

{product.name}

25 | 26 | 27 | Description} 31 | > 32 |

{product.description}

33 |
34 | "Reviews"}> 35 |
    36 | {product.reviews.map(review => ( 37 |
  • 38 | "{review.comment}" - {review.reviewer} 39 |
  • 40 | ))} 41 |
42 |
43 |
44 | 45 |

46 | {new Intl.NumberFormat("en-US", { 47 | currency: "USD", 48 | style: "currency" 49 | }).format(product.price)} 50 |

51 | {!props.inBasket && ( 52 | 53 | )} 54 |
55 | ); 56 | }; 57 | export default withLoader(Product); 58 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import Routes from "./Routes"; 5 | 6 | ReactDOM.render(, document.getElementById("root") as HTMLElement); 7 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/src/withLoader.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | interface IProps { 3 | loading: boolean; 4 | } 5 | const withLoader =

( 6 | Component: React.ComponentType

7 | ): React.SFC

=> ({ loading, ...props }: IProps) => 8 | loading ? ( 9 |

10 |
11 |
12 |
13 |
14 | ) : ( 15 | 16 | ); 17 | export default withLoader; 18 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6", "dom"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter07/02-ReducingBoilerplateWithGenericComponents/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "no-debugger": false, 7 | "no-console": false, 8 | "jsx-no-lambda": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the React shop built in the third section of chapter 7. 2 | To restore this: 3 | 4 | - Copy the contents of the `03-ValidatingForms` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactshop", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "^16.7.3", 9 | "@types/react-dom": "16.0.9", 10 | "react": "^16.7.0-alpha.0", 11 | "react-dom": "^16.7.0-alpha.0", 12 | "react-router-dom": "^4.3.1", 13 | "react-scripts": "2.1.1", 14 | "react-transition-group": "^2.5.0", 15 | "typescript": "3.1.6", 16 | "url-search-params-polyfill": "^5.0.0" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": "react-app" 26 | }, 27 | "browserslist": [ 28 | ">0.2%", 29 | "not dead", 30 | "not ie <= 11", 31 | "not op_mini all" 32 | ], 33 | "devDependencies": { 34 | "@types/react-router-dom": "^4.3.1", 35 | "@types/react-transition-group": "^2.0.14", 36 | "tslint": "^5.11.0", 37 | "tslint-config-prettier": "^1.15.0", 38 | "tslint-react": "^3.6.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter07/03-ValidatingForms/public/favicon.ico -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/src/ContactUs.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Form, minLength, required } from "./Form"; 3 | 4 | const ContactUs: React.SFC = () => { 5 | return ( 6 |
13 | 14 | 15 | 21 | 22 | 23 | ); 24 | }; 25 | export default ContactUs; 26 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/src/ContactUsPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import ContactUs from "./ContactUs"; 3 | 4 | class ContactUsPage extends React.Component<{}, {}> { 5 | public constructor(props: {}) { 6 | super(props); 7 | this.state = { 8 | email: "", 9 | name: "", 10 | notes: "", 11 | reason: "" 12 | }; 13 | } 14 | public render() { 15 | return ( 16 |
17 |

Contact Us

18 |

19 | If you enter your details we'll get back to you as soon as we can. 20 |

21 | 22 |
23 | ); 24 | } 25 | } 26 | export default ContactUsPage; 27 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/src/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const LoginPage: React.SFC = () => { 4 | return ( 5 |
6 |

Login

7 |

You need to login ...

8 |
9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/src/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const NotFoundPage: React.SFC = () => { 4 | return ( 5 |
6 |

Sorry, this page cannot be found

7 |
8 | ); 9 | }; 10 | 11 | export default NotFoundPage; 12 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/src/Product.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { IProduct } from "./ProductsData"; 3 | import Tabs from "./Tabs"; 4 | import withLoader from "./withLoader"; 5 | 6 | interface IProps { 7 | product?: IProduct; 8 | inBasket: boolean; 9 | onAddToBasket: () => void; 10 | } 11 | 12 | const Product: React.SFC = props => { 13 | const product = props.product; 14 | 15 | const handleAddClick = () => { 16 | props.onAddToBasket(); 17 | }; 18 | if (!product) { 19 | return null; 20 | } 21 | 22 | return ( 23 | 24 |

{product.name}

25 | 26 | 27 | Description} 31 | > 32 |

{product.description}

33 |
34 | "Reviews"}> 35 |
    36 | {product.reviews.map(review => ( 37 |
  • 38 | "{review.comment}" - {review.reviewer} 39 |
  • 40 | ))} 41 |
42 |
43 |
44 | 45 |

46 | {new Intl.NumberFormat("en-US", { 47 | currency: "USD", 48 | style: "currency" 49 | }).format(product.price)} 50 |

51 | {!props.inBasket && ( 52 | 53 | )} 54 |
55 | ); 56 | }; 57 | export default withLoader(Product); 58 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import Routes from "./Routes"; 5 | 6 | ReactDOM.render(, document.getElementById("root") as HTMLElement); 7 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/src/withLoader.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | interface IProps { 3 | loading: boolean; 4 | } 5 | const withLoader =

( 6 | Component: React.ComponentType

7 | ): React.SFC

=> ({ loading, ...props }: IProps) => 8 | loading ? ( 9 |

10 |
11 |
12 |
13 |
14 | ) : ( 15 | 16 | ); 17 | export default withLoader; 18 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6", "dom"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter07/03-ValidatingForms/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "no-debugger": false, 7 | "no-console": false, 8 | "jsx-no-lambda": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the React shop built in the fourth section of chapter 7. 2 | To restore this: 3 | 4 | - Copy the contents of the `04-FormSubmission` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactshop", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "^16.7.3", 9 | "@types/react-dom": "16.0.9", 10 | "react": "^16.7.0-alpha.0", 11 | "react-dom": "^16.7.0-alpha.0", 12 | "react-router-dom": "^4.3.1", 13 | "react-scripts": "2.1.1", 14 | "react-transition-group": "^2.5.0", 15 | "typescript": "3.1.6", 16 | "url-search-params-polyfill": "^5.0.0" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": "react-app" 26 | }, 27 | "browserslist": [ 28 | ">0.2%", 29 | "not dead", 30 | "not ie <= 11", 31 | "not op_mini all" 32 | ], 33 | "devDependencies": { 34 | "@types/react-router-dom": "^4.3.1", 35 | "@types/react-transition-group": "^2.0.14", 36 | "tslint": "^5.11.0", 37 | "tslint-config-prettier": "^1.15.0", 38 | "tslint-react": "^3.6.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter07/04-FormSubmission/public/favicon.ico -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/src/ContactUs.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Form, ISubmitResult, IValues, minLength, required } from "./Form"; 3 | 4 | interface IProps { 5 | onSubmit: (values: IValues) => Promise; 6 | } 7 | 8 | const ContactUs: React.SFC = props => { 9 | const handleSubmit = async (values: IValues): Promise => { 10 | const result = await props.onSubmit(values); 11 | return result; 12 | }; 13 | return ( 14 |
22 | 23 | 24 | 30 | 31 | 32 | ); 33 | }; 34 | export default ContactUs; 35 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/src/ContactUsPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import ContactUs from "./ContactUs"; 3 | import { ISubmitResult, IValues } from "./Form"; 4 | 5 | const wait = (ms: number): Promise => { 6 | return new Promise(resolve => setTimeout(resolve, ms)); 7 | }; 8 | 9 | class ContactUsPage extends React.Component<{}, {}> { 10 | public constructor(props: {}) { 11 | super(props); 12 | this.state = { 13 | email: "", 14 | name: "", 15 | notes: "", 16 | reason: "" 17 | }; 18 | } 19 | public render() { 20 | return ( 21 |
22 |

Contact Us

23 |

24 | If you enter your details we'll get back to you as soon as we can. 25 |

26 | 27 |
28 | ); 29 | } 30 | private handleSubmit = async (values: IValues): Promise => { 31 | await wait(1000); // simulate asynchronous web API call 32 | // return { 33 | // errors: { 34 | // email: ["Some is wrong with this"] 35 | // }, 36 | // success: false 37 | // }; 38 | return { 39 | success: true 40 | }; 41 | }; 42 | } 43 | export default ContactUsPage; 44 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/src/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const LoginPage: React.SFC = () => { 4 | return ( 5 |
6 |

Login

7 |

You need to login ...

8 |
9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/src/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const NotFoundPage: React.SFC = () => { 4 | return ( 5 |
6 |

Sorry, this page cannot be found

7 |
8 | ); 9 | }; 10 | 11 | export default NotFoundPage; 12 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/src/Product.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { IProduct } from "./ProductsData"; 3 | import Tabs from "./Tabs"; 4 | import withLoader from "./withLoader"; 5 | 6 | interface IProps { 7 | product?: IProduct; 8 | inBasket: boolean; 9 | onAddToBasket: () => void; 10 | } 11 | 12 | const Product: React.SFC = props => { 13 | const product = props.product; 14 | 15 | const handleAddClick = () => { 16 | props.onAddToBasket(); 17 | }; 18 | if (!product) { 19 | return null; 20 | } 21 | 22 | return ( 23 | 24 |

{product.name}

25 | 26 | 27 | Description} 31 | > 32 |

{product.description}

33 |
34 | "Reviews"}> 35 |
    36 | {product.reviews.map(review => ( 37 |
  • 38 | "{review.comment}" - {review.reviewer} 39 |
  • 40 | ))} 41 |
42 |
43 |
44 | 45 |

46 | {new Intl.NumberFormat("en-US", { 47 | currency: "USD", 48 | style: "currency" 49 | }).format(product.price)} 50 |

51 | {!props.inBasket && ( 52 | 53 | )} 54 |
55 | ); 56 | }; 57 | export default withLoader(Product); 58 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import Routes from "./Routes"; 5 | 6 | ReactDOM.render(, document.getElementById("root") as HTMLElement); 7 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/src/withLoader.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | interface IProps { 3 | loading: boolean; 4 | } 5 | const withLoader =

( 6 | Component: React.ComponentType

7 | ): React.SFC

=> ({ loading, ...props }: IProps) => 8 | loading ? ( 9 |

10 |
11 |
12 |
13 |
14 | ) : ( 15 | 16 | ); 17 | export default withLoader; 18 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6", "dom"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter07/04-FormSubmission/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "no-debugger": false, 7 | "no-console": false, 8 | "jsx-no-lambda": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter08/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the React shop built in chapter 8. 2 | To restore this: 3 | 4 | - Copy the contents of the `08-ReactRedux` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter08/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactshop", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "^16.7.3", 9 | "@types/react-dom": "16.0.9", 10 | "react": "^16.7.0-alpha.0", 11 | "react-dom": "^16.7.0-alpha.0", 12 | "react-redux": "^5.1.0", 13 | "react-router-dom": "^4.3.1", 14 | "react-scripts": "2.1.1", 15 | "react-transition-group": "^2.5.0", 16 | "redux": "^4.0.1", 17 | "redux-thunk": "^2.3.0", 18 | "typescript": "3.1.6", 19 | "url-search-params-polyfill": "^5.0.0" 20 | }, 21 | "scripts": { 22 | "start": "react-scripts start", 23 | "build": "react-scripts build", 24 | "test": "react-scripts test", 25 | "eject": "react-scripts eject" 26 | }, 27 | "eslintConfig": { 28 | "extends": "react-app" 29 | }, 30 | "browserslist": [ 31 | ">0.2%", 32 | "not dead", 33 | "not ie <= 11", 34 | "not op_mini all" 35 | ], 36 | "devDependencies": { 37 | "@types/react-redux": "^6.0.9", 38 | "@types/react-router-dom": "^4.3.1", 39 | "@types/react-transition-group": "^2.0.14", 40 | "@types/redux-thunk": "^2.1.0", 41 | "tslint": "^5.11.0", 42 | "tslint-config-prettier": "^1.15.0", 43 | "tslint-react": "^3.6.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Chapter08/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter08/public/favicon.ico -------------------------------------------------------------------------------- /Chapter08/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Chapter08/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter08/src/BasketActions.ts: -------------------------------------------------------------------------------- 1 | import { BasketActionTypes, IBasketAdd } from "./BasketTypes"; 2 | import { IProduct } from "./ProductsData"; 3 | export const addToBasket = (product: IProduct): IBasketAdd => ({ 4 | product, 5 | type: BasketActionTypes.ADD 6 | }); 7 | -------------------------------------------------------------------------------- /Chapter08/src/BasketReducer.ts: -------------------------------------------------------------------------------- 1 | import { Reducer } from "redux"; 2 | import { BasketActions, BasketActionTypes, IBasketState } from "./BasketTypes"; 3 | 4 | const initialBasketState: IBasketState = { 5 | products: [] 6 | }; 7 | 8 | export const basketReducer: Reducer = ( 9 | state = initialBasketState, 10 | action 11 | ) => { 12 | switch (action.type) { 13 | case BasketActionTypes.ADD: { 14 | return { 15 | ...state, 16 | products: state.products.concat(action.product) 17 | }; 18 | } 19 | } 20 | return state || initialBasketState; 21 | }; 22 | -------------------------------------------------------------------------------- /Chapter08/src/BasketSummary.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | interface IProps { 3 | count: number; 4 | } 5 | const BasketSummary: React.SFC = props => { 6 | return
{props.count}
; 7 | }; 8 | export default BasketSummary; 9 | -------------------------------------------------------------------------------- /Chapter08/src/BasketTypes.ts: -------------------------------------------------------------------------------- 1 | import { IProduct } from "./ProductsData"; 2 | 3 | export enum BasketActionTypes { 4 | ADD = "BASKET/ADD" 5 | } 6 | 7 | export interface IBasketState { 8 | readonly products: IProduct[]; 9 | } 10 | 11 | export interface IBasketAdd { 12 | type: BasketActionTypes.ADD; 13 | product: IProduct; 14 | } 15 | 16 | export type BasketActions = IBasketAdd; 17 | -------------------------------------------------------------------------------- /Chapter08/src/ContactUs.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Form, ISubmitResult, IValues, minLength, required } from "./Form"; 3 | 4 | interface IProps { 5 | onSubmit: (values: IValues) => Promise; 6 | } 7 | 8 | const ContactUs: React.SFC = props => { 9 | const handleSubmit = async (values: IValues): Promise => { 10 | const result = await props.onSubmit(values); 11 | return result; 12 | }; 13 | return ( 14 |
22 | 23 | 24 | 30 | 31 | 32 | ); 33 | }; 34 | export default ContactUs; 35 | -------------------------------------------------------------------------------- /Chapter08/src/ContactUsPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import ContactUs from "./ContactUs"; 3 | import { ISubmitResult, IValues } from "./Form"; 4 | 5 | const wait = (ms: number): Promise => { 6 | return new Promise(resolve => setTimeout(resolve, ms)); 7 | }; 8 | 9 | class ContactUsPage extends React.Component<{}, {}> { 10 | public constructor(props: {}) { 11 | super(props); 12 | this.state = { 13 | email: "", 14 | name: "", 15 | notes: "", 16 | reason: "" 17 | }; 18 | } 19 | public render() { 20 | return ( 21 |
22 |

Contact Us

23 |

24 | If you enter your details we'll get back to you as soon as we can. 25 |

26 | 27 |
28 | ); 29 | } 30 | private handleSubmit = async (values: IValues): Promise => { 31 | await wait(1000); // simulate asynchronous web API call 32 | // return { 33 | // errors: { 34 | // email: ["Some is wrong with this"] 35 | // }, 36 | // success: false 37 | // }; 38 | return { 39 | success: true 40 | }; 41 | }; 42 | } 43 | export default ContactUsPage; 44 | -------------------------------------------------------------------------------- /Chapter08/src/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const LoginPage: React.SFC = () => { 4 | return ( 5 |
6 |

Login

7 |

You need to login ...

8 |
9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /Chapter08/src/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const NotFoundPage: React.SFC = () => { 4 | return ( 5 |
6 |

Sorry, this page cannot be found

7 |
8 | ); 9 | }; 10 | 11 | export default NotFoundPage; 12 | -------------------------------------------------------------------------------- /Chapter08/src/ProductsActions.ts: -------------------------------------------------------------------------------- 1 | import { ActionCreator, AnyAction, Dispatch } from "redux"; 2 | import { ThunkAction } from "redux-thunk"; 3 | import { 4 | getProduct as getProductFromAPI, 5 | getProducts as getProductsFromAPI 6 | } from "./ProductsData"; 7 | import { 8 | IProductsGetAllAction, 9 | IProductsGetSingleAction, 10 | IProductsLoadingAction, 11 | IProductsState, 12 | ProductsActionTypes 13 | } from "./ProductsTypes"; 14 | 15 | const loading: ActionCreator = () => ({ 16 | type: ProductsActionTypes.LOADING 17 | }); 18 | 19 | export const getProducts: ActionCreator< 20 | ThunkAction, IProductsState, null, IProductsGetAllAction> 21 | > = () => { 22 | return async (dispatch: Dispatch) => { 23 | dispatch(loading()); 24 | const products = await getProductsFromAPI(); 25 | return dispatch({ 26 | products, 27 | type: ProductsActionTypes.GETALL 28 | }); 29 | }; 30 | }; 31 | 32 | export const getProduct: ActionCreator< 33 | ThunkAction, IProductsState, null, IProductsGetSingleAction> 34 | > = (id: number) => { 35 | return async (dispatch: Dispatch) => { 36 | dispatch(loading()); 37 | const product = await getProductFromAPI(id); 38 | dispatch({ 39 | product, 40 | type: ProductsActionTypes.GETSINGLE 41 | }); 42 | }; 43 | }; 44 | -------------------------------------------------------------------------------- /Chapter08/src/ProductsList.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import { IProduct } from "./ProductsData"; 4 | import withLoader from "./withLoader"; 5 | 6 | interface IProps { 7 | products?: IProduct[]; 8 | search: string; 9 | } 10 | 11 | const ProductsList: React.SFC = props => { 12 | const search = props.search; 13 | return ( 14 |
    15 | {props.products && 16 | props.products.map(product => { 17 | if ( 18 | !search || 19 | (search && 20 | product.name.toLowerCase().indexOf(search.toLowerCase()) > -1) 21 | ) { 22 | return ( 23 |
  • 24 | {product.name} 25 |
  • 26 | ); 27 | } else { 28 | return null; 29 | } 30 | })} 31 |
32 | ); 33 | }; 34 | 35 | export default withLoader(ProductsList); 36 | -------------------------------------------------------------------------------- /Chapter08/src/ProductsPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { connect } from "react-redux"; 3 | import { RouteComponentProps } from "react-router-dom"; 4 | import { getProducts } from "./ProductsActions"; 5 | import { IProduct } from "./ProductsData"; 6 | import ProductsList from "./ProductsList"; 7 | import { IApplicationState } from "./Store"; 8 | 9 | import "url-search-params-polyfill"; 10 | 11 | interface IProps extends RouteComponentProps { 12 | getProducts: typeof getProducts; 13 | loading: boolean; 14 | products: IProduct[]; 15 | } 16 | 17 | class ProductsPage extends React.Component { 18 | public componentDidMount() { 19 | this.props.getProducts(); 20 | } 21 | 22 | public render() { 23 | const searchParams = new URLSearchParams(this.props.location.search); 24 | const search = searchParams.get("search") || ""; 25 | return ( 26 |
27 |

28 | Welcome to React Shop where you can get all your tools for ReactJS! 29 |

30 | 35 |
36 | ); 37 | } 38 | } 39 | 40 | const mapStateToProps = (store: IApplicationState) => { 41 | return { 42 | loading: store.products.productsLoading, 43 | products: store.products.products 44 | }; 45 | }; 46 | 47 | const mapDispatchToProps = (dispatch: any) => { 48 | return { 49 | getProducts: () => dispatch(getProducts()) 50 | }; 51 | }; 52 | 53 | export default connect( 54 | mapStateToProps, 55 | mapDispatchToProps 56 | )(ProductsPage); 57 | -------------------------------------------------------------------------------- /Chapter08/src/ProductsReducer.ts: -------------------------------------------------------------------------------- 1 | import { Reducer } from "redux"; 2 | import { 3 | IProductsState, 4 | ProductsActions, 5 | ProductsActionTypes 6 | } from "./ProductsTypes"; 7 | 8 | const initialProductState: IProductsState = { 9 | currentProduct: null, 10 | products: [], 11 | productsLoading: false 12 | }; 13 | 14 | export const productsReducer: Reducer = ( 15 | state = initialProductState, 16 | action 17 | ) => { 18 | switch (action.type) { 19 | case ProductsActionTypes.LOADING: { 20 | return { 21 | ...state, 22 | productsLoading: true 23 | }; 24 | } 25 | case ProductsActionTypes.GETALL: { 26 | return { 27 | ...state, 28 | products: action.products, 29 | productsLoading: false 30 | }; 31 | } 32 | case ProductsActionTypes.GETSINGLE: { 33 | return { 34 | ...state, 35 | currentProduct: action.product, 36 | productsLoading: false 37 | }; 38 | } 39 | } 40 | return state; 41 | }; 42 | -------------------------------------------------------------------------------- /Chapter08/src/ProductsTypes.ts: -------------------------------------------------------------------------------- 1 | import { IProduct } from "./ProductsData"; 2 | 3 | export enum ProductsActionTypes { 4 | GETALL = "PRODUCTS/GETALL", 5 | GETSINGLE = "PRODUCTS/GETSINGLE", 6 | LOADING = "PRODUCTS/LOADING" 7 | } 8 | 9 | export interface IProductsGetAllAction { 10 | type: ProductsActionTypes.GETALL; 11 | products: IProduct[]; 12 | } 13 | export interface IProductsLoadingAction { 14 | type: ProductsActionTypes.LOADING; 15 | } 16 | 17 | export interface IProductsGetSingleAction { 18 | type: ProductsActionTypes.GETSINGLE; 19 | product: IProduct; 20 | } 21 | 22 | export type ProductsActions = 23 | | IProductsGetAllAction 24 | | IProductsGetSingleAction 25 | | IProductsLoadingAction; 26 | 27 | export interface IProductsState { 28 | readonly currentProduct: IProduct | null; 29 | readonly products: IProduct[]; 30 | readonly productsLoading: boolean; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter08/src/Store.ts: -------------------------------------------------------------------------------- 1 | import { applyMiddleware, combineReducers, createStore, Store } from "redux"; 2 | import thunk from "redux-thunk"; 3 | import { basketReducer } from "./BasketReducer"; 4 | import { IBasketState } from "./BasketTypes"; 5 | import { productsReducer } from "./ProductsReducer"; 6 | import { IProductsState } from "./ProductsTypes"; 7 | 8 | export interface IApplicationState { 9 | basket: IBasketState; 10 | products: IProductsState; 11 | } 12 | 13 | const rootReducer = combineReducers({ 14 | basket: basketReducer, 15 | products: productsReducer 16 | }); 17 | 18 | export default function configureStore(): Store { 19 | const store = createStore(rootReducer, undefined, applyMiddleware(thunk)); 20 | return store; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter08/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import { Store } from "redux"; 5 | import "./index.css"; 6 | import Routes from "./Routes"; 7 | import configureStore from "./Store"; 8 | import { IApplicationState } from "./Store"; 9 | 10 | interface IProps { 11 | store: Store; 12 | } 13 | const Root: React.SFC = props => { 14 | return ( 15 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | const store = configureStore(); 22 | ReactDOM.render(, document.getElementById( 23 | "root" 24 | ) as HTMLElement); 25 | -------------------------------------------------------------------------------- /Chapter08/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter08/src/withLoader.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | interface IProps { 3 | loading: boolean; 4 | } 5 | const withLoader =

( 6 | Component: React.ComponentType

7 | ): React.SFC

=> ({ loading, ...props }: IProps) => 8 | loading ? ( 9 |

10 |
11 |
12 |
13 |
14 | ) : ( 15 | 16 | ); 17 | export default withLoader; 18 | -------------------------------------------------------------------------------- /Chapter08/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6", "dom"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter08/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "no-debugger": false, 7 | "no-console": false, 8 | "jsx-no-lambda": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter09/01-AsyncCode/01-callbacks.ts: -------------------------------------------------------------------------------- 1 | // Execution order of code with callbacks 2 | let firstName: string; 3 | setTimeout(() => { 4 | firstName = "Fred"; 5 | console.log("firstName in callback", firstName); // second 6 | }, 1000); 7 | console.log("firstName after setTimeout", firstName); // first 8 | 9 | // Errors in callback aren't caught outside of callback 10 | try { 11 | setTimeout(() => { 12 | throw new Error("Something went wrong"); 13 | }, 1000); 14 | } catch (ex) { 15 | console.log("An error has occurred", ex); // never reached 16 | } 17 | 18 | // Errors in callback have to be caught inside the callback and then managed 19 | interface IResult { 20 | success: boolean; 21 | error?: any; 22 | } 23 | let result: IResult = { success: true }; 24 | setTimeout(() => { 25 | try { 26 | throw new Error("Something went wrong"); 27 | } catch (ex) { 28 | result.success = false; 29 | result.error = ex; 30 | } 31 | }, 1000); 32 | console.log(result); 33 | 34 | // callback hell with jQuery ajax 35 | $("button").click(function() { 36 | $.get("api/resouce1", function(items) { 37 | items.array.forEach(element => { 38 | $.get("api/resouce2", function(data) { 39 | // do some stuff 40 | }); 41 | }); 42 | }); 43 | }); 44 | // => messy and hard to manage errors 45 | -------------------------------------------------------------------------------- /Chapter09/01-AsyncCode/02-promises.ts: -------------------------------------------------------------------------------- 1 | fetch("https://jsonplaceholder.typicode.com/posts") 2 | .then(response => response.json()) // returns a promise 3 | .then(data => console.log(data)) 4 | .catch(json => console.log("error", json)); 5 | // => cleaner + errors are managed nicer 6 | 7 | const wait = (ms: number) => { 8 | return new Promise((resolve, reject) => { 9 | if (ms > 1000) { 10 | reject("Too long"); 11 | } 12 | setTimeout(() => { 13 | resolve("Sucessfully waited"); 14 | }, ms); 15 | }); 16 | }; 17 | 18 | wait(1500) 19 | .then(result => console.log(result)) 20 | .catch(error => console.log(error)); 21 | -------------------------------------------------------------------------------- /Chapter09/01-AsyncCode/03-async-await.ts: -------------------------------------------------------------------------------- 1 | const someWork = async () => { 2 | // need mark asynchronous function with async keyword 3 | try { 4 | const result = await wait(1500); // need to use await keyword to call asynchronous function 5 | console.log(result); 6 | } catch (ex) { 7 | console.log(ex); 8 | } 9 | }; 10 | 11 | someWork(); 12 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the axios app built in chapter 9 with a class component. 2 | To restore this: 3 | 4 | - Copy the contents of the `03-AxiosWithClass` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crud-api", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "16.7.1", 9 | "@types/react-dom": "16.0.9", 10 | "axios": "^0.18.0", 11 | "react": "^16.7.0-alpha.0", 12 | "react-dom": "^16.7.0-alpha.0", 13 | "react-scripts": "2.1.1", 14 | "typescript": "3.1.6" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": "react-app" 24 | }, 25 | "browserslist": [ 26 | ">0.2%", 27 | "not dead", 28 | "not ie <= 11", 29 | "not op_mini all" 30 | ], 31 | "devDependencies": { 32 | "tslint": "^5.11.0", 33 | "tslint-config-prettier": "^1.15.0", 34 | "tslint-react": "^3.6.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter09/03-AxiosWithClass/public/favicon.ico -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | 16 | .posts { 17 | list-style: none; 18 | margin: 0px auto; 19 | width: 800px; 20 | text-align: left; 21 | } 22 | 23 | .error { 24 | color: red; 25 | } 26 | 27 | .post-edit { 28 | display: flex; 29 | flex-direction: column; 30 | width: 300px; 31 | margin: 0px auto; 32 | } 33 | .post-edit input { 34 | font-family: inherit; 35 | width: 100%; 36 | margin-bottom: 5px; 37 | } 38 | 39 | .post-edit textarea { 40 | font-family: inherit; 41 | width: 100%; 42 | margin-bottom: 5px; 43 | } 44 | 45 | .post-edit button { 46 | font-family: inherit; 47 | width: 100px; 48 | } 49 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "allowJs": true, 5 | "skipLibCheck": false, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "preserve" 16 | }, 17 | "include": [ 18 | "src" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Chapter09/03-AxiosWithClass/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "jsx-no-lambda": false, 7 | "no-debugger": false, 8 | "no-console": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the axios app built in chapter 9 with a function component. 2 | To restore this: 3 | 4 | - Copy the contents of the `04-AxiosWithFunction` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crud-api", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "16.7.1", 9 | "@types/react-dom": "16.0.9", 10 | "axios": "^0.18.0", 11 | "react": "^16.7.0-alpha.0", 12 | "react-dom": "^16.7.0-alpha.0", 13 | "react-scripts": "2.1.1", 14 | "typescript": "3.1.6" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": "react-app" 24 | }, 25 | "browserslist": [ 26 | ">0.2%", 27 | "not dead", 28 | "not ie <= 11", 29 | "not op_mini all" 30 | ], 31 | "devDependencies": { 32 | "tslint": "^5.11.0", 33 | "tslint-config-prettier": "^1.15.0", 34 | "tslint-react": "^3.6.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter09/04-AxiosWithFunction/public/favicon.ico -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | 16 | .posts { 17 | list-style: none; 18 | margin: 0px auto; 19 | width: 800px; 20 | text-align: left; 21 | } 22 | 23 | .error { 24 | color: red; 25 | } 26 | 27 | .post-edit { 28 | display: flex; 29 | flex-direction: column; 30 | width: 300px; 31 | margin: 0px auto; 32 | } 33 | .post-edit input { 34 | font-family: inherit; 35 | width: 100%; 36 | margin-bottom: 5px; 37 | } 38 | 39 | .post-edit textarea { 40 | font-family: inherit; 41 | width: 100%; 42 | margin-bottom: 5px; 43 | } 44 | 45 | .post-edit button { 46 | font-family: inherit; 47 | width: 100px; 48 | } 49 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "allowJs": true, 5 | "skipLibCheck": false, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "preserve" 16 | }, 17 | "include": [ 18 | "src" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Chapter09/04-AxiosWithFunction/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "jsx-no-lambda": false, 7 | "no-debugger": false, 8 | "no-console": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter10/01-QuerySyntax/Queries.txt: -------------------------------------------------------------------------------- 1 | // Basic queries 2 | 3 | query { 4 | viewer { 5 | name 6 | } 7 | } 8 | 9 | query { 10 | viewer { 11 | name 12 | avatarUrl 13 | } 14 | } 15 | 16 | 17 | // Nested data 18 | 19 | query { 20 | repository (owner:"facebook", name:"react") { 21 | name 22 | description 23 | } 24 | } 25 | 26 | query { 27 | repository (owner:"facebook", name:"react") { 28 | name 29 | description 30 | stargazers { 31 | totalCount 32 | } 33 | } 34 | } 35 | 36 | query { 37 | repository (owner:"facebook", name:"react") { 38 | name 39 | description 40 | stargazers { 41 | stars: totalCount 42 | } 43 | } 44 | } 45 | 46 | query { 47 | repository (owner:"facebook", name:"react") { 48 | name 49 | description 50 | stargazers { 51 | stars: totalCount 52 | } 53 | issues(last: 5) { 54 | edges { 55 | node { 56 | id 57 | title 58 | url 59 | publishedAt 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | // Query parameters 67 | 68 | query ($org: String!, $repo: String!) { 69 | repository (owner:$org, name:$repo) { 70 | name 71 | description 72 | stargazers { 73 | stars: totalCount 74 | } 75 | issues(last: 5) { 76 | edges { 77 | node { 78 | id 79 | title 80 | url 81 | publishedAt 82 | } 83 | } 84 | } 85 | } 86 | } 87 | { 88 | "org": "facebook", 89 | "repo": "react" 90 | } -------------------------------------------------------------------------------- /Chapter10/02-MutationSyntax/Mutations.txt: -------------------------------------------------------------------------------- 1 | mutation ($repoId: ID!) { 2 | addStar(input: { starrableId: $repoId }) { 3 | starrable { 4 | stargazers { 5 | totalCount 6 | } 7 | } 8 | } 9 | } 10 | { 11 | "repoId": "MDEwOlJlcG9zaXRvcnkxMDI3MDI1MA==" 12 | } 13 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the app built in chapter 10 with axios. 2 | To restore this: 3 | 4 | - Copy the contents of the `03-Axios` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "repo-search", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.5", 8 | "@types/react": "16.7.1", 9 | "@types/react-dom": "16.0.9", 10 | "axios": "^0.18.0", 11 | "react": "^16.7.0-alpha.0", 12 | "react-dom": "^16.7.0-alpha.0", 13 | "react-scripts": "2.1.1", 14 | "typescript": "3.1.6" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": "react-app" 24 | }, 25 | "browserslist": [ 26 | ">0.2%", 27 | "not dead", 28 | "not ie <= 11", 29 | "not op_mini all" 30 | ], 31 | "devDependencies": { 32 | "tslint": "^5.11.0", 33 | "tslint-config-prettier": "^1.15.0", 34 | "tslint-react": "^3.6.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter10/03-Axios/public/favicon.ico -------------------------------------------------------------------------------- /Chapter10/03-Axios/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 200px; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: 16px; 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | 34 | .avatar { 35 | width: 60px; 36 | border-radius: 50%; 37 | } 38 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import "./App.css"; 3 | import { Header } from "./Header"; 4 | 5 | class App extends Component { 6 | public render() { 7 | return ( 8 |
9 |
10 |
11 |
12 |
13 | ); 14 | } 15 | } 16 | 17 | export default App; 18 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/src/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import axios from "axios"; 3 | 4 | interface IViewer { 5 | name: string; 6 | avatarUrl: string; 7 | } 8 | interface IQueryResult { 9 | data: { 10 | viewer: IViewer; 11 | }; 12 | } 13 | 14 | export const Header: React.SFC = () => { 15 | const [viewer, setViewer]: [ 16 | IViewer, 17 | (viewer: IViewer) => void 18 | ] = React.useState({ name: "", avatarUrl: "" }); 19 | 20 | React.useEffect(() => { 21 | axios 22 | .post( 23 | "https://api.github.com/graphql", 24 | { 25 | query: `query { 26 | viewer { 27 | name 28 | avatarUrl 29 | } 30 | }` 31 | }, 32 | { 33 | headers: { 34 | Authorization: "bearer our-bearer-token" 35 | } 36 | } 37 | ) 38 | .then(response => { 39 | setViewer(response.data.data.viewer); 40 | }); 41 | }, []); 42 | 43 | return ( 44 |
45 | 46 |
{viewer.name}
47 |

GitHub Search

48 |
49 | ); 50 | }; 51 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "allowJs": true, 5 | "skipLibCheck": false, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "preserve" 16 | }, 17 | "include": [ 18 | "src" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Chapter10/03-Axios/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "jsx-no-lambda": false, 7 | "no-debugger": false, 8 | "no-console": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the app built in chapter 10 with apollo. 2 | To restore this: 3 | 4 | - Copy the contents of the `04-Apollo` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "repo-search", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.5", 8 | "@types/react": "16.7.1", 9 | "@types/react-dom": "16.0.9", 10 | "apollo-boost": "^0.1.20", 11 | "axios": "^0.18.0", 12 | "graphql": "^14.0.2", 13 | "react": "^16.7.0-alpha.0", 14 | "react-apollo": "^2.2.4", 15 | "react-dom": "^16.7.0-alpha.0", 16 | "react-scripts": "2.1.1", 17 | "typescript": "3.1.6" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": "react-app" 27 | }, 28 | "browserslist": [ 29 | ">0.2%", 30 | "not dead", 31 | "not ie <= 11", 32 | "not op_mini all" 33 | ], 34 | "devDependencies": { 35 | "@types/graphql": "^14.0.3", 36 | "tslint": "^5.11.0", 37 | "tslint-config-prettier": "^1.15.0", 38 | "tslint-react": "^3.6.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter10/04-Apollo/public/favicon.ico -------------------------------------------------------------------------------- /Chapter10/04-Apollo/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 200px; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: 16px; 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | 34 | .avatar { 35 | width: 60px; 36 | border-radius: 50%; 37 | } 38 | 39 | .repo-search { 40 | margin: 30px auto; 41 | width: 300px; 42 | font-family: Arial; 43 | font-size: 16px; 44 | text-align: left; 45 | } 46 | .repo-search label { 47 | display: block; 48 | margin-bottom: 3px; 49 | font-size: 14px; 50 | } 51 | .repo-search input { 52 | display: block; 53 | margin-bottom: 10px; 54 | font-size: 16px; 55 | color: #676666; 56 | width: 100%; 57 | } 58 | .repo-search button { 59 | display: block; 60 | margin-bottom: 20px; 61 | font-size: 16px; 62 | } 63 | 64 | .repo-search h4 { 65 | text-align: center; 66 | } 67 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import ApolloClient from "apollo-boost"; 3 | import { ApolloProvider } from "react-apollo"; 4 | import "./App.css"; 5 | import { Header } from "./Header"; 6 | import RepoSearch from "./RepoSearch"; 7 | 8 | const client = new ApolloClient({ 9 | uri: "https://api.github.com/graphql", 10 | headers: { 11 | authorization: `Bearer our-bearer-token` 12 | } 13 | }); 14 | 15 | class App extends Component { 16 | public render() { 17 | return ( 18 | 19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 | ); 27 | } 28 | } 29 | 30 | export default App; 31 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/src/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import gql from "graphql-tag"; 3 | import { Query } from "react-apollo"; 4 | 5 | interface IViewer { 6 | name: string; 7 | avatarUrl: string; 8 | } 9 | interface IQueryResult { 10 | viewer: IViewer; 11 | } 12 | 13 | const GET_VIEWER = gql` 14 | { 15 | viewer { 16 | name 17 | avatarUrl 18 | } 19 | } 20 | `; 21 | 22 | class GetViewerQuery extends Query {} 23 | 24 | export const Header: React.SFC = () => { 25 | return ( 26 | 27 | {({ data, loading, error }) => { 28 | if (error) { 29 | return
{error.toString()}
; 30 | } 31 | if (loading) { 32 | return
Loading ...
; 33 | } 34 | 35 | if (!data || !data.viewer) { 36 | return null; 37 | } 38 | return ( 39 |
40 | 41 |
{data.viewer.name}
42 |

GitHub Search

43 |
44 | ); 45 | }} 46 |
47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es2015", "dom", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter10/04-Apollo/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "jsx-no-lambda": false, 7 | "no-debugger": false, 8 | "no-console": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the tests built in chapter 11 on the React shop. 2 | To restore this: 3 | 4 | - Copy the contents of the `01-ReactShop` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactshop", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "^16.7.3", 9 | "@types/react-dom": "16.0.9", 10 | "react": "^16.7.0-alpha.0", 11 | "react-dom": "^16.7.0-alpha.0", 12 | "react-redux": "^5.1.0", 13 | "react-router-dom": "^4.3.1", 14 | "react-scripts": "2.1.1", 15 | "react-transition-group": "^2.5.0", 16 | "redux": "^4.0.1", 17 | "redux-thunk": "^2.3.0", 18 | "typescript": "3.1.6", 19 | "url-search-params-polyfill": "^5.0.0" 20 | }, 21 | "scripts": { 22 | "start": "react-scripts start", 23 | "build": "react-scripts build", 24 | "test": "react-scripts test --verbose=false", 25 | "eject": "react-scripts eject" 26 | }, 27 | "eslintConfig": { 28 | "extends": "react-app" 29 | }, 30 | "browserslist": [ 31 | ">0.2%", 32 | "not dead", 33 | "not ie <= 11", 34 | "not op_mini all" 35 | ], 36 | "devDependencies": { 37 | "@types/react-redux": "^6.0.9", 38 | "@types/react-router-dom": "^4.3.1", 39 | "@types/react-transition-group": "^2.0.14", 40 | "@types/redux-thunk": "^2.1.0", 41 | "react-testing-library": "^5.2.3", 42 | "tslint": "^5.11.0", 43 | "tslint-config-prettier": "^1.15.0", 44 | "tslint-react": "^3.6.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter11/01-ReactShop/public/favicon.ico -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/BasketActions.ts: -------------------------------------------------------------------------------- 1 | import { BasketActionTypes, IBasketAdd } from "./BasketTypes"; 2 | import { IProduct } from "./ProductsData"; 3 | export const addToBasket = (product: IProduct): IBasketAdd => ({ 4 | product, 5 | type: BasketActionTypes.ADD 6 | }); 7 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/BasketReducer.ts: -------------------------------------------------------------------------------- 1 | import { Reducer } from "redux"; 2 | import { BasketActions, BasketActionTypes, IBasketState } from "./BasketTypes"; 3 | 4 | const initialBasketState: IBasketState = { 5 | products: [] 6 | }; 7 | 8 | export const basketReducer: Reducer = ( 9 | state = initialBasketState, 10 | action 11 | ) => { 12 | switch (action.type) { 13 | case BasketActionTypes.ADD: { 14 | return { 15 | ...state, 16 | products: state.products.concat(action.product) 17 | }; 18 | } 19 | } 20 | return state || initialBasketState; 21 | }; 22 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/BasketSummary.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | interface IProps { 3 | count: number; 4 | } 5 | const BasketSummary: React.SFC = props => { 6 | return
{props.count}
; 7 | }; 8 | export default BasketSummary; 9 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/BasketTypes.ts: -------------------------------------------------------------------------------- 1 | import { IProduct } from "./ProductsData"; 2 | 3 | export enum BasketActionTypes { 4 | ADD = "BASKET/ADD" 5 | } 6 | 7 | export interface IBasketState { 8 | readonly products: IProduct[]; 9 | } 10 | 11 | export interface IBasketAdd { 12 | type: BasketActionTypes.ADD; 13 | product: IProduct; 14 | } 15 | 16 | export type BasketActions = IBasketAdd; 17 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/ContactUs.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Form, ISubmitResult, IValues, minLength, required } from "./Form"; 3 | 4 | interface IProps { 5 | onSubmit: (values: IValues) => Promise; 6 | } 7 | 8 | const ContactUs: React.SFC = props => { 9 | const handleSubmit = async (values: IValues): Promise => { 10 | const result = await props.onSubmit(values); 11 | return result; 12 | }; 13 | return ( 14 |
22 | 23 | 24 | 30 | 31 | 32 | ); 33 | }; 34 | export default ContactUs; 35 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/ContactUsPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import ContactUs from "./ContactUs"; 3 | import { ISubmitResult, IValues } from "./Form"; 4 | 5 | const wait = (ms: number): Promise => { 6 | return new Promise(resolve => setTimeout(resolve, ms)); 7 | }; 8 | 9 | class ContactUsPage extends React.Component<{}, {}> { 10 | public constructor(props: {}) { 11 | super(props); 12 | this.state = { 13 | email: "", 14 | name: "", 15 | notes: "", 16 | reason: "" 17 | }; 18 | } 19 | public render() { 20 | return ( 21 |
22 |

Contact Us

23 |

24 | If you enter your details we'll get back to you as soon as we can. 25 |

26 | 27 |
28 | ); 29 | } 30 | private handleSubmit = async (values: IValues): Promise => { 31 | await wait(1000); // simulate asynchronous web API call 32 | // return { 33 | // errors: { 34 | // email: ["Some is wrong with this"] 35 | // }, 36 | // success: false 37 | // }; 38 | return { 39 | success: true 40 | }; 41 | }; 42 | } 43 | export default ContactUsPage; 44 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/Form.test.tsx: -------------------------------------------------------------------------------- 1 | import { required, IValues } from "./Form"; 2 | 3 | describe("required", () => { 4 | test("When required called with title being an empty string, an error should be 'This must be populated'", () => { 5 | // debugger; 6 | const values: IValues = { 7 | title: "" 8 | }; 9 | // console.log("values:", values); 10 | const result = required("title", values); 11 | // console.log("result:", result); 12 | expect(result).toBe("This must be populated"); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/LoginPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const LoginPage: React.SFC = () => { 4 | return ( 5 |
6 |

Login

7 |

You need to login ...

8 |
9 | ); 10 | }; 11 | 12 | export default LoginPage; 13 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/NotFoundPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | const NotFoundPage: React.SFC = () => { 4 | return ( 5 |
6 |

Sorry, this page cannot be found

7 |
8 | ); 9 | }; 10 | 11 | export default NotFoundPage; 12 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/ProductsActions.ts: -------------------------------------------------------------------------------- 1 | import { ActionCreator, AnyAction, Dispatch } from "redux"; 2 | import { ThunkAction } from "redux-thunk"; 3 | import { 4 | getProduct as getProductFromAPI, 5 | getProducts as getProductsFromAPI 6 | } from "./ProductsData"; 7 | import { 8 | IProductsGetAllAction, 9 | IProductsGetSingleAction, 10 | IProductsLoadingAction, 11 | IProductsState, 12 | ProductsActionTypes 13 | } from "./ProductsTypes"; 14 | 15 | const loading: ActionCreator = () => ({ 16 | type: ProductsActionTypes.LOADING 17 | }); 18 | 19 | export const getProducts: ActionCreator< 20 | ThunkAction, IProductsState, null, IProductsGetAllAction> 21 | > = () => { 22 | return async (dispatch: Dispatch) => { 23 | dispatch(loading()); 24 | const products = await getProductsFromAPI(); 25 | return dispatch({ 26 | products, 27 | type: ProductsActionTypes.GETALL 28 | }); 29 | }; 30 | }; 31 | 32 | export const getProduct: ActionCreator< 33 | ThunkAction, IProductsState, null, IProductsGetSingleAction> 34 | > = (id: number) => { 35 | return async (dispatch: Dispatch) => { 36 | dispatch(loading()); 37 | const product = await getProductFromAPI(id); 38 | dispatch({ 39 | product, 40 | type: ProductsActionTypes.GETSINGLE 41 | }); 42 | }; 43 | }; 44 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/ProductsList.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import { IProduct } from "./ProductsData"; 4 | import withLoader from "./withLoader"; 5 | 6 | interface IProps { 7 | products?: IProduct[]; 8 | search: string; 9 | } 10 | 11 | const ProductsList: React.SFC = props => { 12 | const search = props.search; 13 | return ( 14 |
    15 | {props.products && 16 | props.products.map(product => { 17 | if ( 18 | !search || 19 | (search && 20 | product.name.toLowerCase().indexOf(search.toLowerCase()) > -1) 21 | ) { 22 | return ( 23 |
  • 24 | {product.name} 25 |
  • 26 | ); 27 | } else { 28 | return null; 29 | } 30 | })} 31 |
32 | ); 33 | }; 34 | 35 | export default withLoader(ProductsList); 36 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/ProductsPage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { connect } from "react-redux"; 3 | import { RouteComponentProps } from "react-router-dom"; 4 | import { getProducts } from "./ProductsActions"; 5 | import { IProduct } from "./ProductsData"; 6 | import ProductsList from "./ProductsList"; 7 | import { IApplicationState } from "./Store"; 8 | 9 | import "url-search-params-polyfill"; 10 | 11 | interface IProps extends RouteComponentProps { 12 | getProducts: typeof getProducts; 13 | loading: boolean; 14 | products: IProduct[]; 15 | } 16 | 17 | class ProductsPage extends React.Component { 18 | public componentDidMount() { 19 | this.props.getProducts(); 20 | } 21 | 22 | public render() { 23 | const searchParams = new URLSearchParams(this.props.location.search); 24 | const search = searchParams.get("search") || ""; 25 | return ( 26 |
27 |

28 | Welcome to React Shop where you can get all your tools for ReactJS! 29 |

30 | 35 |
36 | ); 37 | } 38 | } 39 | 40 | const mapStateToProps = (store: IApplicationState) => { 41 | return { 42 | loading: store.products.productsLoading, 43 | products: store.products.products 44 | }; 45 | }; 46 | 47 | const mapDispatchToProps = (dispatch: any) => { 48 | return { 49 | getProducts: () => dispatch(getProducts()) 50 | }; 51 | }; 52 | 53 | export default connect( 54 | mapStateToProps, 55 | mapDispatchToProps 56 | )(ProductsPage); 57 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/ProductsReducer.ts: -------------------------------------------------------------------------------- 1 | import { Reducer } from "redux"; 2 | import { 3 | IProductsState, 4 | ProductsActions, 5 | ProductsActionTypes 6 | } from "./ProductsTypes"; 7 | 8 | const initialProductState: IProductsState = { 9 | currentProduct: null, 10 | products: [], 11 | productsLoading: false 12 | }; 13 | 14 | export const productsReducer: Reducer = ( 15 | state = initialProductState, 16 | action 17 | ) => { 18 | switch (action.type) { 19 | case ProductsActionTypes.LOADING: { 20 | return { 21 | ...state, 22 | productsLoading: true 23 | }; 24 | } 25 | case ProductsActionTypes.GETALL: { 26 | return { 27 | ...state, 28 | products: action.products, 29 | productsLoading: false 30 | }; 31 | } 32 | case ProductsActionTypes.GETSINGLE: { 33 | return { 34 | ...state, 35 | currentProduct: action.product, 36 | productsLoading: false 37 | }; 38 | } 39 | } 40 | return state; 41 | }; 42 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/ProductsTypes.ts: -------------------------------------------------------------------------------- 1 | import { IProduct } from "./ProductsData"; 2 | 3 | export enum ProductsActionTypes { 4 | GETALL = "PRODUCTS/GETALL", 5 | GETSINGLE = "PRODUCTS/GETSINGLE", 6 | LOADING = "PRODUCTS/LOADING" 7 | } 8 | 9 | export interface IProductsGetAllAction { 10 | type: ProductsActionTypes.GETALL; 11 | products: IProduct[]; 12 | } 13 | export interface IProductsLoadingAction { 14 | type: ProductsActionTypes.LOADING; 15 | } 16 | 17 | export interface IProductsGetSingleAction { 18 | type: ProductsActionTypes.GETSINGLE; 19 | product: IProduct; 20 | } 21 | 22 | export type ProductsActions = 23 | | IProductsGetAllAction 24 | | IProductsGetSingleAction 25 | | IProductsLoadingAction; 26 | 27 | export interface IProductsState { 28 | readonly currentProduct: IProduct | null; 29 | readonly products: IProduct[]; 30 | readonly productsLoading: boolean; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/Store.ts: -------------------------------------------------------------------------------- 1 | import { applyMiddleware, combineReducers, createStore, Store } from "redux"; 2 | import thunk from "redux-thunk"; 3 | import { basketReducer } from "./BasketReducer"; 4 | import { IBasketState } from "./BasketTypes"; 5 | import { productsReducer } from "./ProductsReducer"; 6 | import { IProductsState } from "./ProductsTypes"; 7 | 8 | export interface IApplicationState { 9 | basket: IBasketState; 10 | products: IProductsState; 11 | } 12 | 13 | const rootReducer = combineReducers({ 14 | basket: basketReducer, 15 | products: productsReducer 16 | }); 17 | 18 | export default function configureStore(): Store { 19 | const store = createStore(rootReducer, undefined, applyMiddleware(thunk)); 20 | return store; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import { Store } from "redux"; 5 | import "./index.css"; 6 | import Routes from "./Routes"; 7 | import configureStore from "./Store"; 8 | import { IApplicationState } from "./Store"; 9 | 10 | interface IProps { 11 | store: Store; 12 | } 13 | const Root: React.SFC = props => { 14 | return ( 15 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | const store = configureStore(); 22 | ReactDOM.render(, document.getElementById( 23 | "root" 24 | ) as HTMLElement); 25 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/src/withLoader.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | interface IProps { 3 | loading: boolean; 4 | } 5 | const withLoader =

( 6 | Component: React.ComponentType

7 | ): React.SFC

=> ({ loading, ...props }: IProps) => 8 | loading ? ( 9 |

10 |
11 |
12 |
13 |
14 | ) : ( 15 | 16 | ); 17 | export default withLoader; 18 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6", "dom"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter11/01-ReactShop/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "no-debugger": false, 7 | "no-console": false, 8 | "jsx-no-lambda": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/README.md: -------------------------------------------------------------------------------- 1 | This project contains the completed code for the tests built in chapter 11 that included a mocked REST API. 2 | To restore this: 3 | 4 | - Copy the contents of the `02-MockingRESTAPI` folder into a folder of your choice 5 | - Open the folder in Visual Studio Code 6 | - Run the following command in the Terminal: 7 | 8 | ``` 9 | npm install 10 | ``` 11 | 12 | The following Terminal command will then run the project in the web development server: 13 | 14 | ``` 15 | npm start 16 | ``` 17 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crud-api", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.9", 7 | "@types/node": "10.12.2", 8 | "@types/react": "16.7.1", 9 | "@types/react-dom": "16.0.9", 10 | "axios": "^0.18.0", 11 | "react": "^16.7.0-alpha.0", 12 | "react-dom": "^16.7.0-alpha.0", 13 | "react-scripts": "2.1.1", 14 | "typescript": "3.1.6" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "test-coverage": "react-scripts test --coverage", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": "react-app" 25 | }, 26 | "browserslist": [ 27 | ">0.2%", 28 | "not dead", 29 | "not ie <= 11", 30 | "not op_mini all" 31 | ], 32 | "devDependencies": { 33 | "axios-mock-adapter": "^1.15.0", 34 | "react-testing-library": "^5.2.3", 35 | "tslint": "^5.11.0", 36 | "tslint-config-prettier": "^1.15.0", 37 | "tslint-react": "^3.6.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Learn-React-with-TypeScript-3/9edf966988a2780e88dd5bd932928ac6e2bdd5fe/Chapter11/02-MockingRESTAPI/public/favicon.ico -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./App"; 4 | import { render, cleanup, waitForElement } from "react-testing-library"; 5 | import axios from "axios"; 6 | import MockAdapter from "axios-mock-adapter"; 7 | 8 | afterEach(cleanup); 9 | 10 | describe("App", () => { 11 | test("When page loads, posts are rendered", async () => { 12 | const mock = new MockAdapter(axios); 13 | mock.onGet("https://jsonplaceholder.typicode.com/posts").reply(200, [ 14 | { 15 | userId: 1, 16 | id: 1, 17 | title: "title test 1", 18 | body: "body test 1" 19 | }, 20 | { 21 | userId: 1, 22 | id: 2, 23 | title: "title test 2", 24 | body: "body test 2" 25 | } 26 | ]); 27 | 28 | const { getByTestId } = render(); 29 | 30 | const postsList: any = await waitForElement(() => getByTestId("posts")); 31 | 32 | expect(postsList).toMatchSnapshot(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/src/__snapshots__/App.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`App When page loads, posts are rendered 1`] = ` 4 |
    8 |
  • 9 |

    10 | title test 1 11 |

    12 |

    13 | body test 1 14 |

    15 | 18 | 21 |
  • 22 |
  • 23 |

    24 | title test 2 25 |

    26 |

    27 | body test 2 28 |

    29 | 32 | 35 |
  • 36 |
37 | `; 38 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | 16 | .posts { 17 | list-style: none; 18 | margin: 0px auto; 19 | width: 800px; 20 | text-align: left; 21 | } 22 | 23 | .error { 24 | color: red; 25 | } 26 | 27 | .post-edit { 28 | display: flex; 29 | flex-direction: column; 30 | width: 300px; 31 | margin: 0px auto; 32 | } 33 | .post-edit input { 34 | font-family: inherit; 35 | width: 100%; 36 | margin-bottom: 5px; 37 | } 38 | 39 | .post-edit textarea { 40 | font-family: inherit; 41 | width: 100%; 42 | margin-bottom: 5px; 43 | } 44 | 45 | .post-edit button { 46 | font-family: inherit; 47 | width: 100px; 48 | } 49 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "es2015"], 5 | "allowJs": true, 6 | "skipLibCheck": false, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /Chapter11/02-MockingRESTAPI/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "ordered-imports": false, 5 | "object-literal-sort-keys": false, 6 | "jsx-no-lambda": false, 7 | "no-debugger": false, 8 | "no-console": false 9 | }, 10 | "linterOptions": { 11 | "exclude": [ 12 | "config/**/*.js", 13 | "node_modules/**/*.ts", 14 | "coverage/lcov-report/*.js" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Packt 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 | --------------------------------------------------------------------------------