Reputation: 53
I am a beginner in TypeScript.
I used ts migrate
to replace the JavaScript with TypeScript in my react app, but I got the following error.
Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{}'. TS7053
The files that caused the error are the following.
import React, { useState, useEffect, useCallback} from 'react';
import './assets/styles/style.css';
import {AnswersList, Chats} from './components/index';
import FormDialog from './components/Forms/FormDialog';
import {db} from './firebase/index';
const App = () => {
const [answers, setAnswers] = useState([]);
const [chats, setChats] = useState([]);
const [currentId, setCurrentId] = useState("init");
const [dataset, setDataset] = useState({});
const [open, setOpen] = useState(false);
const displayNextQuestion = (nextQuestionId: any, nextDataset: any) => {
addChats({
text: nextDataset.question,
type: 'question'
})
setAnswers(nextDataset.answers)
setCurrentId(nextQuestionId)
}
const selectAnswer = (selectedAnswer: any, nextQuestionId: any) => {
switch(true) {
case (nextQuestionId === 'contact'):
handleClickOpen()
break;
case (/^https:*/.test(nextQuestionId)):
const a = document.createElement('a');
a.href = nextQuestionId;
a.target = '_blank';
a.click();
break;
default:
addChats({
text: selectedAnswer,
type: 'answer'
})
setTimeout(() => displayNextQuestion(nextQuestionId, dataset[nextQuestionId]), 500) //Here's where the error occurs
break;
}
}
const addChats = (chat: any) => {
setChats(prevChats => {
return [...prevChats, chat]
})
}
const handleClickOpen = () => {
setOpen(true)
};
const handleClose = useCallback(() => {
setOpen(false)
}, [setOpen]);
useEffect(() => {
(async() => {
const initDataset = {};
await db.collection('questions').get().then(snapshots => {
snapshots.forEach(doc => {
const id = doc.id
const data = doc.data()
initDataset[id] = data
})
})
setDataset(initDataset)
displayNextQuestion(currentId, initDataset[currentId])
})()
}, [])
useEffect(() => {
const scrollArea = document.getElementById('scroll-area')
if (scrollArea) {
scrollArea.scrollTop = scrollArea.scrollHeight
}
})
return(
<section className="c-section">
<div className="c-box">
<Chats chats={chats} />
<AnswersList answers={answers} select={selectAnswer} />
<FormDialog open={open} handleClose={handleClose} />
</div>
</section>
);
}
export default App;
First, I defined the type of displayNextQuestion
using the interface as follows, but the error was not resolved and we got another error.
interface StringKeyObject {
[key: string]: any;
}
const displayNextQuestion: StringKeyObject = (nextQuestionId: any, nextDataset: any) => {
addChats({
text: nextDataset.question,
type: 'question'
})
setAnswers(nextDataset.answers)
setCurrentId(nextQuestionId)
}
This expression is not callable. Type 'StringKeyObject' has no call signatures. TS2349
Next, the displayNextQuestion
's argument nextQuestionId
was of type any, so I set it to string, but the error did not change.
I did a lot of research and did not know how to solve this error, so I asked.
Upvotes: 1
Views: 2010
Reputation: 16450
When you say:
const displayNextQuestion: StringKeyObject = (...)
This means displayNextQuestion
is of type StringKeyObject
which is clearly not. It's a function. You are not returning anything from this function either so the return type is void
as well.
Now let's see the parameters. nextQuestionId
must be a string
since you use setCurrentId(nextQuestionId)
and its default state is init
.
nextDataset
should be an object that has array of answers like:
{
answers: [...],
...
}
Putting it all together something like this should work:
const displayNextQuestion = (nextQuestionId: string, nextDataset: { answers: Array<Answer> } ) => {
addChats({
text: nextDataset.question,
type: 'question'
})
setAnswers(nextDataset.answers)
setCurrentId(nextQuestionId)
}
I suggest you define an interface for the dataset as well as answer
:
interface Answer {
// ...whatever that answer has
}
interface Dataset {
answers: Array<Answer>;
// ...other things that Dataset has
}
And explicitly set the type for useState
:
interface Question {}
interface Chat {}
interface Answer { }
interface Dataset {
answers: Array<Answer>;
question: any;
[k: string]: Question;
// ^ This signifies that Dataset can have any key as long as it's string
// and its value is of type Question (best I could guess based on the
// usage at "dataset[nextQuestionId])"
}
const App = () => {
const [answers, setAnswers] = useState<Array<Answer>>([]);
const [chats, setChats] = useState<Array<Chat>>([]);
const [currentId, setCurrentId] = useState("init");
const [dataset, setDataset] = useState<Dataset>({ answers: [], question: null });
const [open, setOpen] = useState(false);
// ...
Upvotes: 2
Reputation: 442
I'm not sure, because there is no mention of exactly where is the line the error occurs.
Maybe I think u should use Generics for useState
.
could you check below is worked?
type DataSet = {
// write the form of state to be managed.
}
const [dataset, setDataset] = useState<DataSet>({});
Upvotes: 0