Typescript Properties(Notice)

Optional properties

add a ? after the property name

function printName(obj: { first: string; last?: string }) {
  // ...
}
// Both OK
printName({ first: "Bob" });
printName({ first: "Alice", last: "Alisson" });

Union Types

Defining a Union Type

function printId(id: number | string) {  //use | to separate
  console.log("Your ID is: " + id);
}
// OK
printId(101);
// OK
printId("202");

if you have the union string | number, you can’t use methods that are only available on string

function printId(id: number | string) {
  console.log(id.toUpperCase());
Property 'toUpperCase' does not exist on type 'string | number'.
  Property 'toUpperCase' does not exist on type 'number'.
}
// solution of upstairs
function printId(id: number | string) {
  if (typeof id === "string") { // use typeof that Typescript knows that only a string value
    // In this branch, id is of type 'string'
    console.log(id.toUpperCase());
  } else {
    // Here, id is of type 'number'
    console.log(id);
  }
}

Type Aliases

use a type to give a name to any type at all

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);
}
 
printCoord({ x: 100, y: 100 });

Interfaces

An interface declaration is another way to name an object type:

interface Point {
  x: number;
  y: number;
}
 
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
 
printCoord({ x: 100, y: 100 });

Differences Between Interfaces and Type Alias

Differences of Extending

interface Animal { // interfaces
  name: string;
}

interface Bear extends Animal {
  honey: boolean;
}

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

type Animal = { // type
  name: string;
}

type Bear = Animal & { 
  honey: boolean;
}

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

Difference of Adding new fields

interface Window { //interfaces
  title: string;
}

interface Window {
  ts: TypeScriptAPI;
}

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


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

type Window = {
  ts: TypeScriptAPI;
}

 // Error: Duplicate identifier 'Window'.

null and undefined

strictNullChecks on

// handle method
function doSomething(x: string | null) {
  if (x === null) {
    // do nothing
  } else {
    console.log("Hello, " + x.toUpperCase());
  }
}

// use ! after any expression
function liveDangerously(x?: number | null) {
  // No error
  console.log(x!.toFixed());
}

More on Function

Function Type Expressions

Typeof Function is fn

type GreetFunction = (a: string) => void;
function greeter(fn: GreetFunction) {
  // ...
}

Generic Functions

function firstElement<Type>(arr: Type[]): Type | undefined {
  return arr[0];   // the Type can be meant every type return
}

// s is of type 'string'
const s = firstElement(["a", "b", "c"]);
// n is of type 'number'
const n = firstElement([1, 2, 3]);
// u is of type undefined
const u = firstElement([]);

Inference Function - The type were inferred - chosen automatically by Typescript

function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
  return arr.map(func);
}
 
// Parameter 'n' is of type 'string'
// 'parsed' is of type 'number[]'
const parsed = map(["1", "2", "3"], (n) => parseInt(n));

Specifying Type Arguments

function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {
  return arr1.concat(arr2);
}

const arr = combine([1, 2, 3], ["hello"]); // mismatched arrays
Type 'string' is not assignable to type 'number'.

const arr = combine<string | number>([1, 2, 3], ["hello"]); // use specify Type

Optional Parameters

// method one
function f(x?: number) { //marking the parameters as optional with ?
  // ...
}
f(); // OK
f(10); // OK

function f(x = 10) { // param is specified as type <number | undefined>,provide a default value
  // ...
}

// method two
Partial<ListApiOption<unknown, unknown>> // use Partial before type call

OtherTypes to Know About

// 1. void
// The inferred return type is void
function noop() {
  return;
}

// 2. unknown
function f1(a: any) {
  a.b(); // OK
}
function f2(a: unknown) { // similar to the any type,but not legal to do anything
  a.b();
'a' is of type 'unknown'.
}

// 3. never
function fail(msg: string): never { // some functions never return a value
  throw new Error(msg);
}

