I'm using Typescript, form some reason the function below gives me the error: Property 'title' doesn't exist on type 'never'
. If i write the same function in JS it doesn't give me error, only in Typescript. I don't know why, but my TextInput doens't filter the FlatList items.
const searchFilter =(text) => {
if(text){
const newData = masterData.filter((item) => {
//the error appears in the next line below in 'item.title'
const itemData = item.title ? item.title.toUpperCase() : ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredData(newData);
setSearch(text);
} else {
setFilteredData(masterData);
setSearch(text);
}
}
My FlatList works and show the data from the JSON fetch. The only problem is when i start typing in the TextInput
and the FlatList disappears.
Full code below:
const ManageCustomersScreen =(props: ManageCustomersScreen) =>{
//navigation
const backPage = () => props.navigation.navigate("Home");
const callCustomer = () => props.navigation.navigate("Customer");
const [filteredData, setFilteredData] = useState([]);
const [masterData, setMasterData] = useState([]);
const [search, setSearch] = useState('');
useEffect(() => {
fetchPosts();
return() => {
}
}, [])
const fetchPosts = () => {
const apiUrl = 'https://jsonplaceholder.typicode.com/users';
fetch(apiUrl)
.then((response) => response.json())
.then((responseJson) => {
setFilteredData(responseJson);
setMasterData(responseJson);
}).catch((error) => {
console.error(error);
})
}
const ItemView = ({item}) => {
return(
<View style={manageCustomersStyle.tableBody}>
<View style={manageCustomersStyle.customerCard}>
<TouchableOpacity
style={manageCustomersStyle.customerCardContent}
onPress={callCustomer}>
<View style={manageCustomersStyle.customerCardInfo}>
<Text style={manageCustomersStyle.customerCardInfoName}>{item.name}</Text>
<Text style={manageCustomersStyle.customerCardInfoId}>{item.id}</Text>
</View>
<Icon
name="angle-double-right"
size={40}
color="grey"
/>
</TouchableOpacity>
</View>
</View>
)
}
const searchFilter =(text) => {
if(text){
const newData = masterData.filter((item) => {
const itemData = item.title ? item.title.toUpperCase() : ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredData(newData);
setSearch(text);
} else {
setFilteredData(masterData);
setSearch(text);
}
}
return(
<SafeAreaView style={manageCustomersStyle.safeAreaView}>
<Appbar.Header>
<Appbar.BackAction onPress={backPage} />
<Appbar.Content title ="Manage Customers" />
</Appbar.Header>
<View style={manageCustomersStyle.searchBarView}>
<Icon
name="search"
size={30}
color="grey"
style={manageCustomersStyle.searchBarIcon}/>
<TextInput
style={manageCustomersStyle.searchBar}
placeholder={'Search'}
value={search}
onChangeText={(text) => searchFilter(text)}/>
</View>
<FlatList
data={filteredData}
keyExtractor={(item, index) => index.toString()}
renderItem={ItemView}
/>
</SafeAreaView>
);
}
export default ManageCustomersScreen;
These screenshots shows when i start typing in the TextInput
the FlatList
simply disappears.
Typescript is meant for writing typed javascript. Currently, you're just writing javascript in a Typescript file. You're not really using Typescript.
You'd greatly benefit from reading: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html
I would start by changing this line to actually include type data:
const [masterData, setMasterData] = useState([]);
Currently, the most strict type Typescript can determine for masterData
would be any[]
, which is bad. You want to avoid any
whenever you can, as it means that Typescript cannot perform any type check for this variable.
For example, if title is an optional string, you could write:
const [masterData, setMasterData] = useState<{ title?: string }[]>([]);
Or even better, you could define this as a type:
interface MasterDataItem {
title?: string
}
And then use it like this:
const [masterData, setMasterData] = useState<MasterDataItem[]>([]);