TypeScript 常见类型定义方法 
1. 函数类型 
1.1 函数类型表达式 
函数类型表达式(Function Type Expressions)是声明函数的简单有效的方法,例如 (s: string) => string。
ts
function greeter(fn: (s: string) => string) {
  fn("Hello, World")
}1.2 函数调用签名 
可以声明函数的调用签名(Call Signatures)来声明函数类型。
ts
type Func = {
  (s: string): boolean
  description: string
}
function greeter(fn: Func) {
  fn("Hello, World")
  console.log(fn.description)
}Func 也常常使用 interface 来声明。
ts
interface Func {
  (s: string): boolean
  description: string
}1.3 函数构造签名 
如果函数需要支持 new,则需要使用 new 签名。
ts
interface Func {
  (s: string): boolean
  new (s: string): Func
}
function greeter(fn: Func) {
  fn("Hello, World")
  return new fn("Hello, World")
}new 签名和调用签名可以同时存在。
1.4 函数重载 
函数重载声明也比较简单:
ts
function makeDate(timestamp: number): Date
function makeDate(m: number, d: number, y: number): Date
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d)
  } else {
    return new Date(mOrTimestamp)
  }
}1.5 泛型函数 
最简单的泛型函数:
ts
function firstElement<T>(arr: T[]): T | undefined {
  return arr[0]
}也可以有多个参数:
ts
function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
  return arr.map(func)
}泛型也可以像 Java 一样有约束类型:
ts
function longest<Type extends { length: number }>(a: Type, b: Type) {
  if (a.length >= b.length) {
    return a
  } else {
    return b
  }
}1.6 箭头函数 
箭头函数的类型声明:
ts
let greet: (name: string) => string
greet = (name: string) => `Hello, ${name}`
箭头函数也可以标记返回值和泛型参数:
ts
const greet = <T>(name: T): string => `Hello, ${name}`
2. 编写声明文件 
2.1 描述全局命名空间 
命名空间用于解决命名冲突问题,尽量在项目中避免使用命名空间,它很难去识别组件之间的依赖关系,但是在声明文件中,可以使用命名空间来描述一些全局变量。
ts
declare namespace myLib {
  function makeGreeting(s: string): string
  let numberOfGreetings: number
}命名空间类似于类中大量包裹无关静态函数的做法,但是后者应该禁止使用的,因为这会导致 JavaScript 打包器中的许多优化失效(例如摇树优化 Tree Shaking)。
ts
class myLib {
  static makeGreeting(s: string): string
  // 虽然项目中没有调用 hello() 方法,但是打包器无法知道这一点
  static hello(): string
  static numberOfGreetings: number
}建议:
ts
export function makeGreeting(s: string): string {
  // ...
}
// 此时打包器可以知道 hello() 方法没有被调用,可以进行优化
export function hello(): string {
  // ...
}2.2 声明全局变量 
使用 declare 关键字声明全局变量:
ts
declare let myGlobal: string
declare const myConstant: string
declare function myFunction(a: number): string如果要在项目中声明全局变量,可以使用 declare global 关键字:
ts
type Observable<T> = {
  subscribe(observer: (value: T) => void): void
}
declare global {
  interface Array<T> {
    toObservable(): Observable<T>
  }
}
export {}注意一定要在文件末尾加上 export {},否则不会生效。
例如,定义 process.env,创建 env.node.d.ts:
ts
declare global {
  namespace NodeJS {
    interface ProcessEnv {
      NODE_ENV: 'development' | 'production'
      PORT: string
    }
  }
}
export {}实例:同时定义前端和后端环境变量
在 Nuxt 3 项目中,前端可通过 import.meta.env 读取公开的环境变量,后端可通过 process.env 读取系统全部环境变量,可以同时定义两者:
ts
interface ImportMetaEnv {
  /**
   * 应用名称
   */
  readonly NUXT_APP_NAME?: string
  /**
   * 鉴权服务地址
   */
  readonly NUXT_AUTH_ORIGIN?: string
}
interface ImportMeta {
  readonly env: ImportMetaEnv
}
declare global {
  namespace NodeJS {
    interface ProcessEnv extends ImportMetaEnv {
      /**
       * MongoDB 连接地址
       */
      DATABASE_URL?: string
      /**
       * Redis 连接地址
       */
      REDIS_URL?: string
    }
  }
}
export {}