Những mẹo nhỏ khi làm việc với Laravel Eloquent

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ững mẹo nhỏ khi làm việc với Laravel Eloquent
Những mẹo nhỏ khi làm việc với Laravel Eloquent

Tăng hoặc giảm giá trị của một thuộc tính

Mình cá là có khá nhiều người đã từng viết những thứ đại loại như thế này:

$page = Page::find($id);

$page->views_count++;
$page->save();

Cách này hoàn toàn đúng nha các bạn, nhưng mình có thể viết lại như sau:

$page = Page::find($id);

$page->increment('views_count');

Đẹp hơn rồi phải không ^^

Các cách viết như sau cũng hoàn toàn hợp lệ:

Page::find($id)->increment('views_count'); //+1

Page::find($id)->increment('views_count', 100); //+100

Product::find($productId)->decrement('stock'); //-1

 

Khởi tạo nhanh Model và Migration

Thường khi chúng ta cần tạo ra model và migration, chúng ta sẽ thực hiện tuần tự các lệnh sau:

$ php artisan make:migration create_posts_table --create=posts
$ php artisan make:model Post

Chúng ta chỉ cần thực hiện một trong hai câu lệnh đơn giản hơn sau đây:

$ php artisan make:model Post -migration
$ php artisan make:model Post -m

 

Các phương thức XorY

Eloquent hỗ trợ một số phương thức kết hợp 2 chức năng, đại loại là "Thực hiện X, ngược lại thực hiện Y". 

Khó hiểu quá hả? Vậy chúng ta cùng xem qua một vài ví dụ nhé.

Ví dụ 1: phương thức findOrFail()

Chúng ta có một đoạn code như thế này:

$post = Post::find($id);

if (!$post) {
    abort(404);
}

Thay vì viết phức tạp như vậy, chúng ta có thể viết trực tiếp như sau:

$post = Post::findOrFail($id);

Ví dụ 2: phương thức firstOrCreate()

Phàm nhân sẽ viết như thế này:

$user = User::where('email', $email)->first();

if (!$user) {
    $user = User::create(['email' => $email]);
}

Chúng ta sẽ thử cách khác xịn xò hơn:

$user = User::firstOrCreate(['email' => $email]);

Ví dụ 3: phương thức insertOrIgnore()

Khi chúng ta thực hiện việc insert một danh sách các bản ghi vào cơ sở dữ liệu, chúng ta thường dùng phương thức insert() để giải quyết:

Post::insert([
    ['name' => 'Post 1', 'status' => 'active'],
    ['name' => 'Post 2', 'status' => 'active'],
]);

Khi chúng ta muốn bỏ qua các bản ghi bị lỗi xảy ra trong quá trình insert:

Post::insertOrIgnore([
    ['name' => 'Post 1', 'status' => 'active'],
    ['name' => 'Post 2', 'status' => 'active'],
]);

 

Phương thức boot()

Chà chà, đây là một nơi kỳ diệu mà Eloquent hỗ trợ chúng ta có thể ghi đè các hành vi mặc định khi thực hiện một số tác vụ nào đó.

Bên dưới là một ví dụ nhỏ về việc thêm một trường uuid vào bảng tại thời điểm tạo mới một User

class User extends Model
{
    public static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            $model->uuid = (string)Uuid::generate();
        });
    }
}

Cũng khá dễ hiểu đúng không các bạn ^^

Eloquent cũng cung cấp các phương thức obsever khác hỗ trợ cho quá trình thao tác với model như: updatingdeleting... Bạn có thể tham khảo liên kết sau để biết thêm nhiều thông tin hơn https://laravel.com/docs/7.x/eloquent.

 

Thiết lập relationship với các điều kiện và thứ tự sắp xếp

Bên dưới là một ví dụ điển hình cho việc thiết lập relationship giữa 2 model User và Post:

class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

Nhưng nếu như bạn muốn thêm một số điều kiện ràng buộc ở đây, hoặc sắp xếp thứ tự hiển thị của các bài viết thì sao?

Eloquent hỗ trợ thực hiện điều này khá dễ dàng:

public function posts()
{
    return $this->hasMany(Post::class)->where('status', 1)->orderByDesc('published_at');
}

 

Các thuộc tính của Model

Bạn có thể cấu hình một số tham số của Eloquent dưới dạng thuộc tính của lớp. Dưới đây là một số thuộc tính phổ biến mà đa số lập trình viên đều biết:

class User extends Model
{
    /**
     * Thiết lập tên bảng trong cơ sở dữ liệu của model này
     * @var string
     */
    protected $table = 'users';

    /**
     * Thiết lập các trường có thể được fill khi bạn dùng Mass Assignment
     * @var array
     */
    protected $fillable = [
        'first_name',
        'last_name',
        'uuid',
        'status',
        'gender',
    ];

    /**
     * Ngược lại với $fillable, đây là các trường không thể được fill khi bạn dùng Mass Assignment.
     * Chú ý: Eloquent không cho phép bạn đồng thời định nghĩa cả $fillable và $guarded cho model của mình.
     * @var array
     */
    protected $guarded = [
        'id',
    ];

    /**
     * Định nghĩa các trường được tự động chuyển sang Carbon object - một class xử lí thời gian mà Laravel đang sử dụng
     * @var array
     */
    protected $dates = [
        'published_at',
    ];

    /**
     * Định nghĩa các trường sẽ được thêm vào trực tiếp trong dữ liệu trả về của model thông qua accessors
     * @var array
     */
    protected $appends = [
        'full_name',
    ];

    /**
     * Accessor trả về thông tin từ model khi người dùng gọi tới thuộc tính full_name
     * @return string
     */
    public function getFullNameAttribute()
    {
        return $this->first_name . ' ' . $this->last_name;
    }
}

Nhưng thực ra thì Eloquent hỗ trợ nhiều hơn thế. 

/**
* Định nghĩa khóa chính của bảng trong cơ sở dữ liệu
* @var string
*/
protected $primaryKey = 'uuid';

/**
* Đây là các trường lưu lại thông tin thời gian cập nhật dữ liệu của model.
* Bạn có thể cập nhật lại chúng cho phù hợp với cơ sở dữ liệu bạn đang có sẵn.
*/
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';

/**
* Chỉ định cho model biết có cần thiết lưu thông tin thời gian cập nhật model hay không.
* @var bool
*/
public $timestamps = false;

...

Ở đây mình chỉ nêu một số thuộc tính chúng ta hay sử dụng khi làm việc với model. Bạn có thể tham khảo liên kết sau để biết thêm nhiều thuộc tính khác mà Eloquent hỗ trợ hơn https://github.com/laravel/framework/.../Model.php.

 

Accessors và Mutators

Trong phần trên mình có nhắc tới Accessor. Vậy thì Accessor là gì?

Trong nhiều trường hợp, chúng ta cần truy cập vào một số thuộc tính của model khi mà chúng không thực sự tồn tại trong cơ sở dữ liệu. Ở ví dụ phía trên, chúng ta cần lấy thông tin full_name của User để hiển thị cho người dùng. Thay vì phải làm một cái gì đó tương tự như thế này:

{{ $user->first_name . ' ' . $user->last_name }}

Thì chúng ta sẽ khai báo phương thức getFullNameAttribute() trong Model như ví dụ phía trên, sau đó ở phía người dùng, chúng ta chỉ cần gọi nó ra như sau:

{{ $user->full_name }}

Để khai báo một accessor, bạn tạo ra một phương thức getFooBarAttribute() trong model của mình, với FooBar đặt theo chuẩn StudlyCase, còn thuộc tính bạn truy vấn ra sẽ dưới dạng snake_case ($user->foo_bar).

Giờ code nhìn sạch sẽ hơn rất nhiều rồi phải không nào ^^

Mutators thì ngược lại với Accessors, chúng được dùng trong quá trình cập nhật thay vì truy xuất dữ liệu như Accessors.

Bạn có thể truy cập liên kết sau để tìm hiểu nhiều hơn về Accessors và Mutatorshttps://laravel.com/docs/7.x/eloquent-mutators#accessors-and-mutators.

 

Phương thức whereX

Có một cách biến đoạn code sau:

$users = User::where('approved', 1)->get();

trở nên dễ hiểu dễ đọc hơn:

$users = User::whereApproved(1)->get();

Đúng thế, bạn chỉ cần thay đổi tên của bất cứ trường nào trong model (foo_bar) và nối nó với tiền tố "where" dưới dạng StudlyCase (FooBar), Eloquent sẽ tự xử lí và khiến đoạn code chạy "chuẩn không cần chỉnh".

Mặt khác, hãy chú ý tới một số phương thức đã được định nghĩa sẵn của Eloquent:

User::whereDate('created_at', date('Y-m-d'));

User::whereDay('created_at', date('d'));
User::whereMonth('created_at', date('m'));
User::whereYear('created_at', date('Y'));

Post::whereNull('category_id')->get();
Post::whereNotNull('category_id')->get();

Ah ha, sạch sẽ rõ ràng dễ hiểu hơn rất nhiều rồi.

Thực ra thì có khá nhiều người ghét kiểu viết như thế này (trừ những hàm mặc định của Eloquent), nhưng Eloquent đã hỗ trợ và bạn muốn xài thì cứ xài thôi. Trên thực tế mình lại thích viết rõ ràng các tên trường ra thay vì gọi tên hàm, bởi mình thấy nó làm cho code khó tái sử dụng hơn.

 

Model có quan hệ belongsTo chứa giá trị mặc định

Hãy tưởng tượng bạn có các bài Post được đăng bởi một Author. Bạn cần xuất tên của Author ra ngoài view.

{{ $post->author->name }}

Nhưng điều gì sẽ xảy ra nếu Author đã bị xóa, hoặc nó chưa được lưu xuống vì một lí do nào đó? Bạn sẽ gặp một lỗi Exception, đại loại là "try to get property of non-object".

Thực ra bạn có thể tránh điều đó bằng cách sau:

{{ $post->author->name ?? '' }}

Nhưng bạn sẽ phải trả giá bằng cách kiểm tra giá trị như trên ở tất cả những nơi cần chúng. Khá phiền phức đúng không?

Có một cách hay hơn để làm điều này. Chúng ta sẽ thêm đoạn code như sau vào Eloquent model:

public function author()
{
    return $this->belongsTo(Author::class)->withDefault();
}

Đoạn code này sẽ trả về một lớp Author rỗng nếu không có Author nào đi kèm với bài Post. Hơn nữa chúng ta hoàn toàn có thể thiết lập các giá trị mặc định cho Author:

public function author()
{
    return $this->belongsTo(Author::class)->withDefault([
        'name' => 'Guest',
    ]);
}

 

Thiết lập một vài Global Scope

Một ngày đẹp trời, bạn muốn các Category được sắp xếp theo "name" bất cứ khi nào truy vấn dạng danh sách. Ủa không lẽ giờ ngồi tìm rồi sửa lại hết hay sao ta?

Có một cách để thực hiện điều này tốt hơn, ít "cơ bắp" hơn - chỉ định một Global Scope. Chúng ta cùng quay trở lại phương thức boot() đã đề cập trước đó:

use Illuminate\Database\Eloquent\Builder;

protected static function boot()
{
    parent::boot();

    static::addGlobalScope('orderByName', function (Builder $builder) {
        $builder->orderBy('name', 'asc');
    });
}

Bạn nên tham khảo liên kết sau đây để tìm hiểu rõ hơn về phần Global Scope này https://laravel.com/docs/7.x/eloquent#global-scopes.

 

Chỉ định các Raw Query

Trong một số trường hợp, khi mà các phương thức xây dựng sẵn của Eloquent không đủ để chúng ta thực hiện truy vấn, chúng ta hoàn toàn có thể thêm vào các raw query.

$orders = Order::whereRaw('price > IF(state = "Texas", ?, 100)', [200])->get();

$products = Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get();

$users = User::orderByRaw('(updated_at - created_at) desc')->get();

 

Replicate - tạo một bản sao của model

Đây là cách ngắn gọn và đơn giản nhất để tạo ra một bản sao cho model:

$post = Post::find($id);

$newPost = $post->replicate();
$newPost->save();

 

Chunk - xử lí dữ liệu lớn

Khi xử lí hàng ngàn kết quả từ Eloquent, sử dụng chunk sẽ giúp tiết kiệm tối đa bộ nhớ hệ thống. Thực ra phương thức này thuộc về xử lí Collection, chứ không hẳn là ở Model

Thay vì viết như thế này:

$users = User::all();

foreach ($users => $user) {
    // ...
}

Chúng ta cần chuyển sang dạng này:

User::chunk(50, function ($users) {
    foreach ($users => $user) {
        // ...
    }
});

 

Tạo thêm các cấu trúc liên quan trong lúc khởi tạo một model

Phần phía trên đã đề cập, và hầu như ai trong chúng ta cũng biết câu lệnh này:

$ php artisan make:model Company

Thực ra chúng ta còn có thêm một số tùy chọn khá hữu ích liên quan tới Model:

$ php artisan make:model Company -m -c -r
  • -m: tạo kèm một migration tương ứng
  • -c: tạo kèm một controller.
  • -r: chỉ định controller được tạo ra là resource.

 

Kết quả trả về của hàm update()

Có bao giờ bạn tự hỏi những đoạn code tương tự như thế này trả về giá trị gì chưa?

