如何在 TypeScript 中使装饰器类型安全?
How do I make a decorator typesafe in TypeScript?
示例:
class Parent {
parentMethod() {
// ...
}
}
@Hooks({
// Only methods from the `Child` class (including inherited methods) must be allowed here
childMethod: [/* ... */],
parentMethod: [/* ... */]
})
class Child extends Parent {
childMethod() {
// ...
}
}
@Hooks()
装饰器将对象作为参数。在此对象中,键是 Child
class 中的方法名称。如何使 @Hooks()
装饰器类型安全?
您能否提供 @Hooks()
?
类型的代码示例
检查它是否适合你
interface ClassType<T> extends Function {
new (...args: any[]): T;
}
type MethodKeys<T> = ({
[K in keyof T]: T[K] extends Function ? K : never
})[keyof T]
type HooksOptions<T> = {
[K in MethodKeys<T>]: []
}
function Hooks<T>(_options: HooksOptions<T>) {
return function (ctor: ClassType<T>): ClassType<T> {
return ctor
}
}
class Parent {
parentMethod() {
// ...
}
}
@Hooks<Child>({
childMethod: [/* ... */],
parentMethod: [/* ... */]
})
class Child extends Parent {
childMethod() {
// ...
}
}
@Hooks("invalid-value") // error
class Child2 extends Parent {
childMethod() {
// ...
}
}
@Hooks<Child3>({
c: [], // error
childMethod: [/* ... */],
childMethod2: [/* ... */], // error
parentMethod: [/* ... */]
})
class Child3 extends Parent {
public c: string = ''
childMethod() {
// ...
}
}
在 typescript 中没有某个 class 方法的类型(从未听说过其他语言中的此类类型,TBH),
您可以为函数签名指定类型。
编辑:
好吧,显然有一些我不知道的技巧
,正如其他答案中所见..
但是,如果您对快速简单但有限的解决方案感兴趣:
例如:
let myAdd: (baseValue: number, increment: number) => number = (baseValue, increment) => baseValue + increment
有关类型化函数的更多信息,请点击此处:
https://www.typescriptlang.org/docs/handbook/functions.html
如果这样就可以在装饰器的声明中使用类型化签名,如下所示:
Interface ObjectInterface {
ChildMethods: {(param) => void} [], //or whatever fuction signature meets your need, this is just an example.
ParentMethods: {(param) => void}[]
}
//this is the decorator declaration
function Hooks(obj: ObjectInterface) {
return function (
target,
propertyKey: string,
descriptor: PropertyDescriptor
) {
// what ever implementation you have in hooks...
};
}
这种方式将非(param) => void
类型的函数传递给装饰器时会导致编译错误。
更多信息在这里:
https://www.typescriptlang.org/docs/handbook/decorators.html
这里是类型化函数数组,就像我在 ObjectInterface
上所做的那样:
A Typed array of functions
我找到了解决方案
interface Type<T> extends Function {
new (...args: any[]): T;
}
type HookMap<T> = {
[func in keyof T]?: any[];
};
function Hooks<T>(hookMap: HookMap<T>) {
return (clazz: Type<T>): void => {
// ...
};
}
class Parent {
parentMethod() {
// ...
}
}
@Hooks({
childMethod: [/* ... */],
parentMethod: [/* ... */]
})
class Child extends Parent {
childMethod() {
// ...
}
}
示例:
class Parent {
parentMethod() {
// ...
}
}
@Hooks({
// Only methods from the `Child` class (including inherited methods) must be allowed here
childMethod: [/* ... */],
parentMethod: [/* ... */]
})
class Child extends Parent {
childMethod() {
// ...
}
}
@Hooks()
装饰器将对象作为参数。在此对象中,键是 Child
class 中的方法名称。如何使 @Hooks()
装饰器类型安全?
您能否提供 @Hooks()
?
检查它是否适合你
interface ClassType<T> extends Function {
new (...args: any[]): T;
}
type MethodKeys<T> = ({
[K in keyof T]: T[K] extends Function ? K : never
})[keyof T]
type HooksOptions<T> = {
[K in MethodKeys<T>]: []
}
function Hooks<T>(_options: HooksOptions<T>) {
return function (ctor: ClassType<T>): ClassType<T> {
return ctor
}
}
class Parent {
parentMethod() {
// ...
}
}
@Hooks<Child>({
childMethod: [/* ... */],
parentMethod: [/* ... */]
})
class Child extends Parent {
childMethod() {
// ...
}
}
@Hooks("invalid-value") // error
class Child2 extends Parent {
childMethod() {
// ...
}
}
@Hooks<Child3>({
c: [], // error
childMethod: [/* ... */],
childMethod2: [/* ... */], // error
parentMethod: [/* ... */]
})
class Child3 extends Parent {
public c: string = ''
childMethod() {
// ...
}
}
在 typescript 中没有某个 class 方法的类型(从未听说过其他语言中的此类类型,TBH), 您可以为函数签名指定类型。
编辑: 好吧,显然有一些我不知道的技巧 ,正如其他答案中所见.. 但是,如果您对快速简单但有限的解决方案感兴趣:
例如:
let myAdd: (baseValue: number, increment: number) => number = (baseValue, increment) => baseValue + increment
有关类型化函数的更多信息,请点击此处: https://www.typescriptlang.org/docs/handbook/functions.html
如果这样就可以在装饰器的声明中使用类型化签名,如下所示:
Interface ObjectInterface {
ChildMethods: {(param) => void} [], //or whatever fuction signature meets your need, this is just an example.
ParentMethods: {(param) => void}[]
}
//this is the decorator declaration
function Hooks(obj: ObjectInterface) {
return function (
target,
propertyKey: string,
descriptor: PropertyDescriptor
) {
// what ever implementation you have in hooks...
};
}
这种方式将非(param) => void
类型的函数传递给装饰器时会导致编译错误。
更多信息在这里: https://www.typescriptlang.org/docs/handbook/decorators.html
这里是类型化函数数组,就像我在 ObjectInterface
上所做的那样:
A Typed array of functions
我找到了解决方案
interface Type<T> extends Function {
new (...args: any[]): T;
}
type HookMap<T> = {
[func in keyof T]?: any[];
};
function Hooks<T>(hookMap: HookMap<T>) {
return (clazz: Type<T>): void => {
// ...
};
}
class Parent {
parentMethod() {
// ...
}
}
@Hooks({
childMethod: [/* ... */],
parentMethod: [/* ... */]
})
class Child extends Parent {
childMethod() {
// ...
}
}