Year #2, Week #17 đť đś
New stuff we learned this week: đ¤
static keyword
- in Javascript, the
static
keyword defines a static method or static property. Static methods and properties are often used for utility functionality related to the class, but that doesnât make sense to be available as a normal instance property or method. Consider the following class definition:
class Car {
// normal "instance" property
type: string;
// đ static PROPERTY
static numWheels: number = 4;
// đ static METHOD
static makeTesla(): Car {
return new Car(`Tesla`);
}
constructor(type: string) {
this.type = type;
}
// normal "instance" method
logType(): void {
console.log(this.type);
}
}
// đ static members are accessed from the CLASS name
Car.numWheels;
// > `4`
const myTesla = Car.makeTesla();
myTesla.type;
// > `"Tesla"`
- static properties canât use the
this
keyword, because they are not called in the context of an object instance:
class Car {
// [...]
static makeTesla(): Car {
this.logType(); // đ¨ ERROR: can't use `this` here
// [...]
}
}
- static methods are really just like normal functions except they are
attached to the class for readability, and organization, and to avoid
polluting the global namespace. Youâve already seen a lot of static methods,
for instance:
Math.random()
Object.keys()
Array.isArray()
- static properties are really kind of like global-ish constants or
variables, but again, they are attached to classes for readability,
organization, and to avoid polluting the global namespace. For instance
javascript defines a few useful static constants on the
Math
class, like:Math.PI
Math.E
Javascript Class/Object Misc Tidbits:
- the
instanceof
operator in javascript can be used to test whether some variable is an instance of a given class:
const now = new Date();
const truck = new Car();
car instanceof Date;
// > false
now instanceof Date;
// > true
- the
instanceof
operator is most often used in logicalif
statements:
if (someVar instanceof Date) {
// do stuff now that you know what it is an instance of
console.log(someVar.toISOString());
}
- in Typescript classes are both values AND types, so the class name can be used anywhere a type can be used:
class Car {
// [...]
}
// â
works: class is used in Type position
const myCar: Car = new Car();
// â
works: class used as type for argument
function takesCar(car: Car): string {
return car.type;
}
- by default, if you convert any object (including an instance of a class) to
a string, you get an unsatisfactory result of
[object Object]
:
const me = {
name: "Jared",
age: 41,
};
String(me);
// > "[object Object]"
// console.log() automatically converts objects to strings
console.log(me);
// > "[object Object]"
- but, javascript lets us define a
toString()
method to override the default way an object is converted to a string:
const me = {
name: "Jared",
age: 41,
// đ custom string conversion
toString() {
return `Name: ${this.name}, age: ${this.age}`;
},
};
// much nicer đ
console.log(me);
// > "Name: Jared, age: 41"
Typescript: Access Modifiers
- sometimes, when youâre creating a class, you need to make some helper method, but you donât want that helper method exposed as part of the public API of the class, meaning, youâd like to HIDE it from the code that uses the class:
class Product {
isAvailable(): boolean {
return this.numInWarehouse() > 0;
}
// hmmm... we need this method, but we really don't want
// to expose it to the outside world
numInWarehouse(): number {
const records = this.database.read();
return records.length;
}
}
- with the above code snippet, weâd really like to only have consumers of our
class call
isAvailable()
, and not to be able to call the methodnumInWarehouse()
â thatâs our business, not theirs. In the past there werenât great solutions for this. One common convention was to prefix the method or property with an underscore, which is sort of like a no trespassing sign. But itâs just a suggestion, you canât stop someone from accessing it:
// attempt 1
class Product {
isAvailable(): boolean {
return this._numInWarehouse() > 0;
}
// here we're using the `_` to signal that this is
// meant to be private
_numInWarehouse(): number {
const records = this.database.read();
return records.length;
}
}
// but it doesn't stop people from actually doing this:
const hats = new Product();
const hahaSecret = hats._numInWarehouse(); // đ˘
- to help this problem, Typescript came along and introduced access
modifiers:
public
,protected
, andprivate
:
// attempt 2
class Product {
// đ we declare that `.isAvailable()` is PUBLIC
public isAvailable(): boolean {
return this.numInWarehouse() > 0;
}
// đ we declare that `.numInWarehouse()` is PRIVATE
private numInWarehouse(): number {
const records = this.database.read();
return records.length;
}
}
// now, users get a Typescript error
// if they try to use `.numInWarehouse()`
const hats = new Product();
const ackTsError = hats.numInWarehouse(); // đ¨ TS Error
- typescript access modifiers are pretty great, and are usually good enough to hide implementation. However, when the typescript is converted to javascript, the modifiers are removed, so it still doesnât technically STOP someone from using your protected method or property:
- the
protected
modifier works just likeprivate
except that a child class can access those members. You can think ofprotected
as âprivate for non-childrenâ. - in the near future fully private fields will be supported in the javascript language, allowing total privacy:
// attempt 3 (in the future)
class Product {
// all properties and methods are public by default
isAvailable(): boolean {
return this.numInWarehouse() > 0;
}
// we use a hash `#` for TRUE privacy
#numInWarehouse(): number {
const records = this.database.read();
return records.length;
}
}
const hats = new Product();
// now this is literally IMPOSSIBLE in javascript
// this would produce a runtime error. đ
const nope = hats.numInWarehouse(); // đ¨ runtime error
Javascript: Getters and Setters
- in a normal javascript object, you can read the value of a property by just
calling
.<prop>
where<prop>
is the property name, and you can set a value using the same dot-notation:
const me = {
name: `Jared`,
age: 41,
};
// READ or "GET" a property:
const myName = me.name;
// WRITE or "SET" a property:
me.age = 42;
- sometimes, though, itâs handy to be able to run a function to get a value, sort of to compute the value of something just-in-time, when it is read. Consider this code, it would be a bummer if we had to do this:
const myRectangle = {
width: 5,
height: 10,
area: 50, // đ eeewwww, this is smelly
};
- in the above code snippet, having the
area
property defined as a constant is sort of stinky, because, if we change the width, we have to remember to update the area too. Really, we shouldnât keep track of the area, we should DERIVE or compute that value. One way to do this is with a regular old METHOD:
const myRectangle = {
width: 5,
height: 10,
area(): number {
// better :)
return this.width * this.height;
},
};
- the above code is perfectly good, except it sort of breaks the symmetry of the
API of our rectangle object, the
width
andheight
members are just plain old properties, but the area is a method. So our users have to remember that distinction, which isnât great. Our dream would be that we could hide the computation of of the area somehow, so that we could still derive it lazily, but to the user of the object it would appear like a normal property. This is possible with agetter
, which looks like this:
const myRectangle = {
width: 5,
height: 10,
// đ new syntax!
get area(): number {
return this.width * this.height;
},
};
// now we can do this:
myRectangle.area;
// > 50 â
- the compliment to a getter is a SETTER â which works just like a getter, except is a hidden function that runs when a value is set. It can be useful for a wide variety of purposes, one of which is doing some sort of runtime validation of a set value. Take for instance the idea of a class where you can set an age property, but you donât want to allow a negative age. You could enforce that constraint with a setter, like so:
class Person {
public name: string;
// đ§ what's this all about...
private _age: number;
constructor(name: string) {
this.name = name;
}
get age(): number {
return this._age;
}
set age(newAge: number) {
if (newAge < 0) {
throw new Error(`Negative age!!`);
}
this._age = newAge;
}
}
const me = new Person();
me.age = 41; // â
OK
me.age = -3; // đ¨ throws Error
- notice in lines 16-18 above, how we guard against setting a negative number as an age.
- also notice, how, since weâre defining
age
with a getter and setter, I was forced to create a private hidden property to track the stored age (see line 5). Thatâs because I canât usethis.age
, since the getter/setter defines those.
Homework Plan
- 1 days review all flashcards (in your app)
- 1 day Flashcard App assignment
- 1 day Akron Snowmen assignment
- 1 day HTTP Response Class assignment
- 1 day Future Project Planning assignment
- 1 days touch typing practice
- 4 days Execute Program homework
HTTP Response Class Assignment
- Carefully and slowly read and review the following sections of âNew Stuffâ
above ^^^:
- Static properties and methods
- getters and setters (computed properties)
- Typescript Access Modifiers
- Object Misc. (
toString()
method andinstanceof
operator)
- clone this repo, connect with vscode, install dependencies
- create a new branch
- make sure you did the last step
- open up the
src/Response.spec.ts
file, start up your tests withnpm test
ornpm run test:watch
and start working through each test, one by one, like usual. - when youâve got them all passing with no typescript errors, commit your work, submit a MR, and slack your MR url.
Flashcard App Assignment
- make sure youâve addressed all the changes I requested on last weekâs API/server work, then merge your MR.
- switch to master, pull from origin, and delete the branch from last week.
- make a new branch
- in Storybook design a new component which is a form for adding a new
card to your app. Youâll need to think through some things, like:
- what input do you need to collect to make a new card?
- what form elements will you use to collect the info?
- what do you want the form to look like?
- start by building this components with no props, and no ability to submit or actually do anything, just design what it will need to have, and make it look the way you want.
- commit your work.
- next, youâre going to need to figure out a way for your flashcard app to
have two modes. What I mean by that is, it will need to support EITHER
a) showing the user the flascards for them to practice, or b) letting the user
ADD a card. Think through how you want this to work. Maybe draw a sketch or
two on a piece of paper or a whiteboard. This, by the way, is called UI
Design (UI stands for âUser Interfaceâ). Here are some possibilities
(although you donât need to be limited to these):
- the app could load into a state where the user is presented with two buttons, one that says âReviewâ and another that says âAdd Cardâ. In this scenario, the user would always have to explicitly choose which âmodeâ they want before proceeding.
- alternatively, you could have the App start in âreviewâ mode (like it always has), and just have a button somewhere on the periphery that says âAdd Cardâ. Then, only when the user clicked that button, the screen would switch to the âAdd a Cardâ screen.
- or⌠something totally different that you come up with.
- once youâve decided on your approach, implement your design. Make it so the user can get into the âAdd Cardâ mode AND get out again. For now, the add card mode will be useless, it wonât work. Thatâs OK, weâll hook it up to our API in future weeks. This is just a baby step towards cool stuff in the future.
- hints/requirements:
- youâre probably going to have to rework your main, outer App component, or create a new wrapping component that can display EITHER the âAddCardâ component, or the normal âReview Cardâ. Before you start typing, stroke your beard for a few minutes and decide what would be the cleanest way to implement that.
- youâre going to need to introduce some new state to track what mode youâre in. Think carefully through what component should OWN that state, and try to give it the strictest typescript type you can come up with.
- not required, but this feature might be a great place to use another icon or two for the buttons within the âadd cardâ mode, and the button to get into that mode.
- while youâre working, make lots of WIP commits, so you can experiment and get back to a good state if you mess something up.
- remember, now your app has two parts, a web-app and a JSON API server, so while youâre working on the app itself (not storybook), youâll need to fire up the parcel dev server, and the api server. Review last weekâs homework if necessary.
- when youâve got everything working and looking the way you want (by working I mean switching between modes, NOT actually adding cards) rebase to squash your WIP commits, build, and submit a MR. Slack all the URLs, as usual.
Future Project Planning Assignment
- For this assignment you will be brainstorming and then deciding on TWO different long-ish-term projects youâll be working on on your own: a brochure website and a web app.
- For the brochure website, think of someone you know who could legitimately
use a simple website. Enough that they (or someone close to them) would be
willing to pay
$15
per year for a domain. The website should not be complicated, with no major interactivity, with the exception of maybe a simple contact form that generates an email. Talk to the person who would want the site, make sure theyâre up for it, and are willing to spend some time with you to help you understand what the content would be, providing input and guidance. Write down you top choice, or if you have several good ideas, write them all down. Here are some types of ideas to get your brain moving:- a website for Addrienne Pearlâs massage business
- a website for Edenâs Rabbit-selling business
- a website for the Wilhite Times
- For the web app â this could be anything with a bit of interactivity,
more likely to be a SPA using react. Something like the Tic-Tac-Toe project,
or your Flashcards app. This doesnât have to be actually useful, although it
could be. It can be primarily for you to use, or just because building it
would be an interesting challenge. It should be hard enough to stretch you,
but not impossible to build â or at least there should be a reasonably
possible first version with options for future enhancements. Some random
ideas:
- MSF Soccer Scheduler
- interactive 2-person checkers or chess game
- game to teach vim
- personal todo list app
- When youâve got your ideas selected, Slack us your choices, PLUS any ideas you liked but decided not to do. Other students can be inspired by your choices, and can take for themselves any ideas you mention that you indicate you will NOT be doing.
Akron Snowmen Assignment
- NOTE: this homework should be done alone, not with any other student/s.
- spend a few minutes looking over the current Akron Snowment site â not because everything there is important and should be re-created on the new site, but simply so you have a feel for whatâs currently there, and to jog your mind a bit for the next step.
- open a new file somewhere on your computer, and save it somewhere safe. Use whatever program you want.
- Think hard for a few minutes about the following questions, and write fairly
detailed answers to each:
- What should the nav items on the homepage actually say for text?
- Do we need any more main sections of the homepage (with nav items)? If so, which ones?
- What should each of the Image/Text blocks be about? (Donât write the text, just decide the SUBJECT of each block.)
- Do we need any more Image/Text blocks? If so, what subjects?
- What should the main SUBJECT of the Pink block be?
- What is your best attempt to pick the 6 âtopicsâ covered by the squares in the pink block? What makes the most sense to call-out and provide a scannable list of? What would grab the attention of someone shopping for a snow removal company?
- Soon weâll add some more interior pages to this site, so itâs not just a single homepage. What pages do you think it needs?
- Make a detailed list of photographs we wish we had for the homepage, and for any interior pages you documented above. If you had a professional photographer working for you for free, which images would you send them to photograph so you could finish the site?
- When you finish, send me a DIRECT MESSAGE with your answers. Do not post them publicly. I want each of you to submit your answers before you see any of the other studentâs answers.