Nhảy tới nội dung

Type annotation của object

Trong TypeScript, type annotation của object được viết giống như JavaScript object literal, với cặp key và type của value cho từng property.

ts
let box: { width: number; height: number };
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Type annotation
box = { width: 1080, height: 720 };
ts
let box: { width: number; height: number };
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Type annotation
box = { width: 1080, height: 720 };

Khi có type annotation cho object, compiler sẽ cảnh báo nếu có lỗi về type.

ts
let box: { width: number; height: number };
// Nhầm gán string cho property
box = { width: "1080", height: 720 };
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
// Quên chỉ định height
box = { width: 1080 };
Property 'height' is missing in type '{ width: number; }' but required in type '{ width: number; height: number; }'.2741Property 'height' is missing in type '{ width: number; }' but required in type '{ width: number; height: number; }'.
ts
let box: { width: number; height: number };
// Nhầm gán string cho property
box = { width: "1080", height: 720 };
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
// Quên chỉ định height
box = { width: 1080 };
Property 'height' is missing in type '{ width: number; }' but required in type '{ width: number; height: number; }'.2741Property 'height' is missing in type '{ width: number; }' but required in type '{ width: number; height: number; }'.

Ký tự phân cách property có thể dùng dấu phẩy , như object literal, nhưng khuyến nghị dùng dấu chấm phẩy ;. Lý do là công cụ format code Prettier sẽ thay thế dấu phẩy bằng dấu chấm phẩy khi sửa type annotation của object.

Type annotation của object có thể xuống dòng. Khi xuống dòng, ký tự phân cách property có thể bỏ qua.

ts
let box: {
width: number;
height: number;
};
box = { width: 1080, height: 720 };
ts
let box: {
width: number;
height: number;
};
box = { width: 1080, height: 720 };

Thay vì type annotation inline, cũng có thể sử dụng type alias.

ts
// Type alias
type Box = { width: number; height: number };
let box: Box = { width: 1080, height: 720 };
// ^^^Type annotation
ts
// Type alias
type Box = { width: number; height: number };
let box: Box = { width: 1080, height: 720 };
// ^^^Type annotation

📄️ Type alias

TypeScript cho phép đặt tên cho kiểu. Kiểu có tên được gọi là type alias.

Type annotation của method

Type annotation của object cũng có thể viết type annotation cho method. Cách viết giống như method syntax của JavaScript với thêm type annotation cho argument và return value.

ts
let calculator: {
sum(x: number, y: number): number;
};
 
calculator = {
sum(x, y) {
return x + y;
},
};
ts
let calculator: {
sum(x: number, y: number): number;
};
 
calculator = {
sum(x, y) {
return x + y;
},
};

Type annotation của method cũng có thể viết theo function syntax.

ts
let calculator: {
sum: (x: number, y: number) => number;
};
ts
let calculator: {
sum: (x: number, y: number) => number;
};

Type annotation theo method syntax và function syntax về cơ bản có cùng ý nghĩa, nhưng khi bật compiler option strictFunctionTypes, cách viết function syntax sẽ làm việc kiểm tra argument của method nghiêm ngặt hơn, chuyển từ bivariant sang covariant. Chi tiết xem phần giải thích strictFunctionTypes.

📄️ strictFunctionTypes

Làm nghiêm ngặt check variance của parameter type

Type inference của object

Khi gán giá trị object trong khai báo biến, có thể bỏ qua type annotation. Type sẽ được tự động xác định từ giá trị. Đây gọi là type inference.

ts
let box = { width: 1080, height: 720 };
let box: { width: number; height: number; }
ts
let box = { width: 1080, height: 720 };
let box: { width: number; height: number; }

Type inference cũng hoạt động với object literal có method. Tuy nhiên, với method cần type annotation cho argument.

ts
let calculator = {
sum(x: number, y: number) {
return x + y;
},
};
calculator;
let calculator: { sum(x: number, y: number): number; }
ts
let calculator = {
sum(x: number, y: number) {
return x + y;
},
};
calculator;
let calculator: { sum(x: number, y: number): number; }

Record<Keys, Type>

Khi định nghĩa type của object key-value giống như associative array, có thể sử dụng utility type Record.

ts
let foo: Record<string, number>;
foo = { a: 1, b: 2 };
ts
let foo: Record<string, number>;
foo = { a: 1, b: 2 };

📄️ Record<Keys, Type>

Tạo object type từ key-value

object type

Type annotation của object cũng có thể sử dụng object type.

ts
let box: object;
box = { width: 1080, height: 720 };
ts
let box: object;
box = { width: 1080, height: 720 };

Không khuyến nghị sử dụng object type. Lý do thứ nhất là object type không có thông tin về property nào tồn tại. Do đó, tham chiếu box.width sẽ báo compile error.

ts
box.width;
Property 'width' does not exist on type 'object'.2339Property 'width' does not exist on type 'object'.
ts
box.width;
Property 'width' does not exist on type 'object'.2339Property 'width' does not exist on type 'object'.

Lý do thứ hai là có thể gán bất kỳ object nào. Có thể gán cả giá trị không mong đợi, khiến khó phát hiện vấn đề trong code.

ts
let box: object;
box = { wtdih: 1080, hihget: 720 }; // Lỗi chính tả
ts
let box: object;
box = { wtdih: 1080, hihget: 720 }; // Lỗi chính tả

Khi type annotation cho object, khuyến nghị không sử dụng object type mà nên định nghĩa type đến từng property.

Chia sẻ kiến thức

・Trong TypeScript, type annotation cho object là định nghĩa type cho từng property key
Ví dụ: { width: number; height: number}
・Khi gán object cho biến, type inference hoạt động
・Về mặt an toàn, nên tránh sử dụng object type

Từ 『Survival TypeScript』

Đăng nội dung này lên X

Thông tin liên quan

📄️ Sự khác biệt giữa object, Object, {}

Trong TypeScript, khi type annotation cho object, thông thường sẽ chỉ định cả type của property.

📄️ Interface

Interface là kiểu định nghĩa field và method mà class cần implement. Class implement interface để có thể kiểm tra xem có tuân theo tên method và kiểu tham số mà interface yêu cầu hay không.