$result = Product::whereNull('category_id')->update(['category_id' => 5]);

Câu lệnh này đã thực hiện việc cập nhật category_id cho toàn bộ các Product thỏa điều kiện, nhưng giá trị của $result ở đây là gì?

Câu trả lời chính là: số lượng các mục bị ảnh hưởng. Điều này có nghĩa là nếu bạn muốn kiểm tra xem có bao nhiêu mục đã được cập nhật, thì đây là chính xác những gì bạn cần, không cần gọi thêm thứ gì khác.

 

Truy vấn điều kiện nâng cao

Nếu bạn có một câu SQL đại loại như thế này:

... WHERE (gender = 'Male' and age >= 20) OR (gender = 'Female' and age >= 18)

Chuyển đoạn SQL này sang Eloquent như thế nào đây? Có lẽ nhiều người từng làm như thế này:

$query->whereRaw('(gender = ? and age >= ?) OR (gender = ? and age >= ?)', ['Male', 20, 'Female', 18]);

Viết như vầy thì "cơ bắp" quá các bạn, cũng khó bảo trì sau này nữa. Trừ trường hợp bất khả kháng, nếu không thì chúng ta nên cố gắng chuyển câu truy vấn sang Eloquent hết sức có thể.

Chúng ta có thể gom nhóm các điều kiện đi kèm với nhau trong dấu ngoặc bằng một hàm Closure như sau:

$query
    ->where(function ($q) {
        $q->where('gender', 'Male')->where('age', '>=', 20);
    })
    ->orWhere(function ($q) {
        $q->where('gender', 'Female')->where('age', '>=', 18);
    });

 

Phương thức orWhere với nhiều tham số

Đôi khi chúng ta cần truy vấn dữ liệu với nhiều điều kiện OR. Đây là cách thông thường mà mọi người hay sử dụng:

$query
    ->where('category_id', $categoryId)
    ->orWhere('name', $name)
    ->orWhere('description', $description)
    ->get();

Ổn và không có vấn đề gì cả. Nhưng chúng ta có thể rút gọn nó như sau:

$query
    ->where('category_id', $categoryId)
    ->orWhere(['name' => $name, 'description' => $description])
    ->get();

 

Trên đây là những kinh nghiệm và mẹo nhỏ mà mình tìm hiểu được khi làm việc với Laravel. Nếu bạn biết một vài mẹo nào đó và muốn chia sẻ, hãy để lại bình luận bên dưới nhé. 

Cám ơn các bạn đã theo dõi. Hẹn gặp lại trong các bài viết tiếp theo.

Comments

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é ^_^
Dạo gần đây đi đâu cũng nghe nói về microservices, người người nhà nhà rục rịch chuyển dịch hệ thống sang microservices. Trước khi đưa ra sự so sánh, mình sẽ khái quát một chút về Monolith Application và MicroServices một chút cho các bạn chưa biết nắm rõ hơn nhé.
Lúc trước mình hay sử dụng cách này trên laptop phụ của mình, giờ mua license luôn rồi. Hôm nay mình xin chia sẻ cho bạn nào cần nhé.
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é.
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é.

Mục lục

Related posts

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
Dạo gần đây đi đâu cũng nghe nói về microservices, người người nhà nhà rục rịch chuyển dịch hệ thống sang microservices. Trước khi đưa ra sự so sánh, mình sẽ khái quát một chút về Monolith Application và MicroServices một chút cho các bạn chưa biết nắm rõ hơn nhé.
Cách bỏ qua câu lệnh --set-upstream quen thuộc cho các con lười
Mình sẽ giới thiệu 2 cách để xóa một property trong Javascript Object. Một cách sử dụng mutable - toán tử delete, một cách còn lại là immutable - tính năng Object Restructuring.

Tin mới nhất

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Trong phần này, chúng ta sẽ tìm hiểu một số khái niệm cơ bản nhất về AWS là gì và một số lợi ích khi sử dụng AWS.
Trở thành một software developer hiệu suất cao không phải là điều dễ dàng. Điều này đòi hỏi bạn phải có kỹ năng và kiến thức về lập trình, cũng như cách tiếp cận và giải quyết các vấn đề phức tạp. Tuy nhiên, nếu bạn có chút kiên nhẫn và sự nỗ lực, bạn hoàn toàn có thể trở thành một developer tài năng và thành công.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Thông tin được định nghĩa dưới dạng dữ liệu, kiến thức về thông tin, và trí tuệ về tri thức.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.