Skip to content

Instantly share code, notes, and snippets.

@Kotauror
Last active May 20, 2019 15:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kotauror/424c68b1d82fdf66f862f1e274696877 to your computer and use it in GitHub Desktop.
Save Kotauror/424c68b1d82fdf66f862f1e274696877 to your computer and use it in GitHub Desktop.
Typescript interfaces

When and how to use interfaces in typescript. TL;DR - to prepare tymplates for objects.

Simple function, not many parameters - interface not needed:

let drawPoint = (x, y) => {
  console.log("kotek")
}

When many parameters would be needed, you shouldn't pass all of them (doesn't read well)

let drawPointTwo = (x, y, z, w, e, d, a) => {
  console.log("kotek")
}

Instead of passing multiple parameters, pass an object

let drawPointThree = (properties) => {
  console.log("kotek")
}

drawPointThree({
  direction: "north", 
  name: "jusia",
  school: "VLO",
  cats: ["kotek", "psotek"]
})

The problem with this solution is that we don't verify what's inside fo the object, we can pass numbers instead of string only and it's still going to be ok

let drawPointFour = (properties) => {
  console.log("kotek")
}

drawPointFour({
  direction: 1, 
  name: 2,
  school: 3,
  cats: 4
})

In order to tell what types of parameters we expect we could use inline annotation. However, it's a bit verbose, need to repeat the notation each time a function is called.

let drawPointFive = (properties: {direction: number, name: number, school: number, cats: number}) => {
  console.log("kotek")
}

drawPointFive({
  direction: 1, 
  name: 2,
  school: 3,
  cats: 4
})

drawPointFive({
  direction: "south",   // [ts] Property 'foo' does not exist on type 'Properties'. [2339]
  name: "kociasia",
  school: 3,
  cats: 4
})

In order to keep the annotation but without the need of rewriting it every time as above, we can use iterfaces!

interface Properties {
  direction: string,
  name: string, 
  age: number,
  cats: string[],
  doSomething(): string;
}

doSomething method - you can't create method implementation in interface, only method signature, later class will implement it. doSomething is a method that takes no input arguments and returns a string.

let drawPointSix = (properties: Properties) => {
  console.log("kotek")
}

Above we define a method with Properties as a type of argument. Below we call the method by passing an object whose content matches the requirements of the interface (it doesn't explicitly implement the interfact, but typescript is ok with duck typing - see below)

drawPointSix({
  direction: "north", 
  name: "kot", 
  age: 28,
  cats:["kot", "psot"],
  doSomething: () => {
    return "kot"
  }
})

Now let's take a look at a class implementing interface and duck typing.

class Kotek implements Properties {
  direction: string;
  name: string;
  age: number;
  cats: string[];
  doSomething(): string {
    throw new Error("Method not implemented.");
  }
}

let aKotek: Properties = new Kotek();

Kotek implements Properties interface this is why this works. In typescript you can create object that implements interface even (all properties) even though it's not an instance of a class that implements an interface

let someObj = {
  direction: "south", 
  name: "jusia", 
  age: 30,
  cats: ["a", "b"],
  doSomething: () => "Test"
}

The object above is not an instance of class Kotek and doesn't implement the interface. Even though Typescript allows to treat is as instance of Kotek! As long as it matched the structure :D :D :D - DUCK TYPING

aKotek = someObj

So we can assing someObj to aKotek as someObj satisfies the contract of Properties interface that Kotek class implements.

However, as we assigned, be can't access the additional field of someObj as it's not existing on interface Properties.

aKotek.foo    // [ts] Property 'foo' does not exist on type 'Properties'. [2339]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment