TypeScript 1.5 에는 이제 데코레이터가 있습니다.
누군가 데코레이터를 구현하는 올바른 방법을 보여주는 간단한 예제를 제공하고 가능한 데코레이터 서명의 인수가 무엇을 의미하는지 설명 할 수 있습니까?
declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
declare type ParameterDecorator = (target: Function, propertyKey: string | symbol, parameterIndex: number) => void;
또한 데코레이터를 구현하는 동안 명심해야 할 모범 사례가 있습니까?
답변
나는 데코레이터와 놀았고 문서가 나오기 전에 이것을 활용하려는 사람을 위해 알아 낸 것을 문서화하기로 결정했습니다. 실수가 있으면 언제든지 수정하십시오.
일반 사항
- 객체가 인스턴스화 될 때가 아니라 클래스가 선언 될 때 데코레이터가 호출됩니다.
- 동일한 클래스 / 속성 / 방법 / 매개 변수에 여러 데코레이터를 정의 할 수 있습니다.
- 생성자에는 데코레이터를 사용할 수 없습니다.
유효한 데코레이터는 다음과 같아야합니다.
- 데코레이터 유형 중 하나에 할당 할 수 있습니다 (
ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator
).- 데코 레이팅 된 값에 할당 할 수있는 값 (클래스 데코레이터 및 메서드 데코레이터의 경우)을 반환합니다.
방법 / 공식 접근 자 데코레이터
구현 매개 변수 :
target
: 클래스의 프로토 타입 (Object
).propertyKey
: 메소드 이름 (string
|symbol
).descriptor
: ATypedPropertyDescriptor
— 디스크립터의 키에 익숙하지 않다면, 이 문서 에서Object.defineProperty
세 번째 매개 변수 인 내용을 읽어 보는 것이 좋습니다 .
예-인수없는
사용하다:
class MyClass {
@log
myMethod(arg: string) {
return "Message -- " + arg;
}
}
이행:
function log(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
const originalMethod = descriptor.value; // save a reference to the original method
// NOTE: Do not use arrow syntax here. Use a function expression in
// order to use the correct value of `this` in this method (see notes below)
descriptor.value = function(...args: any[]) {
// pre
console.log("The method args are: " + JSON.stringify(args));
// run and store result
const result = originalMethod.apply(this, args);
// post
console.log("The return value is: " + result);
// return the result of the original method (or modify it before returning)
return result;
};
return descriptor;
}
입력:
new MyClass().myMethod("testing");
산출:
메소드 인수는 다음과 같습니다. [ “testing”]
리턴 값은 다음과 같습니다. 메시지-테스트
노트:
- 디스크립터 값을 설정할 때 화살표 구문을 사용하지 마십시오. 당신이 할 경우 의 문맥은
this
인스턴스의 것이 아닙니다. - 새 설명자를 반환하여 현재 설명자를 덮어 쓰는 것보다 원래 설명자를 수정하는 것이 좋습니다. 이를 통해 다른 데코레이터가 한 일을 덮어 쓰지 않고 설명자를 편집하는 여러 데코레이터를 사용할 수 있습니다. 이렇게하는 것은 당신이 좋아하는 무언가를 사용할 수
@enumerable(false)
와@log
같은 시간에 (예 : 나쁜 대 좋은 ) - 유용한 : 유형 인수
TypedPropertyDescriptor
메소드 서명 (무엇을 제한 할 수 있습니다 방법 예 ) 또는 접근 서명 ( 접근 자 예 ) 데코레이터가 넣을 수 있습니다.
예-인수 사용 (데코레이터 팩토리)
인수를 사용할 때 데코레이터의 매개 변수를 사용하여 함수를 선언 한 다음 인수없이 예제의 서명이있는 함수를 반환해야합니다.
class MyClass {
@enumerable(false)
get prop() {
return true;
}
}
function enumerable(isEnumerable: boolean) {
return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => {
descriptor.enumerable = isEnumerable;
return descriptor;
};
}
정적 메소드 데코레이터
몇 가지 차이점이있는 메소드 데코레이터와 유사합니다.
- 그것의
target
매개 변수는 생성자 함수 자체가 아닌 프로토 타입입니다. - 디스크립터는 프로토 타입이 아닌 생성자 함수에 정의되어 있습니다.
클래스 데코레이터
@isTestable
class MyClass {}
구현 매개 변수 :
target
: 데코레이터가 선언 된 클래스 (TFunction extends Function
).
사용 예 : 메타 데이터 API를 사용하여 클래스에 정보 저장
부동산 데코레이터
class MyClass {
@serialize
name: string;
}
구현 매개 변수 :
target
: 클래스의 프로토 타입 (Object
).propertyKey
: 속성 이름 (string
|symbol
).
사용 예 : @serialize("serializedName")
데코레이터를 만들고 직렬화 할 속성 목록에 속성 이름을 추가합니다.
파라미터 데코레이터
class MyClass {
myMethod(@myDecorator myParameter: string) {}
}
구현 매개 변수 :
target
: 클래스의 프로토 타입 (Function
– 그것은 보인다Function
더 이상 작동하지 않습니다 당신은 사용해야합니다.any
나Object
지금 여기있는 클래스 내에서 데코레이터를 사용하기 위해 또는 클래스 형을 (지정) 당신이 그것에을 제한합니다.)propertyKey
: 메소드 이름 (string
|symbol
).parameterIndex
: 함수 매개 변수 목록에서 매개 변수의 색인 (number
).
자세한 예
- 데코레이터 메모하기 -메소드, 접근 자 가져 오기 / 설정 데코레이터 예제
답변
다른 답변에서 볼 수없는 중요한 점은 다음과 같습니다.
데코레이터 공장
데코레이터가 선언에 적용되는 방식을 사용자 정의하려면 데코레이터 팩토리를 작성할 수 있습니다. 데코레이터 팩토리는 단순히 데코레이터가 런타임에 호출 할 표현식을 반환하는 함수입니다.
// This is a factory, returns one of ClassDecorator,
// PropertyDecorator, MethodDecorator, ParameterDecorator
function Entity(discriminator: string): {
return function(target) {
// this is the decorator, in this case ClassDecorator.
}
}
@Entity("cust")
export class MyCustomer { ... }
TypeScript 핸드북 데코레이터 장을 확인하십시오 .
답변
class Foo {
@consoleLogger
Boo(name:string) { return "Hello, " + name }
}
- 대상 : 위의 경우 클래스의 프로토 타입은 “Foo”입니다.
- propertyKey : 위의 경우 “Boo”에서 호출 된 메소드의 이름
- 설명자 : object =>의 설명은 value 속성을 포함하며, 이는 함수 자체입니다. function (name) {return ‘Hello’+ name; }
콘솔에 대한 각 호출을 기록하는 것을 구현할 수 있습니다.
function consoleLogger(target: Function, key:string, value:any)
{
return value: (...args: any[]) =>
{
var a = args.map(a => JSON.stringify(a)).join();
var result = value.value.apply(this, args);
var r = JSON.stringify(result);
console.log('called method' + key + ' with args ' + a + ' returned result ' + r);
return result;
}
}