[英]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.