我想知道如何正确输入method decorators在 typescript 中。我有一个简单的装饰器,它将字符串参数作为第一个参数添加到装饰函数中。它工作得很好,问题是我不知道如何正确输入它以及它是否可能?
const task = (
target: unknown,
propertyKey: string,
descriptor: TypedPropertyDescriptor<(...args: unknown[]) => unknown>,
): TypedPropertyDescriptor<(name: string, ...args: unknown[]) => unknown> => {
const original = descriptor.value
descriptor.value = function (...args: unknown[]) {
return original?.call(this, 'Mark', ...args)
}
// what's wrong with this return?
return descriptor
}
class Test {
constructor(){
// should not report an error
this.printName()
}
@task
printName(name: string) {
console.log(name)
}
}
new Test()
Playground 可用 here
最佳答案
正如 @cdimitroulas 所说,这是不可能的,装饰器不会改变 Typescript 类型。
不过,我们可以解决您的一些问题:
// what's wrong with this return?
const task = (
target: unknown,
propertyKey: string,
// you said here that descriptor is this type
descriptor: TypedPropertyDescriptor<(...args: unknown[]) => unknown>,
// yet, you said that the type is different here, namely that the first argument is of type string (it was unknown)
): TypedPropertyDescriptor<(name: string, ...args: unknown[]) => unknown> => {
const original = descriptor.value
descriptor.value = function (...args: unknown[]) {
return original?.call(this, 'Mark', ...args)
}
// you're returning the same descriptor that was passed to the decorator
return descriptor
}
Typescript 期望找到相同的类型,但它是不同的,因此它尝试比较它们以查看一个类型是否可分配给另一个类型,但事实并非如此。 unknown
不可分配给string
。 unknown
只能分配给 unknown
或any
。
知道装饰器无论如何都不会更改类型,您可以完全省略返回类型并让 Typescript 为您推断
const task = (
target: unknown,
propertyKey: string,
descriptor: TypedPropertyDescriptor<(...args: unknown[]) => unknown>,
) => {
const original = descriptor.value
descriptor.value = function (...args: unknown[]) {
return original?.call(this, 'Mark', ...args)
}
return descriptor
}
接下来,Typescript 仍然对此不满意:
@task // --> Type '(name: string) => void' is not assignable to type '(...args: unknown[]) => unknown'
printName(name: string) {
console.log(name)
}
如前所述,unknown
无法分配给string
。所以要么我们改变unknown
至any
(不安全)或者更好的是,我们将签名更改为 TypedPropertyDescriptor<(name: string) => void>
const task = (
target: any,
propertyKey: string,
descriptor: TypedPropertyDescriptor<(name: string) => void>,
) => {
const original = descriptor.value
descriptor.value = function () {
return original?.call(this, 'Mark')
}
return descriptor
}
至于这一行
this.printName()
你能做的最好的事情就是让 name 属性成为可选的。装饰器基本上是为我们设置 Prop ,所以在这种情况下,我们可以完全删除 Prop ,尽管我知道这不是一个真实的案例,只是一个例子来说明你的观点。
关于typescript - 如何在 TS 中输入装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67055899/