Parameter Destructuring

type ABC = { a: number; b: number; c: number };
function sum({ a, b, c }: ABC) { // unpack objects provided as an argument
  console.log(a + b + c);
}

Object Types

readonly Properties

interface SomeType {
  readonly prop: string; //readonly can't be written to during type-checking
}
 
function doSomething(obj: SomeType) {
  // We can read from 'obj.prop'.
  console.log(`prop has the value '${obj.prop}'.`);
 
  // But we can't re-assign it.
  obj.prop = "hello";
Cannot assign to 'prop' because it is a read-only property.
}

interface ReadonlyPerson {
  readonly name: string;
  readonly age: number;
}
 
let writablePerson: Person = {
  name: "Person McPersonface",
  age: 42,
};
 
// works
let readonlyPerson: ReadonlyPerson = writablePerson;
 
console.log(readonlyPerson.age); // prints '42'
writablePerson.age++;
console.log(readonlyPerson.age); // prints '43'

Extending Types

interface BasicAddress {
  name?: string;
  street: string;
  city: string;
  country: string;
  postalCode: string;
}
 
interface AddressWithUnit extends BasicAddress {
  unit: string;
}

Generic Object Types

use <> declares a type parameter

interface Array<Type> {   // Array is a generic type
  /**
   * Gets or sets the length of the array.
   */
  length: number;
 
  /**
   * Removes the last element from an array and returns it.
   */
  pop(): Type | undefined;
 
  /**
   * Appends new elements to an array, and returns the new length of the array.
   */
  push(...items: Type[]): number;
 
  // ...
}

Tuple Types

function doSomething(pair: [string, number]) {
  const a = pair[0];
       
const a: string
  const b = pair[1];
       
const b: number
  // ...
}
 
doSomething(["hello", 42]);

// index shouldn't past the number of elements
function doSomething(pair: [string, number]) {
  // ...
 
  const c = pair[2];
Tuple type '[string, number]' of length '2' has no element at index '2'.
}

// we can destructure tuples 
function doSomething(stringHash: [string, number]) {
  const [inputString, hash] = stringHash;
 
  console.log(inputString);
                  
const inputString: string
 
  console.log(hash);
               
const hash: number
}

Utility Types

Partial

interface Todo {
  title: string;
  description: string;
}
 
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) { // use Partial and bracket <> inside Type
  return { ...todo, ...fieldsToUpdate };
}
 
const todo1 = {
  title: "organize desk",
  description: "clear clutter",
};
 
const todo2 = updateTodo(todo1, {
  description: "throw out trash",
});

Required

opposite of Partial

interface Props {
  a?: number;
  b?: string;
}
 
const obj: Props = { a: 5 };
 
const obj2: Required<Props> = { a: 5 };
Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'.

Record<Keys, Type>

interface CatInfo {
  age: number;
  breed: string;
}
 
type CatName = "miffy" | "boris" | "mordred";
 
const cats: Record<CatName, CatInfo> = { // can be used to map the properties
  miffy: { age: 10, breed: "Persian" },
  boris: { age: 5, breed: "Maine Coon" },
  mordred: { age: 16, breed: "British Shorthair" },
};
 
cats.boris;

Pick<Type, Keys>

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}
 
type TodoPreview = Pick<Todo, "title" | "completed">;
 
const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};
 
todo;  //const todo:TodoPreview

Omit<Type, Keys>

remove keys,The opposite of Pick

interface Todo {
  title: string;
  description: string;
  completed: boolean;
  createdAt: number;
}
 
type TodoPreview = Omit<Todo, "description">;
 
const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
  createdAt: 1615544252770,
};
 
todo;
 
const todo: TodoPreview
 
type TodoInfo = Omit<Todo, "completed" | "createdAt">;
 
const todoInfo: TodoInfo = {
  title: "Pick up kids",
  description: "Kindergarten closes at 5pm",
};
 
todoInfo;