strictFunctionTypes
strictFunctionTypes là compiler option làm nghiêm ngặt check variance của parameter type.
- Mặc định:
truenếu strict được bật, ngược lại làfalse - Phiên bản thêm vào: 2.6
- TypeScript khuyến nghị nên bật
Bivariance của parameter là không an toàn
Function trong TypeScript có tính chất bivariance của parameter (parameter bivariance). Hãy xem từng bước để hiểu rõ:
Đầu tiên, xét phạm vi của 3 type sau:
numbernumber | nullnumber | null | undefined
number là type hẹp hơn number | null. Phạm vi của number | null gồm các giá trị number type như 1, 0.5 và null type. Phạm vi của number type chỉ gồm number type. number | null | undefined là type rộng nhất trong các type trên.
| Type | Độ rộng phạm vi | Ví dụ giá trị |
|---|---|---|
number | Hẹp | 1, 0.5... |
number | null | Rộng | 1, 0.5..., null |
number | null | undefined | Rộng hơn | 1, 0.5..., null, undefined |
Tiếp theo, xét biến func sau. Type của biến này là function nhận parameter number | null:
tsletfunc : (n : number | null) => any;
tsletfunc : (n : number | null) => any;
Giá trị type nào có thể gán vào biến func này? Đương nhiên, function cùng type với type annotation có thể gán được:
tsfunc = (n : number | null) => {}; // OK
tsfunc = (n : number | null) => {}; // OK
Function nhận number | null | undefined rộng hơn parameter number | null thì có gán được không? Điều này cũng OK:
tsfunc = (n : number | null | undefined) => {}; // OK
tsfunc = (n : number | null | undefined) => {}; // OK
Đặc tính có thể mở rộng phạm vi parameter type như vậy được gọi là contravariance của parameter (parameter contravariance).
Function nhận number hẹp hơn parameter number | null thì có gán được không? Trong TypeScript điều này cũng có thể gán được:
tsfunc = (n : number) => {}; // OK
tsfunc = (n : number) => {}; // OK
Đặc tính có thể thu hẹp phạm vi parameter type như vậy được gọi là covariance của parameter (parameter covariance).
Function type trong TypeScript có cả hai đặc tính contravariance và covariance của parameter. Hai đặc tính này gộp lại được gọi là bivariance của parameter.
Bivariance của parameter có khía cạnh nguy hiểm. Vì đang gán function chỉ nhận number vào function func có thể nhận null. Nếu truyền null vào func, sẽ xảy ra lỗi runtime:
ts// Function type có thể nhận nullletfunc : (n : number | null) => any;// Gán function chỉ nhận numberfunc = (n : number) =>n .toString ();// func có thể truyền null → Mâu thuẫn gây lỗi runtimefunc (null);
ts// Function type có thể nhận nullletfunc : (n : number | null) => any;// Gán function chỉ nhận numberfunc = (n : number) =>n .toString ();// func có thể truyền null → Mâu thuẫn gây lỗi runtimefunc (null);
Để tránh lỗi runtime như vậy, parameter type chỉ nên cho phép contravariance. Và nếu là covariance thì nên báo compile error. Tuy nhiên, TypeScript cho phép parameter type là bivariance (tức covariance cũng OK) nên không an toàn.
strictFunctionTypes không cho phép covariance của parameter
Giải quyết vấn đề trên là compiler option strictFunctionTypes. Đặt thành true thì parameter sẽ trở thành contravariant. Nếu parameter là covariant thì TypeScript sẽ cảnh báo:
tsletfunc : (n : number | null) => any;// Invariantfunc = (n : number | null) => {}; // OK// Contravariantfunc = (n : number | null | undefined) => {}; // OK// CovariantType '(n: number) => void' is not assignable to type '(n: number | null) => any'. Types of parameters 'n' and 'n' are incompatible. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.2322Type '(n: number) => void' is not assignable to type '(n: number | null) => any'. Types of parameters 'n' and 'n' are incompatible. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.= ( func n : number) => {}; // NG
tsletfunc : (n : number | null) => any;// Invariantfunc = (n : number | null) => {}; // OK// Contravariantfunc = (n : number | null | undefined) => {}; // OK// CovariantType '(n: number) => void' is not assignable to type '(n: number | null) => any'. Types of parameters 'n' and 'n' are incompatible. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.2322Type '(n: number) => void' is not assignable to type '(n: number | null) => any'. Types of parameters 'n' and 'n' are incompatible. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.= ( func n : number) => {}; // NG
strictFunctionTypes giúp ngăn chặn lỗi runtime không mong muốn. Khuyến nghị nên set strictFunctionTypes thành true.
Method type không được check
Check của strictFunctionTypes chỉ áp dụng cho function type. Không áp dụng cho method type:
tsinterfaceObj {// Method typemethod (n : number | null): any;}constobj :Obj = {method : (n : number) => {}, // Không được check};
tsinterfaceObj {// Method typemethod (n : number | null): any;}constobj :Obj = {method : (n : number) => {}, // Không được check};
Ngay cả với method của interface, method được định nghĩa bằng function type sẽ được check bởi strictFunctionTypes:
tsinterfaceObj {// Function typemethod : (n : number | null) => any;}constobj :Obj = {Type '(n: number) => void' is not assignable to type '(n: number | null) => any'. Types of parameters 'n' and 'n' are incompatible. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.2322Type '(n: number) => void' is not assignable to type '(n: number | null) => any'. Types of parameters 'n' and 'n' are incompatible. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.: ( method n : number) => {}, // Check hoạt động};
tsinterfaceObj {// Function typemethod : (n : number | null) => any;}constobj :Obj = {Type '(n: number) => void' is not assignable to type '(n: number | null) => any'. Types of parameters 'n' and 'n' are incompatible. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.2322Type '(n: number) => void' is not assignable to type '(n: number | null) => any'. Types of parameters 'n' and 'n' are incompatible. Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.: ( method n : number) => {}, // Check hoạt động};
Chia sẻ kiến thức
⚙️strictFunctionTypes của TypeScript là compile option làm nghiêm ngặt check variance của parameter type
☹️Parameter của TypeScript là bivariant nên không an toàn
🔥Có thể xảy ra lỗi runtime
✅strictFunctionTypes biến thành contravariant
👍Option khuyến nghị nên bật
Từ 『Survival TypeScript』
Thông tin liên quan
📄️ strict
Bật hàng loạt các option thuộc nhóm strict