рдкрд╛рд╡рд░рдлреБрд▓ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдбреЗрдХреЛрд░реЗрдЯрд░реНрд╕ - рд╡реЗ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ, рдЙрдиреНрд╣реЗрдВ рдХрд┐рд╕ рдЪреАрдЬ рдореЗрдВ рд╕рдВрдХрд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдХрд┐рд╕рдХреЗ рд▓рд┐рдП рдЖрд╡реЗрджрди рдХрд╛рд░реНрдп рд▓рд╛рдЧреВ рд╣реЛрддреЗ рд╣реИрдВ

рдкреНрд░рддреНрдпреЗрдХ рдХреЛрдгреАрдп рдбреЗрд╡рд▓рдкрд░ рдиреЗ рд╕рдЬреНрдЬрд╛рдХрд╛рд░ рдХреЛ рдЯрд╛рдЗрдордХреЛрдб рдХреЛрдб рдореЗрдВ рджреЗрдЦрд╛ред рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдореЙрдбреНрдпреВрд▓ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ, рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдпрд╛ рдХрд┐рд╕реА рдШрдЯрдХ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдбреЗрдХреЛрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЕрддрд┐рд░рд┐рдХреНрдд рдЬрд╛рдирдХрд╛рд░реА рдпрд╛ рдореЗрдЯрд╛рдбреЗрдЯрд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдлреНрд░реЗрдорд╡рд░реНрдХ рдпрд╛ рдХрдВрдкрд╛рдЗрд▓рд░ (рдХреЛрдгреАрдп рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ) рдХреЗ рд▓рд┐рдПред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХреЛрдгреАрдп рдХреЗрд╡рд▓ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИред рдХрдИ рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИрдВ рдЬреЛ рдШреЛрд╖рдгрд╛ рдХреА рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд░реВрдк рдореЗрдВ рдХреЛрдб рдХреА рд╕рд╛рджрдЧреА рдФрд░ рджреГрд╢реНрдп рдХреЗ рд▓рд┐рдП рд╕рдЬреНрдЬрд╛рдХрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдЕрддреАрдд рдореЗрдВ .NET рдбреЗрд╡рд▓рдкрд░ рдХреЗ рд░реВрдк рдореЗрдВ, рдореБрдЭреЗ рдЯреАрдПрд╕ рдбреЗрдХреЛрд░реЗрдЯрд░реНрд╕ рдФрд░ .NET рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЗ рдмреАрдЪ рдмрд╣реБрдд рд╕реА рд╕рдорд╛рдирддрд╛рдПрдВ рджрд┐рдЦрд╛рдИ рджреЗрддреА рд╣реИрдВред рдЕрдВрдд рдореЗрдВ, рдмрдврд╝рддреЗ NestJS рдмреИрдХрдПрдВрдб рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдлреНрд░реЗрдорд╡рд░реНрдХ (рдиреЛрдб рдкрд░ рдПрдХ рдЕрдореВрд░реНрдд) рднреА рд╕рдЬреНрдЬрд╛рдХрд╛рд░реЛрдВ рдХреЗ рднрд╛рд░реА рдЙрдкрдпреЛрдЧ рдФрд░ рдПрдХ рдШреЛрд╖рдгрд╛рддреНрдордХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдкрд░ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рдпрд╣ рд╕рдм рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЕрдкрдиреЗ рдХреЛрдб рдореЗрдВ рдбреЗрдХреЛрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВ,рдЗрд╕реЗ рдФрд░ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдФрд░ рдкрдардиреАрдп рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП? рд╣рдо рд╕рднреА рд╕рдордЭрддреЗ рд╣реИрдВ рдХрд┐ рдЯреАрдПрд╕ рдХреЛрдб рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдореЗрдВ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛрдб рдорд┐рд▓рддрд╛ рд╣реИред рдЬрд┐рд╕рдореЗрдВ рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреА рдХреЛрдИ рдЕрд╡рдзрд╛рд░рдгрд╛ рдирд╣реАрдВ рд╣реИ, рдЬреИрд╕реЗ рдХрдИ рдЕрдиреНрдп рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕реБрд╡рд┐рдзрд╛рдПрдБред рдЗрд╕рд▓рд┐рдП, рдореЗрд░реЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рд╕рд╡рд╛рд▓ рдпрд╣ рд╣реИ рдХрд┐ рд╕рдВрдХрд▓рди рдХреЗ рдмрд╛рдж рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░рддреЗ рд╣реБрдП, рдореИрдВрдиреЗ рдорд┐рдиреНрд╕реНрдХ рдореЗрдВ рдмреИрдардХ рдореЗрдВ рднрд╛рд╖рдг рджрд┐рдпрд╛ рдФрд░ рдореИрдВ рдЗрд╕ рд▓реЗрдЦ рдХреЛ рд╕рд╛рдЭрд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред




  • тАФ


. , .


  • for Module declaration

@NgModule({
  imports: [
    CommonModule,
  ],
  exports: [
  ],
})
export class NbThemeModule {}

  • for component declaration

@Component({
  selector: 'nb-card-header',
  template: `<ng-content></ng-content>`,
})
export class NbCardHeaderComponent {}

, , , .


, tsconfig.json , emitDecoratorMetadata experimentalDecorators, .


{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es2017",
  },
}


, тАФ , , , get , . @expression, @ . expression . , , .


, тАФ , , . - .


, тАФ . , -, ( ). , , .



тАФ . Typescript :


declare type MethodDecorator = 
    <T>(
        target: Object, 
        propertyKey: string | symbol, 
        descriptor: TypedPropertyDescriptor<T>) 
=> TypedPropertyDescriptor<T> | void;

, . :


  • ,

:


interface TypedPropertyDescriptor<T> {
    enumerable?: boolean;
    configurable?: boolean;
    writable?: boolean;
    value?: T;
    get?: () => T;
    set?: (value: T) => void;
}

, , .


, - , . Javascript .


, - . тАФ .


class TestServiceDeco {

    @LogTime()
        testLogging() {
        ...
    }
}

, . Typescript , . , - , .

:


function LogTime() {
    return (target: Object, propertyName: string, descriptor: TypedPropertyDescriptor<Function>) => {
        const method = descriptor.value;
        descriptor.value = function(...args) {
            console.time(propertyName || 'LogTime');
            const result = method.apply(this, args);
            console.timeEnd(propertyName || 'LogTime');
            return result;
        };
    };
}

, тАФ , . тАФ target, propertyName . .


тАФ , . , , . .


Javascript


"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function LogTime() {
    return (target, propertyName, descriptor) => {
        const method = descriptor.value;
        descriptor.value = function (...args) {
            console.time(propertyName || 'LogTime');
            const result = method.apply(this, args);
            console.timeEnd(propertyName || 'LogTime');
            return result;
        };
    };
}
exports.LogTime = LogTime;

, Typescript . :


Object.defineProperty(exports, "__esModule", { value: true });
const log_time_decorator_1 = require("../src/samples/log-time.decorator");
class TestServiceDeco {
    testLogging() {
...    }
}
__decorate([
    log_time_decorator_1.LogTime(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], TestServiceDeco.prototype, "testLogging", null);

__decorate, .


, target prototype , .

, __decorate, , . , . .



, . тАФ . тАФ . тАФ Dependency Injection. . , :


@CustomBehavior({
    singleton: false,
})
class TestServiceDeco {
    constructor() {
        console.log('TestServiceDeco ctor');
    }
}

, Typescript:


declare type ClassDecorator = 
    <TFunction extends Function>(target: TFunction) 
    => TFunction | void;

:


import 'reflect-metadata';

interface Metadata {
    singleton?: boolean;
}

function CustomBehavior(metadata: Metadata) {
    return function(ctor: Function) {
        Reflect.defineMetadata('metadataKey', metadata, ctor);
    }
}

. тАФ singelton- . .


:


  • target
  • reflect-metadata

Reflect-metadata Typescript. , тАФ . , , .


import 'reflect-metadata';

const instancesMap: Map<Object, Object> = new Map<Object, Object>();

function getInstance<T>(tType: new () => T): T {
    let metadata = Reflect.getMetadata('metadataKey', tType) as Metadata;
    if (metadata.singleton) {
        if (!instancesMap.has(tType)) {
            instancesMap.set(tType, new tType());
        }
        return instancesMap.get(tType) as T;
    } else {
        return new tType() as T;
    }
}

  • getInstance, , ,
  • Reflect.getMetadata , . any, as Metadata
  • , . tType: new () => T
  • - , Map

, , .


getInstance, .


, . , Javascript .


. , , , . , Person Age, 18 60. :


class Person {
    @Age(18, 60)
    age: number;
}

:


declare type PropertyDecorator = 
    (target: Object, propertyKey: string | symbol) => void;

:


import 'reflect-metadata';

function Age(from: number, to: number) {
    return function (object: Object, propertyName: string) {
        const metadata = {
            propertyName: propertyName,
            range: { from, to },
        };
        Reflect.defineMetadata(`validationMetadata_${propertyName}`, metadata, object.constructor);
    };
}

, . . , , , . , .


:


class Person {
...
}
__decorate([
    age_decorator_1.Age(18, 60),
    __metadata("design:type", Number)
], Person.prototype, "age", void 0);

, __decorate, .


, тАФ , . тАФ , , .


, :


function validate<T>(object: T) {
    const properties = Object.getOwnPropertyNames(object);
    properties.forEach(propertyName => {
        let metadata = Reflect.getMetadata(metaKey + propertyName, object.constructor);
        if (metadata && metadata.range) {
            const value = object[metadata.propertyName];
            if (value < metadata.range.from || value > metadata.range.to) {
                throw new Error('Validation failed');
            }
        }
    });
}

, , . .


:


const person = new Person();
person.age = 40;
validate(person);
// > validation passed

person.age = 16;
validate(person);
// > validation error


, , , .


, :


declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void;


Class-Validator


Class-Validator, . .


export class Post {

    @Length(10, 20)
    title: string;

    @IsInt()
    @Min(0)
    @Max(10)
    rating: number;

    @IsEmail()
    email: string;
}

...

validate(object).then(errors => { // array of validation errors
    if (errors.length > 0) {
        console.log("validation failed. errors: ", errors);
    } else {
        console.log("validation succeed");
    }
});

, . .


, NestJS @UsePipes(new ValidationPipe()) http .



Typescript , . , -. , , , , , , , тАж Angular NestJS. ( ).


, , , , , !


ps рд▓рд┐рдЦрддреЗ рд╕рдордп (рдпрд╛ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рд▓реЗрдЦ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░рддреЗ рд╣реБрдП), рдореИрдВрдиреЗ рд╣рдм рдкрд░ рдПрдХ рдФрд░ рд╡рд╣реАрдВ рдкрд╛рдпрд╛, рдЬреЛ рд╕рдЬреНрдЬрд╛рдХрд╛рд░реЛрдВ рдХреЗ рд╡рд┐рд╖рдп рдХреЛ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдкреНрд░рдХрдЯ рдХрд░рддрд╛ рд╣реИред рдореИрдВ рдПрдХ рд▓рд┐рдВрдХ рджреЗрддрд╛ рд╣реВрдВ


All Articles