但目前我面临的问题是,要键入我的ImagesStack组件,我需要将一个类型传递给ImageStackProps,这是我的images Stack组件在其props.images中接收的内容。
这是容易的部分。您只需将组件设为泛型,然后将该泛型类型参数传递给props类型。
function MyComponent<T extends readonly string[]>(props: ImageStackProps<T>) {
return <></>
}
但您的解决方案的其余部分存在一些问题。
-
AllowedArrayIndexes
返回字符串键(
"0" | "1" | "2"
),而不是数字(
0 | 1 | 2
)。
-
AllowedArrayIndex
返回索引,比应该允许的少一个。3项数组具有索引
0|1|2
但是应该允许您显示3个图像。
我提出了一种不同的方法。
首先,我们需要获得
number
元组中的索引。
This issue
有一些巧妙的方法。但让我们继续这样做:
type AllowedCounts<T extends { length: number }> = Partial<T>["length"];
这看起来像是伏都教,但让我们走过来。
元组具有已知的长度。
[number,number,number]
有一个
length
属于
3
但是
Partial<T>
使所有成员都是可选的,因此:
Partial<[number, number, number]>
// yields
[number?, number?, number?]
这意味着元组可能缺少成员,因此长度会更小。以下所有类型都可分配给
[number?, number?, number?]
:
[] // length 0
[number] // length 1
[number, number] // length 2
[number, number, number] // length 3
因此:
Partial<[number, number, number]>['length'] // 0 | 1 | 2 | 3
你甚至可以排除
0
如果你愿意的话,因为显示一个没有图像的图像堆栈没有多大意义。
Exclude<Partial<[number, number, number]>['length'], 0> // 1 | 2 3
这同样适用于无边界数组类型,因为:
type A = string[]['length'] // number
type B = Partial<string[]>['length'] // number
尽管你
不能
排除
0
在这种情况下,由于typescript没有负类型:
Exclude<number, 0> // number, sadly.
现在使用它很简单:
export interface ImageStackProps<ImagesArray extends readonly string[]> {
images: ImagesArray;
imagesToShow: AllowedCounts<ImagesArray>;
}
type AllowedCounts<T extends { length: number }> = Partial<T>["length"];
// A component
function MyComponent<T extends readonly string[]>(props: ImageStackProps<T>) {
return <></>
}
// With known tuple length at compile time
const imagesTuple = ['a.jpg', 'b.jpg'] as const // 2 images, component can show
const jsxA = <MyComponent images={imagesTuple} imagesToShow={0} />
const jsxB = <MyComponent images={imagesTuple} imagesToShow={1} />
const jsxC = <MyComponent images={imagesTuple} imagesToShow={2} />
const jsxD = <MyComponent images={imagesTuple} imagesToShow={3} /> // error
const jsxE = <MyComponent images={imagesTuple} imagesToShow={50} /> // error
// With unknown array length at compile time
declare const imagesArr: string[] // from an api, for example.
const jsxX = <MyComponent images={imagesArr} imagesToShow={1} /> // fine
const jsxY = <MyComponent images={imagesArr} imagesToShow={123456} /> // fine
Playground