[英]Setting a dynamic or conditional value of an interface property in typescript
我正在尝试构建一个显示堆栈图像的反应组件,例如this ,为此,我尝试使用接口和类型来键入它,以强制以特定方式获取一些道具。 这是我之前的界面代码:
旧接口.ts
export interface ImageStackProps{
images: string[];
backgroundColor: string;
extraBannerBackgroundColor: string;
imageSize: ImageSize<string>;
imagesToShow: number;
direction?: StackDirection<"column" | "row" | "column-reverse" | "row-reverse">;
}
type StackDirection<T> = T | Array<T | null> | { [key: string]: T | null };
type ImageSize<T> = { width: T; height: T };
imagesToShow 属性决定将显示多少图像以及是否显示剩余横幅的额外图像。 虽然没有必要,但我试图根据 images 属性(它获取 base64 编码图像的数组)来约束 imagesToShow 属性,因此永远不允许大于数组最后一个索引的值。 因此,为此,我修改了我的界面,使其看起来像这样:
新界面.ts
export interface ImageStackProps<ImagesArray extends Array<string>> {
images: ImagesArray;
backgroundColor: string;
extraBannerBackgroundColor: string;
imageSize: ImageSize<string>;
imagesToShow: AllowedArrayIndexes<ImagesArray>;
direction?: StackDirection<"column" | "row" | "column-reverse" | "row-reverse">;
}
type StackDirection<T> = T | Array<T | null> | { [key: string]: T | null };
type ImageSize<T> = { width: T; height: T };
type ArrayKeys<T extends Array<string>> = keyof T;
type AllowedArrayIndexes<T extends Array<string>> = Exclude<ArrayKeys<T>, ArrayKeys<string[]>>;
但此时我面临的问题是,要键入我的ImagesStack
组件,我需要将一个类型传递给ImageStackProps
,这是我的ImagesStack
组件在其props.images
中接收的内容。
我理解并知道没有必要有这个约束,没有它它工作得很好,但我想看看我是否能做到这一点。 我很确定我没有正确处理这个问题。 有没有更好的方法来执行此操作? 或者更好的是,这甚至可以以某种方式实现吗? 我应该如何修改我的界面?
但此时我面临的问题是,要键入我的 ImagesStack 组件,我需要将一个类型传递给 ImageStackProps,这是我的 ImagesStack 组件在其 props.images 中接收的内容。
这是简单的部分。 您只需使组件通用并将该通用类型参数传递给 props 类型。
function MyComponent<T extends readonly string[]>(props: ImageStackProps<T>) {
return <></>
}
但是你的解决方案的rest有一些问题。
AllowedArrayIndexes
返回字符串键 ( "0" | "1" | "2"
),而不是数字 ( 0 | 1 | 2
)。AllowedArrayIndexes
返回索引,它比应该允许的少一。 一个 3 项数组的索引0 | 1 | 2
0 | 1 | 2
0 | 1 | 2
但你应该被允许显示 3 图像。我提出了一种不同的方法。
首先,我们需要从元组中获取number
索引的方法。 这个问题有一些巧妙的方法。 但是让我们用这个 go :
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.