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 {}