Tìm kiếm trang web

javascript - Làm thế nào để Typescript suy ra một kiểu hợp nhất


Tôi đang cố gắng tạo một chữ ký hàm tương đối đơn giản như sau:

function<U>(...args:U[]):U {/* body */}

Tôi muốn TypeScript kết hợp các kiểu của các đối số được truyền vào thành một union thay vì chỉ đơn giản suy luận U như kiểu của đối số đầu tiên. Làm thế nào tôi có thể làm điều này?

Câu trả lời #1

Vấn đề bạn đang gặp phải là mã sau đây tạo ra lỗi biên dịch:

function f<U>(...args: U[]): U { 
  return args[Math.floor(Math.random() * args.length)] 
}

const a = f("string", 123, true); // error!
//                    ~~~ <-- error! 123 is not a string
// U inferred as string
// const a: string

Các thủ thuật của trình biên dịch ngăn không cho suy diễn một kiểu hợp tại đây vì thường mọi người muốn lỗi đó xảy ra. Xem Tại sao đối số kiểu không được suy diễn thành kiểu hợp? để biết thêm thông tin.

Hiện đang có một yêu cầu tính năng mở tại microsoft/TypeScript#44312 yêu cầu một cách nào đó để thông báo cho trình biên dịch rằng bạn muốn một hợp nhất thay vì lỗi. Hiện tại điều này không khả thi, vì vậy nếu bạn muốn hành vi tương tự, bạn cần sử dụng các cách giải quyết tạm thời.

Một giải pháp thường gặp là thay đổi hàm sao cho nó tổng quát không phải theo kiểu U của các phần tử của args, mà theo kiểu mảng T của args tự nó. Từ đó, bạn có thể truy cập vào kiểu đó bằng number để lấy kiểu phần tử. Nghĩa là, nếu T là một kiểu giống mảng, thì T[number] là kiểu phần tử (vì đó là kiểu bạn nhận được khi truy cập vào mảng với một number):

function f<T extends any[]>(...args: T): T[number] { 
  return args[Math.floor(Math.random() * args.length)] 
}

const a = f("string", 123, true);
// T inferred as [string, number, boolean]
// const a: string | number | boolean

Bây giờ không còn lỗi nào, và kiểu của a là hợp loại mà bạn muốn.

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