Tìm kiếm trang web

typescript - Không cho phép gọi với any


Xem xét các nạp chồng hàm sau:

function f(key: undefined);
function f(key: string | undefined, value: object | undefined);

Tôi muốn thực hiện các cuộc gọi hợp lệ với một đối số rõ ràng là undefined f(undefined), nhưng yêu cầu hai đối số trong tất cả các trường hợp khác. Và các phép nạp chồng ở trên hoạt động tốt, cho đến khi tôi truyền một biến có kiểu any - dường như any có thể được ép kiểu thành undefined (vâng, điều này có vẻ hợp lý vì nó là any).

Làm thế nào để tôi có thể cấm cuộc gọi với một đối số any duy nhất?

Mã demo đầy đủ:

function f(key: undefined);
function f(key: string | undefined, value: object | undefined);

function f(key: string | undefined, value?: object | undefined) {
    console.log(key, value);
}

// No errors - RIGHT
f(undefined);
f("", {});
f("", undefined);
f(undefined, undefined);
f(undefined, {});

// Errors - RIGHT
f("");

// No errors - WRONG
declare var x: any;
f(x);

Câu trả lời #1

TypeScript thực sự không muốn cấm any khỏi việc khớp với một kiểu, vì đó chính là mục đích của any. Bạn có thể muốn xem lại bất kỳ mã nào dựa vào việc từ chối any, vì vậy hãy cẩn thận.


Điều đã nói, bạn có thể sử dụng các loại điều kiện để xây dựng một bộ phát hiện cho any mà sau đó có thể được sử dụng để không cho phép một biến any.

Đây là máy dò:

type IfAny<T, Y, N> = 0 extends (1 & T) ? Y : N; 

Ràng buộc kiểu 0 extends 1 không được thỏa mãn (0 không thể gán cho 1), vì vậy 0 extends (1 & T) cũng nên không thể thỏa mãn, vì (1 & T) thậm chí nên hẹp hơn 1. Tuy nhiên, khi T là any, nó biến 0 extends (1 & any) thành 0 extends any, điều này được thỏa mãn. Điều đó là bởi vì any có ý định không an toàn và đóng vai trò như cả kiểu cha và kiểu con của hầu hết mọi kiểu khác. Do đó, IfAny<T, Y, N> kiểm tra xem T có phải là any không. Nếu đúng, nó trả về Y. Nếu không, nó trả về N. Hãy xem nó hoạt động:

type IsAny<T> = IfAny<T, true, false>
const yes: IsAny<any> = true;
const no: IsAny<string> = false;

Hãy nhớ rằng tôi đã nói any khớp với hầu hết mọi loại khác. Loại duy nhất không khớp với any là never:

declare const any: any;
const never: never = any; // error, any is not assignable to never

Chúng ta cũng cần sự thật đó, để từ chối bất kỳ tham số nào. Hãy thay đổi chữ ký đầu tiên của f() từ

function f(key: undefined): void;

đến

function f<K>(key: K & IfAny<K, never, undefined>): void;

Chúng tôi đã biến key thành một kiểu tổng quát K có giao nhau với IfAny<K, never, undefined>. Nếu K không phải là any, thì ràng buộc đó chỉ là undefined, vì vậy K chỉ có thể là undefined như mong muốn. Nếu K là any, thì ràng buộc đó trở thành never, và vì any không khớp với never, nó sẽ không thỏa mãn ràng buộc.

Khi chúng ta sử dụng chữ ký ở trên, bạn sẽ thấy hành vi sau:

f(undefined); // still works
f(""); // still error

declare var x: any;
f(x); // now error, any is not assignable to never

đó là những gì bạn muốn.

Liên kết Playground đến mã

Bài viết liên quan