Tìm kiếm trang web

Typescript: Lấy thông tin kiểu phần tử từ kiểu mảng


Giả sử tôi có một mảng kiểu T[], có thể trích xuất kiểu T trong một alias/interface khác không? Ví dụ, mã (giả) lý tưởng của tôi sẽ như sau:

// for illustration only...

type ArrayElement<T[]> = T;

// then, ArrayElement<string[]> === string

Nếu không, có những lý do từ lý thuyết loại tổng quát nào để không cho phép một toán tử như vậy không? Nếu vẫn không, tôi có thể gợi ý rằng nên thêm nó.

Câu trả lời #1

Cập nhật: dựa trên câu trả lời của @jerico bên dưới

Tên kiểu thay thế sau sẽ trả về kiểu của các phần tử trong mảng hoặc bộ giá trị:

type ArrayElement<ArrayType extends readonly unknown[]> = 
  ArrayType extends readonly (infer ElementType)[] ? ElementType : never;

Vậy những ví dụ này sẽ hoạt động:

type A = ArrayElement<string[]>; // string
type B = ArrayElement<readonly string[]>; // string
type C = ArrayElement<[string, number]>; // string | number
type D = ArrayElement<["foo", "bar"]>; // "foo" | "bar"
type E = ArrayElement<(P | (Q | R))[]>; // P | Q | R

type Error1 = ArrayElement<{ name: string }>; 
//                         ^^^^^^^^^^^^^^^^
// Error: Type '{ name: string; }' does not satisfy the constraint 'readonly unknown[]'.

Giải thích

Bộ bảo vệ kiểu (phần trong dấu ngoặc nhọn) ArrayType extends readonly unknown[] nói rằng chúng ta mong đợi tham số kiểu ArrayType ít nhất là một mảng chỉ đọc (nó cũng chấp nhận mảng có thể thay đổi) để chúng ta có thể xem kiểu phần tử của nó.

Điều này ngăn việc truyền một giá trị không phải mảng, như trong ví dụ cuối cùng, điều này ngăn ArrayElement bao giờ trả về never.

Lưu ý rằng readonly unknown[] là cú pháp được thêm vào trong TypeScript 3.4; đối với các phiên bản trước đó, hãy sử dụng ReadonlyArray<unknown>.

Ở phía bên phải, biểu thức điều kiện yêu cầu trình biên dịch điền giá trị của ElementType vào mẫu readonly ElementType[] và trả về ElementType nếu có thể, hoặc never nếu không thể.

Vì bảo vệ kiểu ở đầu có nghĩa là chúng ta sẽ chỉ nhận được một giá trị phù hợp với mẫu này, nên điều đó được đảm bảo luôn khớp và không bao giờ trả về never.

Câu trả lời trước

type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType[number];

Câu trả lời #2

Kể từ phiên bản 2.1, TypeScript hỗ trợ toán tử [ ] cho các kiểu. Tên chính thức là kiểu truy cập chỉ mục, còn được gọi là kiểu tra cứu, và nó hoạt động như sau:

type A = {a: string, b: number} [];

type AElement = A[0];

let e: AElement = {x: 0}; //error TS2322: Type '{ x: number; }' is not 
                       //assignable to type '{ a: string; b: number; }'

Câu trả lời #3

Một lựa chọn khác:

type ArrayElement<A> = A extends readonly (infer T)[] ? T : never

Câu trả lời #4

Điều này có thể đạt được khá dễ dàng bằng cách viết kiểu chỉ mục trong dấu ngoặc:

type ArrayElementType = ArrayType[number];

Cập nhật

Như một bình luận bên dưới gợi ý, để tạo một kiểu phần tử mảng chung:

type ArrayElementType<ArrayType extends  Array<T>, T = any> = ArrayType[number];

P.S. number không phải là một giá trị mà là một kiểu.

Bài viết liên quan