我正在使用 TypeScript 构建一个 React Native 应用程序。
renderItem
抱怨解构项隐式具有 any
类型。我用谷歌搜索并找到了这个问题,并尝试结合React Native的index.d.ts
包的@types
中的类型来实现他们在这里教授的内容。
export interface Props {
emotions: Emotion[];
}
class EmotionsPicker extends PureComponent<Props> {
keyExtractor = (item, index) => index;
renderItem = ({ item }) => (
<ListItem title={item.name} checkmark={item.checked} />
);
render() {
return (
<FlatList<Emotion>
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
data={this.props.emotions}
/>
);
}
}
不幸的是,这不起作用。我怎样才能给项目指定类型
Emotion
?
我知道这是一个老问题,但谷歌搜索它的人可能仍然会欣赏它。
import { FlatList, ListRenderItem } from 'react-native'
/*
.
.
.
*/
renderItem: ListRenderItem<Emoticon> = ({ item }) => (
<ListItem title={item.name} checkmark={item.checked} />
);
我找到了一个解决方案(虽然我不知道它是否理想):
renderItem = ({ item }: { item: Emotion }) => (
<ListItem title={item.name} checkmark={item.chosen} />
);
这是因为在定义
renderItem
时,TypeScript 无法知道它应该作为 renderItem
的 FlatList
属性。
如果您跳过变量并直接将函数放入 prop 中,TypeScript 应该能够正确推断它:
export interface Props {
emotions: Emotion[];
}
class EmotionsPicker extends PureComponent<Props> {
render() {
return (
<FlatList<Emotion>
keyExtractor={(item, index) => index}
renderItem={({ item }) => <ListItem title={item.name} checkmark={item.checked} />}
data={this.props.emotions}
/>
);
}
}
我找到了一个对我来说非常有效的解决方案:
import { FlatList, ListRenderItemInfo } from 'react-native';
<FlatList
data={data}
renderItem={({ item }: ListRenderItemInfo<ItemType>) => (
<ItemComponent item={item} />
)}
keyExtractor={(item: ItemType) => item.id}
/>
如果不是内联函数,解构时从 React 导出的正确类型是
ListRenderItemInfo<ItemT>
:
export interface ListRenderItemInfo<ItemT> {
item: ItemT;
index: number;
separators: {
highlight: () => void;
unhighlight: () => void;
updateProps: (select: "leading" | "trailing", newProps: any) => void;
};
}
我觉得这里的答案只解决了如何在更好的情况下修复,在更坏的情况下绕过类型检查,但无法解释为什么它不起作用或者为什么应该按原样输入。
我想更清楚地说明为什么这对大多数人来说会失败,因为即使在官方 react-native wiki 上,它的记录也非常少。
组件
FlatList
方法不需要您常用来传递(即)标准反应元素构造函数(props) => JSX.Element
的渲染函数。
无论好坏,
FlatList
的renderItem
方法的输入方式如下:
type ListRenderItem<ItemT> = (info: ListRenderItemInfo<ItemT>) =>
React.ReactElement | null;
这是因为它不需要直接元素构造函数,就像您在大多数 React 模式中习惯的那样标准构造
renderItem
方法。
相反,它需要一个 具有特定类型的回调。这是为了优化目的的内部处理,但在输入时仍然相当笨重。
export interface ListRenderItemInfo<ItemT> {
item: ItemT;
index: number;
separators: {
highlight: () => void;
unhighlight: () => void;
updateProps: (select: 'leading' | 'trailing', newProps: any) => void;
};
}
所以这意味着我们应该将我们自己的内部
renderItem
视为回调,以及传递特定 <ItemT>
通用的特定项目道具
type Props = {
emotions: Emotion[]
}
// This is the standard React function component
const Item = (({ title, checked }): Emotion) => (
<ListItem title={title} checked={checked} />
)
// This is the callback for constructing the function component
const renderItem: ListRenderItem<Emotion> = ({ item }: ListRenderItemInfo<Emotion>) => (
<Item title={item.title} checked={item.checked} />
)
正如您所看到的,乍一看这可能相当令人困惑并且很容易混淆。在
ListRenderItem<T>
告诉打字稿中,我们希望创建一个 T
类型的函数(通用参数),然后构造 (returns) a Reat.ReactElement | null
。但由于 React 组件本身就是函数,我们仍然需要传递函数来创建一个。这就是混乱和类型错误的根源。
本质上是这样
ListRenderItem<T>
ListRenderItemInfo<T>
的特定 propType 和 prop item
(props: T) => JSX.Element
而不是传递道具并从中创建元素的标准方式。这也是为什么你(是)收到以下typescript错误:
Property 'property name' does not exist on ListRenderItem<any>
使用 TypeScript 使用它来避免类型错误
keyExtractor={(item, index) => index.toString()}
在平面列表中
<FlatList
data={list}
keyExtractor={(item, index) => index.toString()}
....
/>
索引的类型是Number,FlatList需要字符串类型的值作为键。
const renderItem = ( {item}:{item:{ id:number, name:string , check:boolean }}) => { return ( ) }
找到了解决这个问题的神奇方法
import { ListRenderItemInfo } from 'react-native'
interface PlayerDataStructure {
imageUrl: string;
doubleValue: string | number;
singleValue: string | number;
isFavorite: boolean;
name: string;
thirdRowFirstLabel: string;
thirdRowSecondLabel: string;
thirdRowThirdLabel: string;
thirdRowFourthLabel: string;
id: number
}
const player: Array<PlayerDataStructure> = [
{ imageUrl: imageUrl, doubleValue: '43', singleValue: '01', isFavorite: true, name: 'Jerome Bell', thirdRowFirstLabel: '19 y', thirdRowSecondLabel: '183 cm', thirdRowThirdLabel: '75 kg', thirdRowFourthLabel: 'Right (2HB)', id: 0 },
{ imageUrl: imageUrl, doubleValue: '43', singleValue: '01', isFavorite: false, name: 'Jerome Bell', thirdRowFirstLabel: '19 y', thirdRowSecondLabel: '183 cm', thirdRowThirdLabel: '75 kg', thirdRowFourthLabel: 'Right (2HB)', id: 1 },
];
// Render Item
const renderPlayerData = (object: ListRenderItemInfo<PlayerDataStructure>) => {
const { item } = object;
return (
<PlayerCard imageUrl={item.imageUrl} doubleValue={item.doubleValue} singleValue={item.singleValue} isFavorite={item.isFavorite} name={item.name} thirdRowFirstLabel={item.thirdRowFirstLabel} thirdRowSecondLabel={item.thirdRowSecondLabel} thirdRowThirdLabel={item.thirdRowThirdLabel} thirdRowFourthLabel={item.thirdRowFourthLabel} />
)
}
<FlatList
numColumns={2}
data={player}
keyExtractor={item => item.id.toString()}
renderItem={renderPlayerData}
contentContainerStyle={{ gap: PLAYER_CARD_VERTICAL_PADDING, paddingTop: 67 }}
columnWrapperStyle={{ justifyContent: 'space-between' }}
/>
我的问题是我从
FlatList
而不是 react-native-gesture-handler
导入 react-native
。在这种情况下,类型推断无法正常工作,但当我修复导入时,类型推断工作正常。
正确完成后,传递给
renderItem
的项目类型应该可以从 data
数组的类型推断出,并且您不必指定/覆盖类型。
这个解决方案非常适合我
interface Props {
emotions: Emotion[];
}
class EmotionsPicker extends React.Component<Props> {
render(): React.ReactNode {
return (
<FlatList<Emotion>
data={this.props.emotions}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
/>
);
}
renderItem: ListRenderItem<Emotion> = (props: ListRenderItemInfo<Emotion>): ReactElement<Emotion, string | JSXElementConstructor<Emotion>> => {};
keyExtractor = (item: Emotion): string => {};
}