我有一个带有泛型的类型,用于为函数组件定义一些额外的选项.

type FCWithOptions<T> = React.FC<{options?: T}>;

使用此类型,我定义了一些具有其自己的额外属性的组件

interface ComponentAOptions {
    option1: string;
    option2: number;
}

interface ComponentBOptions {
    prop1: boolean;
    prop2: Record<string, string>;
}

type ComponentAFC = FCWithOptions<ComponentAOptions>
type ComponentBFC = FCWithOptions<ComponentBOptions>

const ComponentA: ComponentAFC = ({options}) => {
    return <>Component A</>
}

const ComponentB: ComponentBFC = ({options}) => {
    return <>Component B</>
}

然后,我需要使用一组接口在容器组件中传递这些组件,该接口数组包含要传递的组件和该组件的自定义选项(通过属性).

interface ComponentValue<T>{
    component: FCWithOptions<T>;
    componentOptions?: T;
}
interface MainComponentProps<C>{
    components: ComponentValue<C>[]
}
function MainComponent<C>({}: MainComponentProps<C>) {
    return <>Main</>
}

我应该能做的事情是这样的:

<MainComponent components={[
    {component: ComponentA, componentOptions: {option1: "", option2: 2}},
    {component: ComponentB, componentOptions: { prop1: true, props: {} }}
]} />

但是它只对数组的第一个元素起作用,如果我添加其他元素,我会得到一些类型脚本断言

我怎么才能做到这一点呢? 谢谢

Here a playground

推荐答案

如果您有一个泛型类型F<T>,并且需要表示该类型的array个值,其中数组的每个元素都有不同的T选项,也就是说,如果您需要像[F<T0>, F<T1>, F<T2>, ⋯ , F<TN>]这样的tuple type,那么最好的方法可能是使用mapped tuple/array type,而不是只使用T0T1等类型的元组.也就是说,如果您的类型为type T = [T0, T1, T2, ⋯, TN],则可以对其应用type MapF<T> = {[I in keyof T]: F<T[I]>}以获得[F<T0>, F<T1>, F<T2>, ⋯ , F<TN>].

这意味着我们应该将您的代码更改为如下所示:

interface MainComponentProps<C extends any[]> {
    components: [...{ [I in keyof C]: ComponentValue<C[I]> }]
}

function MainComponent<C extends any[]>({ }: MainComponentProps<C>) {
    return <>Main</>
}

(我们用C代替T,用ComponentValue<⋯>代替F<⋯>.)唯一的区别是我用variadic tuple type([...⋯])包装了components的类型,以便向编译器暗示,我们希望它在调用MainComponent时推断出tuple,而不是任意长度的无序array.(在ms/TS#39094中描述了可变元组类型的这种用法,"类型[...T],其中T是类似数组的类型参数,可以方便地用于指示对元组类型的推断的偏好").

让我们来测试一下:

<MainComponent components={[
    { component: ComponentA, componentOptions: { option1: "", option2: 2 } },
    { component: ComponentB, componentOptions: { prop1: true, prop2: {} } }
]} />

// MainComponentProps<[{ option1: string; option2: number; }, { prop1: boolean; prop2: {}; }]>

看上go 不错.类型C被推断为[{ option1: string; option2: number; }, { prop1: boolean; prop2: {}; }],因此映射的类型[...{ [I in keyof C]: ComponentValue<C[I]> }]components属性的类型匹配.

Playground link to code

Typescript相关问答推荐

当类型断言函数返回假时,TypScript正在推断从不类型

在这种情况下,如何获得类型安全函数的返回值?

如何用不同的键值初始化角react 形式

如何使函数接受类型脚本中具有正确类型的链接修饰符数组

在动态对话框中使用STEP组件实现布线

泛型函数中输入参数类型的推断问题

对未到达受保护路由的路由环境做出react

是否可以针对联合类型验证类型属性名称?

如何将v-for中的迭代器编写为v-if中的字符串?

在另一个类型的函数中,编译器不会推断模板文字类型

迭代通过具有泛型值的映射类型记录

按函数名的类型安全类型脚本方法包装帮助器

如何为特定参数定义子路由?

当传递带有或不带有参数的函数作为组件props 时,我应该如何指定类型?

创建一个函数,该函数返回一个行为方式与传入函数相同的函数

为什么数字是`{[key:string]:UNKNOWN;}`的有效密钥?

Typescript 是否可以区分泛型参数 void?

为什么我无法在 TypeScript 中重新分配函数?

错误:仅允许在‘使用服务器’文件中导出异步函数

TypeScript 中的通用函数包装和类型推断