타이프 스크립트 데코레이터를 구현하는 방법
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;
또한 데코레이터를 구현할 때 주의해야 할 베스트 프랙티스가 있습니까?
저는 결국 데코레이터와 놀아나게 되었고, 어떤 문서가 나오기 전에 이것을 이용하려는 사람들을 위해 제가 알아낸 것을 문서화하기로 결정했습니다.틀린 부분이 있으면 언제든지 수정해 주세요.
일반적인 점
- 데코레이터는 객체가 인스턴스화될 때가 아니라 클래스가 선언될 때 호출됩니다.
- 동일한 클래스/속성/메서드/파라미터에 여러 개의 데코레이터를 정의할 수 있습니다.
- 데코레이터는 생성자에 허용되지 않습니다.
유효한 데코레이터는 다음과 같습니다.
- 하나의 타입Decorator」)에(「Decorator」).
ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator
를 참조해 주세요.- 장식된 값에 할당할 수 있는 값(클래스 장식자 및 메서드 장식자의 경우)을 반환합니다.
메서드/포멀액세서 데코레이터
구현 파라미터:
target
: 클래스의 프로토타입(Object
를 참조해 주세요.propertyKey
: 서서 : : : : : : ) 。string
|symbol
).descriptor
: A - 디스크립터의 키가 익숙하지 않은 경우는, 다음의 메뉴얼을 참조해 주세요.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");
출력:
메서드 arg는 ["testing"]입니다.
반환값은 Message --testing 입니다.
주의:
- 설명자 값을 설정할 때 화살표 구문을 사용하지 마십시오.이 경우 의 컨텍스트는 인스턴스의 컨텍스트가 아닙니다.
- 새 설명자를 반환하여 현재 설명자를 덮어쓰는 것보다 원래 설명자를 수정하는 것이 좋습니다.이렇게 하면 다른 데코레이터가 한 작업을 덮어쓰지 않고 설명자를 편집하는 여러 데코레이터를 사용할 수 있습니다. '어울리다' 같은 것을 할 수 요.
@enumerable(false)
★★★★★★★★★★★★★★★★★」@log
동시에 (예: Bad vs Good) - [유용]: 의 type 인수
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")
- 설명자: 개체 =>에 대한 설명에 값 속성이 포함되어 있습니다. 이 속성은 함수 자체입니다. 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;
}
}
TS 데코레이터:
TS 데코레이터를 사용하면 클래스에 추가 기능을 추가할 수 있습니다.클래스는 클래스 인스턴스가 생성되기 전에 선언 시 데코레이터에 의해 변경됩니다.
구문:
데코레이터는 다음과 같이 선언됩니다.@
예를 들어 부호@metadata
. TS는 대응하는 메타데이터 함수를 검색하여 정확하게 장식된 항목에 따라 다른 sevaral 인수를 자동으로 제공합니다(예를 들어 클래스 또는 클래스 속성에서 다른 인수를 얻습니다).
다음 파라미터는 데코레이터 함수로 제공됩니다.
- 클래스의 원형 개체
- 속성 키 또는 메서드 이름
- PropertyDescriptor 개체는 다음과 같습니다.
{writable: true, enumerable: false, configurable: true, value: ƒ}
이들 인수 중 1~3은 데코레이터의 종류에 따라 데코레이터 기능에 전달됩니다.
데코레이터 유형:
다음 데코레이터를 클래스에 적용할 수 있으며 TS는 다음 순서로 데코레이터를 평가합니다(다음 합계를 TS 문서에서 참조).
- 각 인스턴스 구성원에 대해 매개 변수 장식기 다음에 메서드, 접근자 또는 특성 장식기가 적용됩니다.
- 각 정적 구성원에 대해 Method, Accessor 또는 Property Decorator에 이어 Parameter Decorator가 적용됩니다.
- 생성자에 매개변수 장식기가 적용됩니다.
- 클래스에 클래스 데코레이터가 적용됨
그것들을 더 잘 이해하는 가장 좋은 방법은 예를 들어보는 것이다.이러한 예에서는 TS 언어와 다음과 같은 개념을 충분히 이해할 필요가 있습니다.PropertyDescriptor
.
메서드 데코레이터:
function overwrite(
target: myClass,
propertyKey: string,
descriptor: PropertyDescriptor
) {
console.log('I get logged when the class is declared!')
// desciptor.value refers to the actual function fo the class
// we are changing it to another function which straight up
// overrides the other function
descriptor.value = function () {
return 'newValue method overwritten'
}
}
function enhance(
target: myClass,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const oldFunc = descriptor.value;
// desciptor.value refers to the actual function fo the class
// we are changing it to another function which calls the old
// function and does some extra stuff
descriptor.value = function (...args: any[]) {
console.log('log before');
const returnValue = oldFunc.apply(this, args)
console.log('log after');
return returnValue;
}
}
class myClass {
// here is the decorator applied
@overwrite
foo() {
return 'oldValue';
}
// here is the decorator applied
@enhance
bar() {
return 'oldValueBar';
}
}
const instance =new myClass()
console.log(instance.foo())
console.log(instance.bar())
// The following gets logged in this order:
//I get logged when the class is declared!
// newValue method overwritten
// log before
// log after
// oldValueBar
속성 장식자:
function metaData(
target: myClass,
propertyKey: string,
// A Property Descriptor is not provided as an argument to a property decorator due to
// how property decorators are initialized in TypeScript.
) {
console.log('Execute your custom code here')
console.log(propertyKey)
}
class myClass {
@metaData
foo = 5
}
// The following gets logged in this order:
// Execute your custom code here
// foo
클래스 데코레이터(TS 문서):
function seal(
constructor: Function,
) {
// Object.seal() does the following:
// Prevents the modification of attributes of
// existing properties, and prevents the addition
// of new properties
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@seal
class myClass {
bar?: any;
foo = 5
}
myClass.prototype.bar = 10;
// The following error will be thrown:
// Uncaught TypeError: Cannot add property bar,
// object is not extensible
데코레이터 및 데코레이터 공장:
데코레이터는 데코레이터 기능 또는 데코레이터 공장 기능을 통해 선언할 수 있습니다.구문에는 다음과 같은 차이가 있습니다.이러한 구문은 예를 통해 가장 잘 설명하겠습니다.
// Returns a decorator function, we can return any function
// based on argument if we want
function decoratorFactory(arg: string) {
return function decorator(
target: myClass,
propertyKey: string,
) {
console.log(`Log arg ${arg} in decorator factory`);
}
}
// Define a decorator function directly
function decorator(
target: myClass,
propertyKey: string,
) {
console.log('Standard argument');
}
class myClass {
// Note the parentheses and optional arguments
// in the decorator factory
@decoratorFactory('myArgument')
foo = 'foo';
// No parentheses or arguments
@decorator
bar = 'bar';
}
// The following gets logged in this order:
// Log arg myArgument in decorator factory
// Standard argument
또,decorate/enhance
원본 생성자에 대한 새로운 기능(전 3.9.7 사용)을 제공합니다.다음 스니펫은 원래 생성자를 랩하여 이름 속성의 접두사를 추가합니다.이 과정은 수업이 다음 시간에 따라instantiated
클래스가 '''일 때''입니다.declared
!
//Decorator function
function Prefixer(prefix: string) {
return function<T extends { new (...args: any[]): {name: string} }>(
originalCtor: T
) {
return class extends originalCtor {
constructor(..._: any[]) {
super();
this.name = `${prefix}.${this.name.toUpperCase()}`;
console.log(this.name);
}
};
};
}
가 「」인 .instantiated
은 원래 인 ctor 로직으로 됩니다.
@Prefixer('Mr')
class Person {
name = 'MBB';
constructor() {
console.log('original ctr logic here!');
}
}
const pers = new Person();
console.log(pers); //Mr.MBB
언급URL : https://stackoverflow.com/questions/29775830/how-to-implement-a-typescript-decorator
'programing' 카테고리의 다른 글
MongoDB를 서비스로 시작할 수 없습니다. (0) | 2023.03.06 |
---|---|
Mac OS X에서 MongoDB를 제거합니다. (0) | 2023.03.06 |
CORS는 도메인 간 AJAX 요청을 안전하게 처리하는 방법입니까? (0) | 2023.03.06 |
Reactjs: 문서가 정의되지 않았습니다. (0) | 2023.03.06 |
얄팍한 비교는 반응에서 어떻게 작용합니까? (0) | 2023.03.06 |