Type assertion "as"
TypeScript có tính năng ghi đè type inference. Tính năng này được gọi là type assertion.
TypeScript compiler suy luận kiểu từ code. Type inference đó rất thông minh, nhưng đôi khi lập trình viên biết kiểu chính xác hơn compiler. Trong trường hợp đó, có thể sử dụng type assertion để cho compiler biết kiểu. Type assertion giống như nói với compiler "Tin tôi đi! Tôi biết rõ về kiểu hơn".
Cách viết type assertion
Có 2 cách viết type assertion. Một là cú pháp as.
tsconstvalue : string | number = "this is a string";conststrLength : number = (value as string).length ;
tsconstvalue : string | number = "this is a string";conststrLength : number = (value as string).length ;
Cách còn lại là cú pháp angle-bracket (angle-bracket syntax).
tsconstvalue : string | number = "this is a string";conststrLength : number = (<string>value ).length ;
tsconstvalue : string | number = "this is a string";conststrLength : number = (<string>value ).length ;
Tùy sở thích dùng cách nào, nhưng cú pháp angle-bracket đôi khi không phân biệt được với JSX, nên cú pháp as được dùng nhiều hơn.
Type assertion gây lỗi compile
Không phải type assertion có thể ghi đè thông tin kiểu không giới hạn. Ví dụ, type assertion chuyển kiểu number thành kiểu string sẽ gây lỗi compile.
tsconstnum = 123;constConversion of type 'number' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.2352Conversion of type 'number' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.str : string =num as string;
tsconstnum = 123;constConversion of type 'number' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.2352Conversion of type 'number' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.str : string =num as string;
Lỗi này có nghĩa "Việc chuyển kiểu number thành kiểu string là sai. Vì hai kiểu có quá ít phần chung".
Như vậy, dù type assertion có thể ghi đè type inference của compiler, nhưng không thể chuyển đổi kiểu vô lý.
Nếu vẫn tin type assertion mình viết là đúng, có thể tránh lỗi trên bằng cách đi qua kiểu unknown.
tsconstnum = 123;conststr : string =num as unknown as string; // OK
tsconstnum = 123;conststr : string =num as unknown as string; // OK
Sự khác biệt giữa type assertion và cast
Type assertion giống với cast của các ngôn ngữ khác. Cast là việc chuyển đổi kiểu của một giá trị sang kiểu khác tại runtime. Type assertion không ảnh hưởng đến runtime. Nó không chuyển đổi kiểu giá trị. Chỉ đơn thuần là truyền kiểu cho compiler tại compile time. Compiler dùng thông tin đó để kiểm tra code. Type assertion không phải cast, nên trong TypeScript không gọi type assertion là cast. Để chuyển đổi kiểu tại runtime, cần viết logic cho việc đó.
Với sức mạnh lớn đi kèm trách nhiệm lớn
Type assertion có sức mạnh ghi đè type inference của compiler. Do đó, lập trình viên cần cẩn thận để type assertion không gây ra bug. Về kiểu, dựa vào type inference của compiler sẽ an toàn hơn, nên type assertion chỉ nên dùng khi không còn cách nào khác.
Khi cần sử dụng type assertion, trước hết hãy xem xét có thể giải quyết bằng type guard hoặc user-defined type guard không.
📄️ Phân tích control flow và thu hẹp kiểu bằng type guard
TypeScript có thể thu hẹp kiểu của biến theo luồng xử lý thông qua control flow và type guard.
📄️ Type guard function
Compiler của TypeScript phân tích type của biến tại mỗi vị trí trong control flow như if hay switch, tính năng này được gọi là control flow analysis (phân tích luồng điều khiển).
📄️ Assertion function
Type predicate chủ yếu được sử dụng như user-defined type guard function, nhưng cũng có một phương pháp khác là assertion function.
Sự khác biệt giữa type assertion và type annotation
Type assertion và type annotation có tên giống nhau nên thường bị nhầm lẫn. Trong sách này, type annotation được gọi là "type annotation". Đây là 2 tính năng khác nhau của TypeScript.
Type annotation là việc cho compiler biết "Biến này chỉ có thể gán kiểu này". Compiler dùng type annotation làm gợi ý để kiểm tra xem giá trị có thể gán vào kiểu đó không, và báo cáo ngay khi phát hiện không thể gán.
tsletvalue : number;
tsletvalue : number;
Mặt khác, type assertion là việc cho compiler biết "Bạn nghĩ kiểu này, nhưng thực tế là kiểu kia" để truyền đạt sự không chính xác của type inference.
📄️ Type annotation trong khai báo biến
Trong TypeScript, khi khai báo biến, bạn có thể chỉ định giá trị nào có thể được gán cho biến đó. Chỉ định này được gọi là type annotation (chú thích kiểu). Type annotation trong khai báo biến được viết bằng cách đặt kiểu ở bên phải tên biến như sau: