英文:
React + TS: How to use dot-notation components and generics at the same time?
问题
I have a component List
that has a sub-component Title
, declared using dot-notation.
我有一个名为 `List` 的组件,它具有使用点表示法声明的子组件 `Title`。
And then I use this component:
然后我使用这个组件:
At this point everything is fine, but if I need to add a generic type parameter to the component and its interface, it seems like there is no way to do this.
在这一点上一切都很好,但如果我需要向组件及其接口添加泛型类型参数,似乎无法实现这一点。
For example, I want the item name to be of a certain type that I can pass from the parent.
例如,我希望项目名称具有特定的类型,可以从父组件传递。
I know I can do it like this
我知道可以这样做
But in this case, I don't know how I can specify the type for List.Title
. Is there any way to combine these two techniques?
但在这种情况下,我不知道如何为 `List.Title` 指定类型。是否有一种方法可以将这两种技术结合起来?
英文:
I have a component List
that has a sub-component Title
, declared using dot-notation.
type Item = {
name: string;
value: number;
};
type ListProps = {
title: string;
data: Item[];
};
export const List: React.FC<ListProps> & {
Title: React.FC<{ title: string }>
} = ({ title, data }) => {
return (
<div>
<List.Title title={title}>
<ul>
{data.map((item) => (
<li>
{item.name}: {item.value}
</li>
))}
</ul>
</div>
);
};
List.Title = ({title}) => <div>{title}</div>
And then i use this component:
<List
title="Stats"
data={[
{ name: "strength", value: 30 },
{ name: "dexterity", value: 50 },
{ name: "intellect", value: 100 },
{ name: "vitality", value: 40 }
]}
/>
At this point everything is fine, but if i need to add generic type parameter to component and its interface it seems like there is no way to do this.
For example i want item name to be of certain type, that i can pass from parent.
<List<"strength" | "dexterity" | "intellect" | "vitality">
title="Stats"
data={[
{ name: "strength", value: 30 },
{ name: "dexterity", value: 50 },
{ name: "intellect", value: 100 },
{ name: "vitality", value: 40 }
]}
/>
I know i can do it like this
type Item<ItemName extends string = string> = {
name: ItemName;
value: number;
};
type ListProps<ItemName extends string = string> = {
title: string;
data: Item<ItemName>[];
};
export const List = <ItemName extends string = string,>({
title,
data
}: ListProps<ItemName>): JSX.Element => {
return (
<div>
<ul>
{data.map((item) => (
<li>
{item.name}: {item.value}
</li>
))}
</ul>
</div>
);
};
// This isn't working, because `List` has no property `Title`
// List.Title = ({ title }) => <div>{title}</div>;
But in this case i don't know how i can specify type for List.Title
. Is there any way to combine this two techniques?
答案1
得分: 1
> This isn't working, because List has no property Title
这不起作用,因为 List 没有 Title 属性。
That's not the error TypeScript is raising in the Codesandbox (or in the playground). The error is "Binding element 'title' implicitly has an 'any' type. (7031)" That's because you haven't given any type for the props of List.Title
. The Title
props used to get a type from the type you'd given List
, but since you've removed the explicit type annotation on List
, you need to specify the type of Title
's title
somewhere.
这不是 TypeScript 在 Codesandbox(或playground)中报错的原因。错误是“绑定元素 'title' 隐式具有 'any' 类型 (7031)”这是因为您没有为 List.Title
的 props 指定任何类型。Title
的 props 以前从您给定的 List
类型中获得类型,但由于您已经删除了 List
上的显式类型注释,您需要在某处指定 Title
的 title
的类型。
The simple change is to just specify it inline:
简单的更改是直接内联指定它:
List.Title = ({ title }: { title: string; }) => <div>{title}</div>;
// ^^^^^^^^^^^^^^^^^^^
或者,您可以像在您的第一个示例中那样为 List
指定一个显式类型。该类型是:
{
<ItemName extends string = string>({ title, data }: ListProps<ItemName>): JSX.Element;
Title({ title }: {
title: string;
}): JSX.Element;
}
所以:
export const List: {
<ItemName extends string = string>({ title, data }: ListProps<ItemName>): JSX.Element;
Title({ title }: {
title: string;
}): JSX.Element;
} = <ItemName extends string = string,>({/*...*/) => {
// ...
};
List.Title = ({ title }) => <div>{title}</div>;
英文:
> This isn't working, because List has no property Title
That's not the error TypeScript is raising in the Codesandbox (or in the playground). The error is "Binding element 'title' implicitly has an 'any' type. (7031)" That's because you haven't given any type for the props of List.Title
. The Title
props used to get a type from the type you'd given List
, but since you've removed the explicit type annotation on List
, you need to specify the type of Title
's title
somewhere.
The simple change is to just specify it inline:
List.Title = ({ title }: {title: string; }) => <div>{title}</div>;
// ^^^^^^^^^^^^^^^^^^^
Alternatively, you can do what you did in your first example and give List
an explicit type. The type is:
{
<ItemName extends string = string>({ title, data }: ListProps<ItemName>): JSX.Element;
Title({ title }: {
title: string;
}): JSX.Element;
}
so:
export const List: {
<ItemName extends string = string>({ title, data }: ListProps<ItemName>): JSX.Element;
Title({ title }: {
title: string;
}): JSX.Element;
} = <ItemName extends string = string,>({/*...*/}) => {
// ...
};
List.Title = ({ title }) => <div>{title}</div>;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论