簡體   English   中英

在 typescript 中設置接口屬性的動態或條件值

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM