javascript - Làm thế nào để tôi định nghĩa một kiểu typescript với cấu trúc lặp lại?
Tôi có một loại trông giống như thế này:
type Location=`${number},${number};${number},${number};...`
Có kiểu Utility nào giống Repeat<T> có thể làm điều này cho tôi không? như thế này:
type Location=Repeat<`${number},${number};`>
Câu trả lời #1
CHỈ HOẠT ĐỘNG TRONG TS >=4,5
Có thể tạo loại độc lập.
Vui lòng xem ví dụ này:
type Coordinates = `${number},${number};`
type MAXIMUM_ALLOWED_BOUNDARY = 50
type Last<T extends string[]> = T extends [...infer _, infer Last] ? Last : never;
type ConcatPrevious<T extends any[]> = Last<T> extends string ? `${Last<T>}${Coordinates}` : never
type Mapped<
N extends number,
Result extends Array<unknown> = [Coordinates],
> =
(Result['length'] extends N
? Result
: Mapped<N, [...Result, ConcatPrevious<Result>]>
)
// type MyLocation =
// | `${number},${number};`
// | `${number},${number};${number},${number};`
// | `${number},${number};${number},${number};${number},${number};`
// | `${number},${number};${number},${number};${number},${number};${number},${number};`
// | `${number},${number};${number},${number};${number},${number};${number},${number};${number},${number};`
// | ... 44 more ...
// | `${number},${number};${number},${number};${number},${number};${number},${number};${number},${number};${number},${number}; ....
type MyLocation = Mapped<MAXIMUM_ALLOWED_BOUNDARY>[number]
const myLocation1: MyLocation = '45,56;67,68;' // ok
const myLocation2: MyLocation = '45,56;67,68;1,2;3,4;5,6;7,8;9,10;' // ok
const myLocation3: MyLocation = '45,56;67,68;1,2;3,4;5,6;7,8;9,10,' // expected error
Sân chơi
Các kiểu Mapped là một kiểu tiện ích đại diện cho một vòng lặp while. Nó lặp cho đến khi độ dài của Result đạt đến N. Nói cách khác, Mapped<10> - sẽ lặp 10 lần. Xem ví dụ này trong js thuần túy:
const mapped = (N: number, Result: any[] = []): string => {
if (N === Result.length) {
return Result.join('')
}
const x = Math.random();
const y = Math.random()
return mapped(N, [...Result, `${x},${y};`])
}
Rất khó để biểu diễn các liên hiệp trong js, đó là lý do tại sao tôi đã sử dụng join(''). Tôi hy vọng cách nó hoạt động là rõ ràng.
Nếu bạn muốn tăng MAXIMUM_ALLOWED_BOUNDARY lên 500, nó sẽ làm CPU của bạn nóng lên nên hãy cẩn thận.
Như bạn có thể đã nhận thấy, việc thể hiện mẫu đệ quy cho kiểu trong TypeScript là không thể nhưng có thể tạo ra một hợp nhất đủ lớn.
Xin vui lòng ghi nhớ rằng có một số nhược điểm của loại $ {number}. Bạn được phép sử dụng các số có số 0 đứng đầu như ở đây:
const x: `${number}` = '01'.
Liên kết hữu ích:
Ở đây bạn có thể tìm thấy một ví dụ về cách bạn có thể tạo một phạm vi các số bằng cách sử dụng mẫu này.
Ở đây bạn có thể tìm thấy một PR nơi tính năng này được giới thiệu
Ở đây và ở đây bạn có thể tìm thấy các bài viết của tôi liên quan đến mẫu này
Câu trả lời #2
Tôi không nghĩ có cách nào để định nghĩa một mẫu lặp vô hạn cho một kiểu mà bạn sử dụng khi khai báo biến.
Tuy nhiên, một loại bảo vệ trên một hàm có thể kiểm tra rằng một chuỗi khớp với một mẫu vô hạn, như sau (playground):
type MatchesPattern<Pattern extends string, Current extends string> = Current extends `` ? string : (Current extends `${Pattern}${infer Rest}` ? MatchesPattern<Pattern, Rest> : never);
type LocationPattern = `${number},${number};`;
declare function onlyAcceptsLocation<L extends string & IsLocation, IsLocation = MatchesPattern<LocationPattern, L>>(location: L): void;
onlyAcceptsLocation("12,34;56,78;"); // 👍 matches
onlyAcceptsLocation("12,34;56,78"); // ⚠️
onlyAcceptsLocation("12'34;56,78;"); // ⚠️
onlyAcceptsLocation("1,2,3;45,67;"); // ⚠️
