繁体   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