Step 2-01 updates

This commit is contained in:
Elizabeth Craig
2019-02-27 20:17:08 -08:00
parent fdceb93839
commit 61ae8afdf1
11 changed files with 126 additions and 81 deletions

View File

@@ -2,56 +2,83 @@
[Lessons](../) | [Exercise](./exercise/) | [Demo](./demo/)
In this step, we'll cover enough of the TypeScript concepts to be productive with the React & Redux frameworks.
In this step, we'll cover enough TypeScript concepts to be productive with the React & Redux frameworks.
Topics in this step will include:
- ES modules
- Basic Types
- Interfaces & Classes
- Basic Generics
- Spread and Destructuring
- Async / Await
- [ES modules](#modules)
- [Types](#typescript-types)
- [Spread](#spread-operator) and [Destructuring](#destructuring)
- [Promise](#promise) and [Async / Await](#async--await)
> To try out TypeScript concepts and see the corresponding JavaScript, you can use the [TypeScript playground](http://www.typescriptlang.org/play/index.html). We won't be using it in this training, but it's very handy in general!
## Modules
Historically, JS is only executed in browser. The code all had to be loaded from `<script>` tags. Since the introduction of node.js, the JS community needed a way to scale beyond just single script files. Other language support the notion of modules. There are many JS modularity standards today.
Historically, JS was only executed in-browser. The code all had to be loaded using `<script>` tags. With the introduction of node.js, the JS community needed a way to scale beyond just single script files. Other languages support the notion of modules, so various groups started developing modularity standards for JS.
The most important ones to know about are:
- commonjs - Node.js's standard to support modules
- synchronous
- require() function, can be dynamically called in the course of a program
- ESM (ECMAScript module) - language level support
- **commonjs** - Node.js's standard to support modules
- synchronous loading using `require()` function
- `require()` can be dynamically called in the course of a program
- **ESM (ECMAScript module)** - language-level support
- statically analyzable and synchronous
- dynamic and asynchronous support via `import()` that returns a promise
> For more information about the *many* modularity patterns and standards developed over time, see [this article](https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc). You may still encounter some of the older patterns in legacy code.
## TypeScript Types
Refer to the `demo/src` for some examples of some of the types available in TS that benefits a React developer.
Refer to [`demo/src`](./demo/src) for examples of some of the types available in TS that benefit a React developer.
## Spread Syntax
## Spread Operator
Spread syntax allows for quick way to clone and concatenate objects and arrays. This syntax is seen a lot inside React props and Redux reducers.
The spread operator `...` provides a quick way to clone and concatenate objects and arrays. This syntax is seen a lot inside React props and Redux reducers.
To shallow copy something:
With objects:
```ts
const cloned = { ...obj };
```
// Shallow copy an object
const cloned1 = { ...obj };
To shallow copy and add / overwrite a key:
// Shallow copy and add/overwrite a key
const overridden1 = { ...obj, key: value };
```ts
const overridden = { ...obj, key: value };
```
// Shallow copy multiple objects and add a key
const cloned2 = { ...obj1, ...obj2, key: value };
You can have an expression to calculate this key if it is dynamic:
```ts
// Use an expression to calculate a key dynamically
const overridden = { ...object, [key + '-suffix']: value };
```
With arrays:
```ts
const copy1 = [...arr];
const copy2 = [...arr1, ...arr2];
const copyWithExtras = [123, ...arr, 'hello'];
```
Spreading an array into positional arguments to a function:
```ts
function myFunc(a: number, b: number, c: number) {
// ...
}
const arr = [1, 2, 3];
myFunc(...arr);
```
Spreading an object into props for a React component:
```tsx
const obj = { a: 1, b: 2, c: 3 };
// equivalent to:
// <MyComponent a={obj.a} b={obj.b} c={obj.c} />
const rendered = <MyComponent {...obj} />;
```
## Destructuring
Destructuring is a concise way to take properties out of an object or array:
@@ -60,32 +87,31 @@ Destructuring is a concise way to take properties out of an object or array:
const obj = { foo: 1, bar: 2 };
const { foo, bar } = obj;
// foo = 1, bar = 2
```
Same thing for array:
```ts
const arr = [1, 2];
const [foo, bar] = arr;
// foo = 1, bar = 2
```
You can separate an item and the rest of the object with destructuring:
You can separate an item from the rest of the object with destructuring:
```ts
const obj = { a: 1, b: 2, c: 3, d: 4 };
const { a, ...rest } = obj;
// a = 1, rest = {b: 2, c: 3, d: 4}
const arr = [1, 2, 3];
const [foo, ...bar] = arr;
// foo = 1, bar = [2, 3]
```
# Promise
## Promise
A promise is an object that represent work that will be completed later, asynchronously. It is a chainable so writing async code is maintainable. Typically legacy async code uses callback to let the caller have control over what to do after the task has been completed.
A promise is an object representing work that will be completed later, asynchronously. Promises are chainable, which helps with writing maintainable async code. (Typically, legacy async code uses callbacks to let the caller have control over what to do after the task has been completed, which becomes very hard to read.)
```ts
const aPromise = new Promise((resolve, reject) => {
// do something async and call resolve() to let promise know it is done
setTimeout(() => {
// setTimeout will call this method after 1s, simulating async operation like network calls
resolve();
@@ -93,10 +119,11 @@ const aPromise = new Promise((resolve, reject) => {
});
```
The promise object exposes a `then()` function that is chainable. `catch()` is present that catches all exceptions or `reject()` calls:
Each promise instance exposes a `then()` function that is chainable. It also provides `catch()`, which catches all exceptions or `reject()` calls:
```ts
const aPromise = Promise.resolve('hello world'); /* ... just an example promise */
// Promise.resolve() creates an already-resolved promise instance
const aPromise = Promise.resolve('hello world');
aPromise
.then(result => {
@@ -110,9 +137,11 @@ aPromise
});
```
# Async / Await
> For more information, see [this overview of promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) or [this deep dive](https://developers.google.com/web/fundamentals/primers/promises).
This syntax is inspired heavily by C#'s async / await syntax. To write an async function write it like this:
## Async / Await
This syntax is inspired heavily by C#'s async / await syntax. An async function is written like this:
```ts
async function someFunctionAsync() {
@@ -122,7 +151,7 @@ async function someFunctionAsync() {
}
```
All functions that are marked `async` return a `Promise` automatically. This previous example returned a `Promise<string>`, and can be used like this:
All functions that are marked `async` return a `Promise` automatically. The previous example returned a `Promise<string>`, and can be used like this:
```ts
someFunctionAsync().then(result => {
@@ -130,27 +159,29 @@ someFunctionAsync().then(result => {
});
```
> For more information, see [this article](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function).
# Exercise
Please complete all exercises inside the `exercise/src` folder unless otherwise specified in the exercises below. First, open up [Step2-01 exercise page](http://localhost:8080/step2-01/exercise/) to see the results while you're implementing things.
Please complete all exercises inside the `exercise/src` folder unless otherwise specified. First, open up [Step2-01 exercise page](http://localhost:8080/step2-01/exercise/) to see the results while you're implementing things.
## Modules
1. Open up file called `index.ts` in VS Code
1. Open the file called `index.ts` in VS Code
2. Create another module file called `fibonacci.ts`
3. Inside the file from (step 2), write a function called `fib(n)` that takes in a number and returns a the n-th Fibonacci number - be sure the specify the type of n
3. Inside the file from (step 2), write a function called `fib(n)` that takes in a number and returns the `n`-th Fibonacci number (be sure the specify the type of `n`).
> HINT: function fib(n: number) { return n <= 1 ? n : fib(n - 1) + fib(n - 2); }
> HINT: `function fib(n: number) { return n <= 1 ? n : fib(n - 1) + fib(n - 2); }`
4. Export `fib(n)` as a **named export**
5. Export another const variable as a **default export**
6. Inside `index.ts` Import both the modules created in steps (4) and (5) and use the built-in `console.log()` function to log the result of `fib(FibConst)`.
6. Inside `index.ts`, import both of the modules created in steps (4) and (5) and use the built-in `console.log()` function to log the result of `fib(FibConst)`.
## Types, Interfaces, and Classes
## Types and Interfaces
Inside `index.ts`:
@@ -158,15 +189,15 @@ Inside `index.ts`:
2. Describe a type of car with an interface: `interface Car { ... }` complete with `wheels`, `color`, `make`, `model`
## Generic
## Generics
Inside `stack.ts`, create a generic class for a `Stack<T>` complete with a typed `pop()` and `push()` methods
Inside `stack.ts`, create a generic class for a `Stack<T>` complete with a typed `pop()` and `push()` methods.
> Hint: the JavaScript array already has `push()` and `pop()` implemented for you. That can be your backing store.
Be sure to use the built-in `console.log()` to show the functionality of `Stack<T>`
Be sure to use the built-in `console.log()` to show the functionality of `Stack<T>`.
## Spread and Destructure
## Spread and Destructuring
1. Note the following code in index.ts:
@@ -187,11 +218,11 @@ const obj2 = {
2. Now create a one-liner using the spread syntax `{...x, ...y}` to create a new variable that combines these two objects.
3. Using the destructuring syntax to retrieve the values for `{first, second, catcher}` from this new object created in step (2).
3. Use the destructuring syntax to retrieve the values for `{first, second, catcher}` from the new object created in step (2).
## Async / Await
1. Note the following code in index.ts:
Note the following code in index.ts:
```ts
function makePromise() {
@@ -199,6 +230,6 @@ function makePromise() {
}
```
2. call `makePromise()` with the `await` syntax and log the results using the provided `log()` function
1. Call `makePromise()` with the `await` syntax and log the results using the provided `log()` function.
3. create a new function that uses the `async` keyword to create an async function. Make an await call to `makePromise()` and return the results
2. Create a new function that uses the `async` keyword. Make an `await` call to `makePromise()` and return the results.

View File

@@ -6,7 +6,7 @@
<body class="ms-Fabric">
<div id="markdownReadme"></div>
<div id="app">
Nothing to show here, just look at your console window for output. Hit F12 to open console window.
Nothing to show here; just look at your console window for output. Hit F12 (<code>cmd+option+I</code> on Mac) to open console window.
</div>
<script src="../../assets/scripts.js"></script>
</body>

View File

@@ -3,10 +3,10 @@ async function fetchSomething() {
return await response.text();
}
// Async functions always returns Promise
// Async functions always return a Promise
fetchSomething().then(text => {
console.log('hello ' + text);
});
// adding an export to turn this into a "module"
// adding an export turns this into a "module"
export default {};

View File

@@ -19,5 +19,5 @@ function reverse<T>(arg: T[]): T[] {
return arg;
}
// adding an export to turn this into a "module"
// adding an export turns this into a "module"
export default {};

View File

@@ -1,22 +1,32 @@
// Interface for an object or class
interface Car {
make: string;
model: string;
}
class MyCar implements Car {
make: 'Honda';
model: 'Accord';
}
make: string;
model: string;
const myCar: Car = {
constructor(make: string, model: string) {
this.make = make;
this.model = model;
}
}
const myCar1: Car = new MyCar('Honda', 'Accord');
const myCar2: Car = {
make: 'Honda',
model: 'Accord'
};
// Interface as Functions
// Interface for a function
interface InterestingFn {
(someArgs: string): number;
}
const interesting: InterestingFn = (someArgs: string): number => {
return Number(someArgs);
};
// adding an export to turn this into a "module"
export default {};

View File

@@ -1,10 +1,10 @@
// These are named imports from a file relative to this file
import { namedConst, namedFn, namedObj, namedConstBracket } from './named';
// We can even apply an alias to the named constant
// We can even give an alias to the named constant
import { namedConst as c } from './named';
// These are the same instances of the named imports, but gets imported all at the same time under a single object
// These are the *same instances* of the named imports, but they all get imported inside a single object
import * as named from './named';
// Print out the exports
@@ -14,12 +14,15 @@ console.log(namedFn());
console.log(namedObj);
console.log(namedConstBracket);
// Print out exports through module level import
// Print out exports from module level import
console.log(named.namedConst);
console.log(named.namedFn());
console.log(named.namedObj);
console.log(named.namedConstBracket);
// The named and module-level imports reference the same object instances
console.log(namedObj === named.namedObj); // true
// Default import can be named anything we want as the consumer
import DefaultClass from './default';
import Foo from './default';

View File

@@ -1,6 +1,6 @@
// Destructuring
var [a, b, ...rest] = [1, 2, 3, 4];
console.log(a, b, rest); // 1,2,[3,4]
console.log(a, b, rest); // 1 2 [3,4]
// Array assignment
var list = [1, 2];
@@ -20,5 +20,5 @@ const obj3 = { ...obj1, ...obj2 };
// Destructuring object
const { x } = obj3;
// adding an export to turn this into a "module"
// adding an export turns this into a "module"
export default {};

View File

@@ -47,13 +47,18 @@ let choose1 = <Specific1>{ common: '5' };
type CatStatus = 'alive' | 'dead' | 'both';
// Classes
class Animal {}
class Animal { }
// Illustration purposes only
// In real apps, avoid inheritance if possible
// noted exception: React.Component with react@<16.8.0
class Cat extends Animal {}
class Dog extends Animal {}
class Cat extends Animal { }
class Dog extends Animal { }
// adding an export to turn this into a "module"
// Any Type - avoid if possible
let mystery: any = "I don't like the person who will be maintaining this code";
mystery = 2;
mystery = () => 3;
// adding an export turns this into a "module"
export default {};

View File

@@ -6,7 +6,7 @@
<body class="ms-Fabric">
<div id="markdownReadme"></div>
<div id="app">
Nothing to show here, just look at your console window for output. Hit F12 to open console window.
Nothing to show here; just look at your console window for output. Hit F12 (<code>cmd+option+I</code> on Mac) to open the console window.
</div>
<script src="../../assets/scripts.js"></script>
</body>

View File

@@ -19,12 +19,12 @@ function makePromise() {
return Promise.resolve(5);
}
// Do the exercises here, output your results with "console.log()" function
// Do the exercises here, outputting results using console.log()
// ...
console.log('hello world');
async function run() {
// Place your code for the async / await exercise here
// Call the function you added for the async / await exercise here
// ...
}

View File

@@ -1,10 +1,6 @@
// TODO: create a Stack<T> generic class here:
/**
*
* export class Stack<T> {
* push(...) { ... }
* pop(...) { ... }
* }
*
*/
// export class Stack<T> {
// push(...) { ... }
// pop(...) { ... }
// }