参数装饰器应用于方法参数,可以记录参数信息或修改参数行为。参数装饰器接收三个参数:目标对象、方法名和参数索引。
参数装饰器是一个函数,接收三个参数。
function log(target: any, propertyKey: string, parameterIndex: number) {
console.log(`装饰参数: ${propertyKey} 的第 ${parameterIndex} 个参数`)
}
class User {
greet(@log name: string): string {
return `你好,${name}`
}
}
参数装饰器的三个参数:
function inspect(target: any, propertyKey: string, parameterIndex: number) {
console.log("target:", target === User.prototype)
console.log("propertyKey:", propertyKey)
console.log("parameterIndex:", parameterIndex)
}
class User {
greet(@inspect name: string, @inspect age: number): string {
return `你好,${name},你 ${age} 岁了`
}
}
参数装饰器可以记录参数信息。
const requiredParams: Map<string, number[]> = new Map()
function required(target: any, propertyKey: string, parameterIndex: number) {
const key = `${target.constructor.name}.${propertyKey}`
if (!requiredParams.has(key)) {
requiredParams.set(key, [])
}
requiredParams.get(key)!.push(parameterIndex)
}
class UserService {
createUser(@required name: string, @required email: string, age?: number) {
console.log(`创建用户: ${name}, ${email}, ${age}`)
}
}
console.log(requiredParams)
参数装饰器可以验证参数。
const paramValidators: Map<string, Map<number, (value: any) => boolean>> = new Map()
function validate(validator: (value: any) => boolean) {
return function (target: any, propertyKey: string, parameterIndex: number) {
const key = `${target.constructor.name}.${propertyKey}`
if (!paramValidators.has(key)) {
paramValidators.set(key, new Map())
}
paramValidators.get(key)!.set(parameterIndex, validator)
}
}
function validateParams(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const original = descriptor.value
const key = `${target.constructor.name}.${propertyKey}`
descriptor.value = function (...args: any[]) {
const validators = paramValidators.get(key)
if (validators) {
for (const [index, validator] of validators) {
if (!validator(args[index])) {
throw new Error(`参数 ${index} 验证失败`)
}
}
}
return original.apply(this, args)
}
return descriptor
}
function isString(value: any): boolean {
return typeof value === "string"
}
function isNumber(value: any): boolean {
return typeof value === "number"
}
class Calculator {
@validateParams
add(@validate(isNumber) a: number, @validate(isNumber) b: number): number {
return a + b
}
}
const calc = new Calculator()
console.log(calc.add(1, 2))
console.log(calc.add("1" as any, 2))
参数装饰器可以用于依赖注入。
const injectMap: Map<string, Map<number, string>> = new Map()
function inject(token: string) {
return function (target: any, propertyKey: string, parameterIndex: number) {
const key = `${target.constructor.name}.${propertyKey}`
if (!injectMap.has(key)) {
injectMap.set(key, new Map())
}
injectMap.get(key)!.set(parameterIndex, token)
}
}
const container = new Map<string, any>()
container.set("logger", { log: (msg: string) => console.log(`[LOG] ${msg}`) })
container.set("db", { query: (sql: string) => console.log(`执行: ${sql}`) })
function resolve(target: any) {
const injections = injectMap.get(`${target.name}.constructor`)
if (!injections) {
return new target()
}
const args: any[] = []
for (const [index, token] of injections) {
args[index] = container.get(token)
}
return new target(...args)
}
class UserService {
constructor(@inject("logger") private logger: any, @inject("db") private db: any) {}
getUser(id: number) {
this.logger.log(`获取用户 ${id}`)
this.db.query(`SELECT * FROM users WHERE id = ${id}`)
return { id, name: "张三" }
}
}
const userService = resolve(UserService)
userService.getUser(1)
参数装饰器可以设置参数默认值。
const defaultValues: Map<string, Map<number, any>> = new Map()
function defaultValue(value: any) {
return function (target: any, propertyKey: string, parameterIndex: number) {
const key = `${target.constructor.name}.${propertyKey}`
if (!defaultValues.has(key)) {
defaultValues.set(key, new Map())
}
defaultValues.get(key)!.set(parameterIndex, value)
}
}
function applyDefaults(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const original = descriptor.value
const key = `${target.constructor.name}.${propertyKey}`
descriptor.value = function (...args: any[]) {
const defaults = defaultValues.get(key)
if (defaults) {
for (const [index, value] of defaults) {
if (args[index] === undefined) {
args[index] = value
}
}
}
return original.apply(this, args)
}
return descriptor
}
class Greeter {
@applyDefaults
greet(name: string, @defaultValue("你好") greeting: string): string {
return `${greeting},${name}`
}
}
const greeter = new Greeter()
console.log(greeter.greet("张三"))
console.log(greeter.greet("李四", "欢迎"))
参数装饰器应用于方法参数,接收目标对象、方法名和参数索引三个参数。参数装饰器可以记录参数信息、验证参数、实现依赖注入、设置默认值等。参数装饰器通常与方法装饰器配合使用,实现参数验证和依赖注入功能。参数装饰器不能直接修改参数值,需要配合方法装饰器来实现。