Skip to content

Instantly share code, notes, and snippets.

@sophialittlejohn
Last active April 11, 2020 15:51
Show Gist options
  • Save sophialittlejohn/54023304865e2c327fcf6e96699e4931 to your computer and use it in GitHub Desktop.
Save sophialittlejohn/54023304865e2c327fcf6e96699e4931 to your computer and use it in GitHub Desktop.
Learning Frontend Web Development

11.04.20 ::before and ::after pseudo elements

Use display: inline-block to make sure they're visible.

To place an icon in an input field, it can be set as the background-image.

.icon::after {
  background-image: url(../../assets/chevron-down.svg);
  content: "";
  display: inline-block;
  position: absolute;
  right: 16px;
  bottom: 16px;
}

14.02.20

To include node modules in VSCode search add this to settings.json:

  "search.exclude": {
    "**/node_modules": false
  },
  "search.useIgnoreFiles": false

12.11.19 Generics

function identity<T>(arg: T): T {
    return arg;
}

After the name of the function we have included a type variable, T, in angled brackets <>. T is now a placeholder for the type we wish to pass into identity, and is assigned to arg in place of its type: instead of number, T is now acting as the type.

We are not limited to only one type variable.

function identities<T, U>(arg1: T, arg2: U): T {
   return arg1;
}

Now we have an identities() function that supports two generic types, with the addition of the U type variable — but the return type remains T. Our function is now clever enough to adopt two types, and return the same type as our arg1 parameter.

Generic Interfaces

interface Identities<V, W> {
   id1: V,
   id2: W
}

We can now apply this interface as the return type of identities(), amending our return type to adhere to it.

function identities<T, U> (arg1: T, arg2: U): Identities<T, U> {
   let identities: Identities<T, U> = {
    id1: arg1,
    id2: arg2
  };
  return identities;
}

Generic Classes

class Programmer<T> {
   
   private languageName: string;
   private languageInfo: T;
constructor(lang: string) {
      this.languageName = lang;
   }
   ...
}
let programmer1 = 
   new Programmer<Language.Typescript>("Typescript");
let programmer2 = 
   new Programmer<Language.Rust>("Rust");

For our Programmer class, T is a type variable for programming language meta data, allowing us to assign various language types to the languageInfo property. Every language will inevitably have different metadata, and therefore need a different type.

For instantiating classes, there is not much the compiler can do to guess which language type we want assigned to our programmer; it is compulsory to pass the type here. However, with functions, the compiler can guess which type we want our generics to be — and this is the most common way developers opt to use generics.

Using constraints to ensure type properties exist

// this will cause an error
function identity<T>(arg: T): T {
   console.log(arg.length);
   return arg;
}

What we need to do is extend our type variable to an interface that houses our required properties.

interface Length {
    length: number;
}

function identity<T extends Length>(arg: T): T {
   // length property can now be called
   console.log(arg.length);
   return arg;
}

This is how we say: "Whatever type T is, it must contain the properties in Length otherwise the compiler will warn us when calling the function that the argument passed is either not of shape object or the object does not contain the property length".

Source

11.11.19 Why to avoid as keyword

interface Foo {
    bar: number;
    bas: string;
}
var foo = {} as Foo; // here the compiler won't tell you anything is wrong even though bar and bas are missing!!

11.11.19 Typescript Managing non existing values

Unfortunately you can not use typescript optional “?” to define a variable as potentially undefined or a function return type as undefined and you might want an abstraction to cover this.

type Optional<T> = T | undefined

This way if your user might not be here because it is loading for example while you first render your components, you could have a user with the following type:

let user: Optional<User>;

Which is going to be the same as defining the following type:

let user: User | undefined;

08.11.19 useEffect notes

useEffect watches for changes in the elements passed in the optional array as the second arguments. If the array is empty it won't watch for any changes.

  useEffect(() => {
    console.log("componentDidMount");
    };
  }, []); // empty-array means don't watch for any updates

05.11.19 Differnce in Union type declaration

data: Array<Car | Plane> // data can contain either Plane or Car
data: Plane[] | Car[] // data can be either of type Plane or type Car but not both --> more strict

05.11.19 Typescript Type Guard in keyword

type Car = {
  brand: string;
}

type Plane = {
  year: number;
}

function add(arg: Plane | Car) {
  if ('brand' in arg) {
    arg // car
  } else {
    arg // plane
  }
} 

Example can be used to test which type we have.

27.10.19 Typescript Intersection Type

function extend<First, Second>(first: First, second: Second): First & Second {
    const result: Partial<First & Second> = {};
    for (const prop in first) {
        if (first.hasOwnProperty(prop)) {
            (result as First)[prop] = first[prop];
        }
    }
    for (const prop in second) {
        if (second.hasOwnProperty(prop)) {
            (result as Second)[prop] = second[prop];
        }
    }
    return result as First & Second;
}

Function extend takes arguments of type First and Second and returns either of types First or Second. result initially is an empty object that can contain properties from First or Seconds but can also have nothing (neither a prop from First or Second).

The hasOwnProperty() method returns a boolean indicating whether the object has the specified property as its own property (as opposed to inheriting it).

Upon looping over the objects, if the key prop exists in the type and is not inherited, add the key value pair to the results object as that type.

Finally return an object containing properties from both type First and Second.

Sources: TS Advanced Types & mdn hasOwnProperty

24.10.19 Typescript Record

interface FileReformatted {
  extension: string;
  name: string;
}

class FileModel {
  fileFormatted: Record<string, FileReformatted> = {}
}

const file = new FileModel
file.fileFormatted

One of the popular cases when Record works in well is an interface for a business entity that you keep in a dictionary as key-value pairs.

Partial type makes all properties in the object optional.

https://levelup.gitconnected.com/advanced-typescript-types-with-examples-1d144e4eda9e

29.09.19 Creating unique array with Set

const cities = ['Basel', 'Zurich', 'Zurich', 'Bern']

let uniqueCities = [...new Set(cities)] // ['Basel', 'Zurich', 'Bern']

15.09.19 Compound Components

Why compound commponents are useful:

  • Internally they are built to operate on a set of data that is passed in through children instead of props
  • They provide a way to shield feature specific logic from the rest of the app providing a clean and expressive API for consuming the component

From acticle: React.js — Compound Components

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment