Decorators trong Typescript

Các bạn dev nào từng làm Angular chắc sẽ khá quen thuộc với Decorators đúng không? Nhưng bạn thật sự đã hiểu rõ về nó hay chưa? Chúng ta hãy cùng nhau ôn bài một tí nhé ^_^
Decorators trong Typescript
Decorators trong Typescript

TypeScript là một ngôn ngữ lập trình tuyệt vời. Nó cho phép bạn viết code tốt hơn trong hầu hết mọi trường hợp. Nó giúp chúng ta giảm thiểu được các lỗi mắc phải trong lúc viết code thay vì quăng lỗi vào mặt chúng ta trong lúc chạy =)).

Tuy nhiên, để trở thành một lập trình viên xịn xò và mạnh mẽ, chúng ta vẫn nên dành trọn trái tim của mình cho việc fix bug nhé <3.

Fix Bug

Hôm nay mình muốn chia sẻ với các bạn một tính năng có thể cải thiện rất nhiều quy trình code của chúng ta.

Let's start!

 

Decorators - nó là cái gì?

Decorator là một cách khai báo đặc biệt để có thể được đính kèm một số metadata khi khai báo các class, method, accessor, property hoặc các parameter. Decorator sử dụng từ khóa @expression, trong đó expression là tên một function sẽ được gọi khi runtime với thông tin được khai báo trong decorator.

Decorator không phải là một tính năng mới của TypeScript, mà thực sự nó đến từ JavaScript, là một đề xuất trong giai đoạn 2. Khi code được dịch bởi TypeScript, decorator sẽ wrap các thứ này lại và thêm vào các metadata.

Trong JavaScript thuần từ trước phiên bản ES6, khái niệm decorator cũng đã xuất hiện dưới dạng "functional composition" - wrap một function bằng một function khác.

Ví dụ: khi ta cần ghi log lại hoạt động của một function , ta có thể tạo 1 decorator function bao bọc lấy function cần thực hiện.

function doBusinessJob() {
    console.log('do my job')
}

function logDecorator(job) {
    return function () {
        console.log('start my job')
        var result = job.apply(this, arguments)
        return result
    }
}

var logWrapper = logDecorator(doBusinessJob)

Bản chất của decorators chỉ là các hàm JavaScript, có thể được “hook” vào các class, method, accessor, properties hoặc parameters.

Nếu bạn từng làm việc với React JS, chắc chắn bạn cũng đã nghe tới khái niệm Higher-Order Component, thì thực tế nó cũng hoạt động theo cách tương tự.

Làm nhẹ vài cái ví dụ nhé.

 

Không sử dụng decorators:

interface InitArguments {
    fuel: number;
}

class Rocket {
    fuel: number

    constructor(args: InitArguments) {
        this.fuel = args.fuel || 0
    }
}

class Falcon9 extends Rocket {}

class Starship extends Rocket {}

const falcon = new Falcon9({fuel: 100})

const starship = new Starship({fuel: 250})

 

Có sử dụng decorators:

function Init(args: InitArguments) {
    return <T extends { new (...args: any[]): {} }>(constructor: T) => {
        return class extends constructor {
            fuel = args.fuel || 0
        }
    }
}

interface InitArguments {
    fuel: number;
}

class Rocket {
    fuel: number
}

@Init({fuel: 100})
class Falcon9 extends Rocket {}

@Init({fuel: 250})
class Starship extends Rocket {}

const falcon = new Falcon9()
const starship = new Starship()

console.log(`Fueled Falcon9 with ${falcon9.fuel}T.`)
//Fueled Falcon9 with 100T.

console.log(`Fueled Starship with ${starship.fuel}T.`)
//Fueled Starship with 250T.

Phía bên dưới là đoạn code Javascript đã được Typescript transpiled. Constructor được wrap bởi hàm decorator, đó là cách mà thuộc tính fuel được thiết lập. 

Nếu bạn đã từng sử dụng Angular, đó chính xác là những gì xảy ra bên dưới với decorator @component@inject.

"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function Init(args) {
    return (constructor) => {
        return class extends constructor {
            constructor() {
                super(...arguments);
                this.fuel = args.fuel || 0;
            }
        };
    };
}
class Rocket {
}
let Falcon9 = class Falcon9 extends Rocket {
};
Falcon9 = __decorate([
    Init({ fuel: 100 })
], Falcon9);
let Starship = class Starship extends Rocket {
};
Starship = __decorate([
    Init({ fuel: 250 })
], Starship);
const falcon = new Falcon9();
const starship = new Starship();
console.log(`Fueled Falcon9 with ${falcon9.fuel}T.`);
//Fueled Falcon9 with 100T.
console.log(`Fueled Starship with ${starship.fuel}T.`);
//Fueled Starship with 250T.

 

Multiple decorators

Chúng ta có thể khai báo multiple decorators cho đối tượng. Có 2 cách để triển khai như sau:

  • Trên cùng một hàng. Các decorator sẽ được dịch tuần tự từ trái qua phải. Các kết quả (results) sau đó sẽ là các functions được gọi tuần tự từ phải qua trái.
@foo @bar myFunction() {}

//foo(bar(myFunction))
  • Trên nhiều hàng. Các decorator sẽ được dịch tuần tự từ trên xuống dưới. Các kết quả (results) sau đó sẽ là các functions được gọi tuần tự từ dưới lên trên.
@foo 
@bar 
myFunction() {

}

//foo(bar(myFunction))

 

Các loại Decorator

Trong Typescript, có 5 loại decorator:

  • Class decorator
  • Method decorator
  • Property decorator
  • Accessor decorator
  • Parameter decorator

Có một thứ tự được xác định rõ ràng về cách áp dụng cho các kiểu khai báo decorator khác nhau bên trong một class:

  • Parameter Decorators, sau đó là Method Decorators, Accessor Decorators, hoặc Property Decorators:
    • Áp dụng cho từng instance member.
    • Áp dụng cho từng static member.
  • Parameter Decorators
    • Áp dụng cho constructor.
  • Class Decorators
    • Áp dụng cho class.

 

Class decorators

Class decorators được khai báo ngay trước đoạn khai báo class.

Class decorators được áp dụng cho constructor của class và có thể được sử dụng để observe, sửa đổi hoặc thay thế định nghĩa của class đó.

Không thể được khai báo trong tập tin declaration (thường là index.d.ts của một số packages) cũng như một vài context khác xung quanh (chẳng hạn khi bạn khai báo declare class).

@foo()
declare class Foo {} //Incorrect

Class decorators sẽ được gọi như một function lúc runtime, với constructor của class là parameter duy nhất.

Nếu Class decorators trả về một giá trị, nó sẽ thay thế định nghĩa class bằng hàm constructor được cung cấp.

Chú ý: Nếu bạn lựa chọn trả về một hàm constructor mới, bạn phải chú ý duy trì prototype ban đầu. Các logic áp dụng decorators sẽ không làm điều này cho bạn lúc runtime.

Sau đây là một ví dụ về class decorator (@sealed) được áp dụng cho class Greeter:

function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return "Hello, " + this.greeting;
  }
}

Khi @sealed được thực thi, nó sẽ seal cả constructor và prototype của nó.

Còn đây là ví dụ về cách override constructor của class:

function classDecorator<T extends { new(...args: any[]): {} }>(constructor: T) {
    return class extends constructor {
        newProperty = "new property"
        hello = "override"
    }
}

@classDecorator
class Greeter {
    property = "property"
    hello: string
    constructor(m: string) {
        this.hello = m
    }
}

console.log(new Greeter("world"))

 

Method Decorators

Một Method Decorator được khai báo ngay trước khi khai báo method của class. Method Decorator được áp dụng cho Property Descriptor và có thể được sử dụng để observe, sửa đổi hoặc thay thế định nghĩa của method.

Không thể được khai báo trong tập tin declaration (thường là index.d.ts của một số packages), khi thực hiện overload cũng như một vài context khác xung quanh (chẳng hạn khi bạn khai báo declare class).

Biểu thức của method decorator sẽ được chạy bằng một function lúc runtime, với 3 tham số như sau:

  1. Hàm constructor của class cho static member, hoặc prototype của class cho instance member.
  2. Tên của member.
  3. Property Descriptor của member.

Chú ý: Property Descriptor sẽ là undefined nếu script target nhỏ hơn ES5.

Nếu method decorator trả về một giá trị, nó sẽ được sử dụng làm Property Descriptor cho method đó.

Chú ý: Giá trị trả về sẽ bị bỏ qua nếu script target nhỏ hơn ES5.

Sau đây là một ví dụ về method decorator (@enumerable) được áp dụng cho một method trên class Greeter:

function enumerable(value: boolean) {
    return function (
        target: any,
        propertyKey: string,
        descriptor: PropertyDescriptor
    ) {
        descriptor.enumerable = value;
    }
}

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message
    }

    @enumerable(false)
    greet() {
        return "Hello, " + this.greeting
    }
}

Decorator @enumerable(false) ở đây là một decorator factory. Khi decorator @enumerable(false) được gọi, nó sẽ sửa đổi property enumerable của property descriptor.

 

Accessor Decorators

Một Accessor Decorator được khai báo ngay trước một khai báo accessor. Accessor Decorator được áp dụng cho Property Descriptor của accessor và có thể được sử dụng để observe, sửa đổi hoặc thay thế các định nghĩa của accessor.

Không thể được khai báo trong tập tin declaration (thường là index.d.ts của một số packages) cũng như một vài context khác xung quanh (chẳng hạn khi bạn khai báo declare class).

Chú ý: TypeScript không cho phép decorating cả hai bộ accessor getset của một member duy nhất. Thay vào đó, tất cả các decorators cho member phải được áp dụng cho accessor đầu tiên được chỉ định trong thứ tự tài liệu. Điều này là do decorators áp dụng cho Property Descriptor, bộ này kết hợp cả hai accessor getset, mà không phải khai báo riêng biệt cho mỗi thứ.

Biểu thức của accessor decorator sẽ được chạy bằng một function lúc runtime, với 3 tham số như sau:

  1. Hàm constructor của class cho static member, hoặc prototype của class cho instance member.
  2. Tên của member.
  3. Property Descriptor của member.

Chú ý: Property Descriptor sẽ là undefined nếu script target nhỏ hơn ES5.

Nếu accessor decorator trả về một giá trị, nó sẽ được sử dụng làm Property Descriptor cho member đó.

Chú ý: Giá trị trả về sẽ bị bỏ qua nếu script target nhỏ hơn ES5.

Sau đây là ví dụ về accessor decorator (@configurable) được áp dụng cho một member của class Point:

function configurable(value: boolean) {
    return function (
        target: any,
        propertyKey: string,
        descriptor: PropertyDescriptor
    ) {
        descriptor.configurable = value;
    };
}

class Point {
    private _x: number;
    private _y: number;
    constructor(x: number, y: number) {
        this._x = x;
        this._y = y;
    }

    @configurable(false)
    get x() {
        return this._x;
    }

    @configurable(false)
    get y() {
        return this._y;
    }
}

 

Property Decorators

Property Decorator được khai báo ngay trước khi khai báo property.

Không thể được khai báo trong tập tin declaration (thường là index.d.ts của một số packages) cũng như một vài context khác xung quanh (chẳng hạn khi bạn khai báo declare class).

Biểu thức của property decorator sẽ được chạy bằng một function lúc runtime, với 2 tham số như sau:

  1. Hàm constructor của class cho static member, hoặc prototype của class cho instance member.
  2. Tên của member.

Chú ý: Property Descriptor không được cung cấp làm tham số cho Property Decorator do cách Property Decorator được khởi tạo trong TypeScript.

Điều này là do hiện tại không có cơ chế để mô tả thuộc tính của một instance khi khai báo các members của một prototype và không có cách nào để observe hoặc sửa đổi giá trị khởi tạo của một property. Giá trị trả về cũng bị bỏ qua. Do đó, một Property Decorator chỉ có thể được sử dụng để observe rằng một property của một name cụ thể đã được khai báo cho một class.

Chúng ta có thể sử dụng thông tin này để ghi lại metadata cho property, như trong ví dụ sau đây:

import "reflect-metadata";

const formatMetadataKey = Symbol("format");

function format(formatString: string) {
    return Reflect.metadata(formatMetadataKey, formatString);
}

function getFormat(target: any, propertyKey: string) {
    return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}

class Greeter {
    @format("Hello, %s")
    greeting: string;

    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        let formatString = getFormat(this, "greeting");
        return formatString.replace("%s", this.greeting);
    }
}

Decorator @format("Hello, %s") ở đây là một decorator factory. Khi @format("Hello, %s") được gọi, nó sẽ thêm một metadata cho property bằng cách sử dụng hàm Reflect.metadata từ thư viện reflect-metadata. Khi getFormat được gọi, nó sẽ đọc giá trị metadata cho việc format.

 

Parameter Decorators

Parameter Decorator được khai báo ngay trước khi khai báo tham số. Parameter Decorator được áp dụng cho function để khai báo parameter hoặc class constructor.

Không thể được khai báo trong tập tin declaration (thường là index.d.ts của một số packages), khi thực hiện overload cũng như một vài context khác xung quanh (chẳng hạn khi bạn khai báo declare class).

Biểu thức của Parameter Decorator sẽ được chạy bằng một function lúc runtime, với 3 tham số như sau:

  1. Hàm constructor của class cho static member, hoặc prototype của class cho instance member.
  2. Tên của member.
  3. Số thứ tự của parameter trong danh sách parameter của function.

Chú ý: Chỉ có thể sử dụng Parameter Decorator để observe rằng một parameter đã được khai báo trên một method.

Giá trị trả về của Parameter Decorator bị bỏ qua.

Sau đây là một ví dụ về Parameter Decorator (@required) được áp dụng cho parameter của member class Greeter:

import "reflect-metadata";

const requiredMetadataKey = Symbol("required");

function required(
    target: Object,
    propertyKey: string | symbol,
    parameterIndex: number
) {
    let existingRequiredParameters: number[] =
        Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
    existingRequiredParameters.push(parameterIndex);
    Reflect.defineMetadata(
        requiredMetadataKey,
        existingRequiredParameters,
        target,
        propertyKey
    );
}

function validate(
    target: any,
    propertyName: string,
    descriptor: TypedPropertyDescriptor<Function>
) {
    let method = descriptor.value;
    descriptor.value = function () {
        let requiredParameters: number[] = Reflect.getOwnMetadata(
            requiredMetadataKey,
            target,
            propertyName
        );
        if (requiredParameters) {
            for (let parameterIndex of requiredParameters) {
                if (
                    parameterIndex >= arguments.length ||
                    arguments[parameterIndex] === undefined
                ) {
                    throw new Error("Missing required argument.");
                }
            }
        }

        return method.apply(this, arguments);
    };
}

class Greeter {
    greeting: string;

    constructor(message: string) {
        this.greeting = message;
    }

    @validate
    greet(@required name: string) {
        return "Hello " + name + ", " + this.greeting;
    }
}

Decorator @required thêm một metadata đánh dấu parameter name là bắt buộc. Sau đó, decorator @validate wrap method greet() trong một function để validate các tham số trước khi gọi method ban đầu.

 

Metadata

Một số ví dụ phía trên sử dụng thư viện reflect-metadata để thêm một polyfill cho experimental metadata API. Thư viện này chưa phải là một phần của tiêu chuẩn ECMAScript (JavaScript). Tuy nhiên, khi các decorators được chính thức chấp nhận như một phần của tiêu chuẩn ECMAScript, các phần mở rộng này sẽ được đề xuất áp dụng.

Cài đặt nó qua command line:

npm i reflect-metadata --save

TypeScript hỗ trợ một số tính năng thử nghiệm để tạo ra một số loại metadata nhất định cho các khai báo có decorators. Bạn có 2 cách để bật hỗ trợ tính năng thử nghiệm này.

Chạy command line:

tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata

Hoặc cập nhật tsconfig.json:

{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

 

Tổng kết

Decorator, Metadata là các tính năng thử nghiệm và có thể dẫn đến các breaking changes trong tương lai.

Tuy nhiên, đây đều là các tính năng đã được xác nhận là đang (và sẽ) được implement vào JavaScript trong tương lai, nên ta có thể yên tâm sử dụng nó thông qua cách mà TypeScript cung cấp mà không phải quá lo lắng.

Nếu chết thì cùng chết cả đám thôi ấy mà =)))

 

Comments

Mục lục

Bài viết nổi bật

PHP là ngôn ngữ được sử dụng rộng rãi nhất trên thế giới trong lập trình web. Nó cũng bị ghét nhất. Nhưng tại sao nhiều developer lại ghét nó đến vậy? Hôm nay chúng ta hãy cùng tìm hiểu lý do xem chúng có thuyết phục không nhé ^_^
Ở bài viết này mình sẽ hướng dẫn bạn bắt đầu xây dựng một ứng dụng HMVC với Laravel, và tận dụng sức mạnh của Composer khi quản lí modules.
Có khá nhiều bạn đã yêu cầu mình một bài viết về Repository Design Pattern. Vậy mục đích của nó là gì? Nó có thực sự cần thiết cho ứng dụng của bạn hay không? Những điểm mạnh, điểm yếu của nó là gì? Chúng ta cùng đi sâu tìm hiểu qua bài viết này nhé.
Trong quá trình làm việc với Laravel Eloquent ORM, chắc hẳn các bạn từng thực hiện khá nhiều tác vụ lặp đi lặp lại - mà bạn không hề biết Laravel đã hỗ trợ sẵn. Thông qua vài mẹo và thủ thuật nhỏ trong bài viết này, mình hi vọng sẽ giúp các bạn giảm bớt sự phức tạp khi viết code cũng như bớt nhàm chán khi thực hiện các tác vụ lặp đi lặp lại theo cách thông thường.
Như đã được thông báo vào năm 2018, React Native đã và đang được đội ngũ phát triển của Facebook nỗ lực tái kiến trúc nhằm giúp nền tảng này trở nên mạnh mẽ hơn và giải quyết một số vấn đề phổ biến mà các nhà phát triển đã gặp phải trong vài năm qua.

Related posts

Redux là một framework quản lý state dựa trên ý tưởng: tất cả các state của ứng dụng sẽ được lưu xuống một global state và sử dụng các reducer function để tương tác với chúng.
Styled-Components là một thư viện giúp bạn tổ chức và quản lý styles trong các dự án sử dụng React tuân theo đề xuất từ Facebook.
PHP là ngôn ngữ được sử dụng rộng rãi nhất trên thế giới trong lập trình web. Nó cũng bị ghét nhất. Nhưng tại sao nhiều developer lại ghét nó đến vậy? Hôm nay chúng ta hãy cùng tìm hiểu lý do xem chúng có thuyết phục không nhé ^_^
Là developer, chúng ta luôn tìm cách để tiết kiệm thời gian cho các dự án của mình. Đó là lý do tại sao các thư viện được tạo ra để giảm bớt các khó khăn khi triển khai những thứ lặp đi lặp lại. Với các frontend framework như React, việc chia sẻ chức năng chung cho các dự án khác nhau trở nên dễ dàng hơn bao giờ hết.
Snappy là một thư viện PHP cho phép tạo các thumnails, snapshots và PDF từ URL hoặc trang HTML. Tác giả Barryvdh đã viết thư viện Laravel Snappy giúp việc tích hợp với Laravel dễ dàng hơn.
Bạn có thể sử dụng tính năng kiểm tra kiểu dữ liệu của Typescript để xác định các interface cho các components, nhằm chắc chắn rằng component của bạn chỉ nhận được các thông tin đầu vào chính xác.
Bài viết này cung cấp một cái nhìn tổng quan ngắn gọn về TypeScript, tập trung vào hệ thống kiểu dữ liệu của nó.
Hooks là một tính năng bổ sung mới từ React 16.8 trở đi. Chúng cho phép bạn sử dụng State và các tính năng khác của React mà không cần viết một class.
Giới thiệu series react
601
Một vài kiến thức cơ bản cũng như nâng cao mà mình sẽ tổng hợp lại trong quá trình làm việc cũng như self learning
JWT Tokens là một cách thức lưu trữ thông tin xác thực hiệu quả, nhưng làm cách nào để chúng ta có thể giúp chúng an toàn hơn? Có 2 cách thường dùng để lưu trữ JWT Tokens là LocalStorage và Cookies. Bây giờ chúng ta sẽ bắt đầu "mổ xẻ" các ưu - nhược điểm của mỗi loại nhé.
Flexbox toàn tập
1428
Bài viết này sẽ hướng dẫn cho bạn mọi thứ về flexbox, bao gồm tất cả các thuộc tính cho phần tử cha (flex container) và phần tử con (flex items).
Như đã được thông báo vào năm 2018, React Native đã và đang được đội ngũ phát triển của Facebook nỗ lực tái kiến trúc nhằm giúp nền tảng này trở nên mạnh mẽ hơn và giải quyết một số vấn đề phổ biến mà các nhà phát triển đã gặp phải trong vài năm qua.

Tin mới nhất

Redux là một framework quản lý state dựa trên ý tưởng: tất cả các state của ứng dụng sẽ được lưu xuống một global state và sử dụng các reducer function để tương tác với chúng.
Styled-Components là một thư viện giúp bạn tổ chức và quản lý styles trong các dự án sử dụng React tuân theo đề xuất từ Facebook.
Decorators trong Typescript
1105
Các bạn dev nào từng làm Angular chắc sẽ khá quen thuộc với Decorators đúng không? Nhưng bạn thật sự đã hiểu rõ về nó hay chưa? Chúng ta hãy cùng nhau ôn bài một tí nhé ^_^
PHP là ngôn ngữ được sử dụng rộng rãi nhất trên thế giới trong lập trình web. Nó cũng bị ghét nhất. Nhưng tại sao nhiều developer lại ghét nó đến vậy? Hôm nay chúng ta hãy cùng tìm hiểu lý do xem chúng có thuyết phục không nhé ^_^
Là developer, chúng ta luôn tìm cách để tiết kiệm thời gian cho các dự án của mình. Đó là lý do tại sao các thư viện được tạo ra để giảm bớt các khó khăn khi triển khai những thứ lặp đi lặp lại. Với các frontend framework như React, việc chia sẻ chức năng chung cho các dự án khác nhau trở nên dễ dàng hơn bao giờ hết.
Snappy là một thư viện PHP cho phép tạo các thumnails, snapshots và PDF từ URL hoặc trang HTML. Tác giả Barryvdh đã viết thư viện Laravel Snappy giúp việc tích hợp với Laravel dễ dàng hơn.
IRAC (Issue - Rule - Analysis - Conclusion) là một phương pháp phổ biến và quen thuộc với sinh viên luật và dân luật nói chung. Cá nhân mình thấy phương pháp này khá hay và hoàn toàn có thể áp dụng vào bất cứ công việc hoặc ngành nghề nào.
Bạn có thể sử dụng tính năng kiểm tra kiểu dữ liệu của Typescript để xác định các interface cho các components, nhằm chắc chắn rằng component của bạn chỉ nhận được các thông tin đầu vào chính xác.
Bài viết này cung cấp một cái nhìn tổng quan ngắn gọn về TypeScript, tập trung vào hệ thống kiểu dữ liệu của nó.
Hooks là một tính năng bổ sung mới từ React 16.8 trở đi. Chúng cho phép bạn sử dụng State và các tính năng khác của React mà không cần viết một class.
Giới thiệu series react
601
Một vài kiến thức cơ bản cũng như nâng cao mà mình sẽ tổng hợp lại trong quá trình làm việc cũng như self learning
JWT Tokens là một cách thức lưu trữ thông tin xác thực hiệu quả, nhưng làm cách nào để chúng ta có thể giúp chúng an toàn hơn? Có 2 cách thường dùng để lưu trữ JWT Tokens là LocalStorage và Cookies. Bây giờ chúng ta sẽ bắt đầu "mổ xẻ" các ưu - nhược điểm của mỗi loại nhé.
Redux là một framework quản lý state dựa trên ý tưởng: tất cả các state của ứng dụng sẽ được lưu xuống một global state và sử dụng các reducer function để tương tác với chúng.
Styled-Components là một thư viện giúp bạn tổ chức và quản lý styles trong các dự án sử dụng React tuân theo đề xuất từ Facebook.
Decorators trong Typescript
1105
Các bạn dev nào từng làm Angular chắc sẽ khá quen thuộc với Decorators đúng không? Nhưng bạn thật sự đã hiểu rõ về nó hay chưa? Chúng ta hãy cùng nhau ôn bài một tí nhé ^_^
PHP là ngôn ngữ được sử dụng rộng rãi nhất trên thế giới trong lập trình web. Nó cũng bị ghét nhất. Nhưng tại sao nhiều developer lại ghét nó đến vậy? Hôm nay chúng ta hãy cùng tìm hiểu lý do xem chúng có thuyết phục không nhé ^_^
Là developer, chúng ta luôn tìm cách để tiết kiệm thời gian cho các dự án của mình. Đó là lý do tại sao các thư viện được tạo ra để giảm bớt các khó khăn khi triển khai những thứ lặp đi lặp lại. Với các frontend framework như React, việc chia sẻ chức năng chung cho các dự án khác nhau trở nên dễ dàng hơn bao giờ hết.