// Differences Between Type Aliases and Interfaces

// Type aliases and interfaces are very similar, and in many cases you can choose between them freely.
// Almost all features of an interface are available in type, the key distinction is that a type
// cannot be re-opened to add new properties vs an interface which is always extendable.

//Extending an interface
interface Animal {
  name: string;
}

interface Bear extends Animal {
  honey: boolean;
}

const bear = getBear();
bear.name;
bear.honey;
interface Window {
  title: string;
}

// Adding new fields to an existing interface
interface Window {
  ts: TypeScriptAPI;
}

const src = 'const a = "Hello World"';
window.ts.transpileModule(src, {});

//Extending a type via intersections
type Animal = {
  name: string;
}

type Bear = Animal & { 
  honey: boolean;
}

const bear = getBear();
bear.name;
bear.honey;

//A type cannot be changed after being created
type Window = {
  title: string;
}

type Window = {
  ts: TypeScriptAPI;
}

 // Error: Duplicate identifier 'Window'.


declare global {
  type Maybe<T> = T | null | undefined;
}


function printName(obj: { first: string; last?: string }) {
  // ...
}
function printId(id: number | string) {
  console.log("Your ID is: " + id);
}

function printId(id: number | string) {
  if (typeof id === "string") {
    // In this branch, id is of type 'string'
    console.log(id.toUpperCase());
  } else {
    // Here, id is of type 'number'
    console.log(id);
  }
}

function welcomePeople(x: string[] | string) {
  if (Array.isArray(x)) {
    // Here: 'x' is 'string[]'
    console.log("Hello, " + x.join(" and "));
  } else {
    // Here: 'x' is 'string'
    console.log("Welcome lone traveler " + x);
  }
}

type Point = {
  x: number;
  y: number;
};
 
// Exactly the same as the earlier example
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}

// Non-null Assertion Operator (Postfix   !  )
  
  // TypeScript also has a special syntax for removing null and undefined from a
  // type without doing any explicit checking. Writing ! after any expression is
  // effectively a type assertion that the value isn’t null or undefined:
  function liveDangerously(x?: number | null) {
    // No error
    console.log(x!.toFixed());
  }


  // Type Assertions
  // const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
  // const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");