# Functions

TIP

TypeScript has many ways to describe how functions can be called. Let’s learn about how to write types that describe functions

# Basic

  • TypeScript allows you to specify the types of both the input and output values of function
// with `string` parameter and return `number`
function greet(name: string): number {
  console.log("Hello, " + name.toUpperCase() + "!!");
  return 26;
}
  • fn: (a: string) => void means with one string parameter, and doesn’t have a return value
function greeter(fn: (a: string) => void) {
  fn("Hello, World");
}
function p(s: string) {
  console.log(s);
}
greeter(p);
//------------
// type alias to name a function type
type GreetFunction = (a: string) => void;
function greeter(fn: GreetFunction) {
  // ...
}
  • NOTE: In JavaScript, functions can have properties in addition to being callable and invoked with the new operator. However, the function type expression syntax doesn’t allow for declaring properties.

# Signatures

  • If we want to describe something callable with properties, write a call signature in an object type
type d = {
  description: string;
  (someArg: number): boolean; // here is a call signature
};
function doSomething(fn: d) {
  console.log(fn.description + " returned " + fn(6)); //see fu (...)
}
  • You can write a construct signature by adding the new keyword in front of a call signature
type s = {
  new (s: string): SomeObject;
};
function fn(ctor: s) {
  return new ctor("hello"); // see new 
}

# Generic Functions

  • generics are used when we want to describe a correspondence between two values.
  • keyword : constrained
function firstElement<Type>(arr: Type[]): Type | undefined {
  return arr[0];
}
// 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([]);

# Optional Parameters

  • callers can always pass undefined, as this simply simulates a “missing” argument
function f(x?: number) {
  // ...
}
f(); // OK
f(10); // OK
f(undefined); // ok

// set default
function f(x = 10) {
  // ...
}
  • When writing afunction type for a callback, never write an optional parameter unless you intend to call the function without passing that argument
function myForEach(arr: any[], callback: (arg: any, index?: number) => void) {
  for (let i = 0; i < arr.length; i++) {
    callback(arr[i], i);
  }
}

myForEach([1, 2, 3], (a, i) => {
  console.log(i.toFixed());
// i Object is possibly 'undefined'.
});

# Function Overloads

  • In TypeScript, called in a variety of argument counts and types we can specify a function that can be called in different ways by writing overload signatures
function fn(x: boolean): void; //signature1
function fn(x: string): void;//signature2

function fn(x: boolean) {}// error

function fn(x: boolean | string) {} //right, u must contain all param types

# 'this' in a Function

  • TypeScript specification states (like js) that you cannot have a parameter called this , so just let you declare the type for this in the function body
  • Note that you need to use function and not arrow functions to get this behavior
interface DB {
  filterUsers(filter:
  (this: User) => boolean // params : a function ;
  ): User[]; //  return : array[]
}
const db = getDB();
const handler = function (this: User) {
  return this.admin;
}
const admins = db.filterUsers(handler);
const admins = db.filterUsers(() => this.admin);// error

# Other Types

  • these are especially relevant in the context of functions
    void object unknown never Function

  • void represents the return value of functions which don’t return a value
    • void is not the same as undefined
    function noop() {
    return;
    }
    

  • object type refers to any value that isn’t a primitive (string, number, bigint, boolean, symbol, null, or undefined)
    • object is not Object. Always use object!
    • This is different from the empty object type { }, and also different from the global type Object

  • unknown type represents as a safer type of any value
    • it’s not legal to do anything with an unknown value
      function f1(a: any) {
      a.b(); // OK
    }
    function f2(a: unknown) {
      a.b();// error: Object is of type 'unknown'
    
    }
    
    • This is useful when describing function types
    function safeParse(s: string): unknown {
    return JSON.parse(s); //  we not really sure the return type
    }
    
    • we should avoid use any for many cases, and unknown only can assign to nuknown | any
    declare let T: unknown;
    
    declare let v1: string; 
    v1 = T; // error;
    
    declare let v2: number;
    v2 = T; // error;
    
    declare let v3: boolean;
    v3 = T; // error;
    
    declare let v4: number[];
    v4 = T; // error;
    
    declare let v5: any;
    v5 = T; // ok; // any = unknown
    
    • use typeof or instanceof to narrow the range of unknown makes your operations legally
     if (typeof x === 'string') {
      ...
    }
    if (x instanceof Bird) {
     ...
    }
    

  • Some functions never return a value
    • function throws an exception or terminates execution of the program
      function fail(msg: string): never {
      throw new Error(msg);
    }
    
    • when TypeScript determines there’s nothing left in a union
      function fn(x: string | number) {
      if (typeof x === "string") {
        ...
      } else if (typeof x === "number") {
        ...
      } else {
        x; // has type 'never'!
      }
    }
    

  • Function describes properties like bind, call, apply
function doSomething(f: Function) {
  f(1, 2, 3);
}

# Rest Parameters | Arguments

  • rest parameters define functions that take an unbounded number of arguments
function multiply(n: number, ...m: number[]) {// use the ... syntax
  return m.map((x) => n * x);
}
const a = multiply(10, 1, 2, 3, 4); // [10, 20, 30, 40]

  • rest Arguments
const args = [8, 5];
const angle = Math.atan2(...args); // error

const args = [8, 5] as const;
const angle = Math.atan2(...args);// ok
Last Updated: 2022/1/10 上午9:52:53