Typescript Error: Argument of type 'NodeListOf<HTMLInputElement> | undefined' is not assignable to parameter of type 'Iterable<HTMLInputElement> ..." - reactjs

In my React/Typescript App, I am accessing an array of inputs in an event listener through using 'e.currentTarget'. I am using Array.from() to convert the NodeListOf into an array, and made sure to configure my TS.config.json settings of 'es2015'. However I'm receiving this error.
Error
Oddly, this error doesn't occur in my original directory. I had duplicated my project folder, deleted node modules, zipped it, and reopened it, and that's when this error occurs. Not quite sure how else to approach this issue, if anyone has suggestions or solutions, it'd be appreciated.
e: React.ChangeEvent<HTMLInputElement> | React.KeyboardEvent<Element>,
letter: string,
idx: number,
) => {
const fields: HTMLInputElement[] = Array.from(
e.currentTarget.parentElement?.parentElement?.querySelectorAll('input')
)
const length: number = fields.length
const position: number = fields.indexOf(e.target)

You didn't provide much code, but my guess is this is happening because e.currentTarget.parentElement?.parentElement?.querySelectorAll('input') could potentially be undefined. undefined cannot be used as the argument for Array.from, as undefined is not iterable. You need to make sure it exists before you feed it to Array.from. Two possible solutions:
Check that the NodeList you're targeting really exists, then assign your variable
if (document.querySelector('.maybe')?.parentElement?.querySelectorAll('.doesnt-exist?')) {
const fields = Array.from(document.querySelector('.maybe')!.parentElement!.querySelectorAll('.doesnt-exist?'))
}
Assign your potential NodeList to a variable, but default it to [], just in case. Autocast that variable as an HTMLInputElement[], and then it can be safely used in Array.from:
const checker =
document.querySelector('.maybe')?.parentElement?.querySelectorAll('.doesnt-exist?') ?? [] as HTMLInputElement[]
const fields: Element[] = Array.from(checker)
TS Playground

Related

Typescript: Member of union type with incompatible signature when using find on array of objects

I want to check if a value exists in an array of objects.
My array looks something like this:
[
0: {
id: 'unique_obj_id',
item: {
id: 'unique_item_id',
...
},
...
},
1: {...}
]
The objects in the array can be one of many interface types (depending on my api call, here: resource strings represent these interfaces, which are defined somewhere else). But one array will always consist of the same interface types for a given data request.
I'm trying to write a reusable function to check whether given_id exists for any object in the array for obj.item.id.
So far I've managed to write the correct logic but typescript throws some exceptions that I can't seem to figure out. shopApprovalData is a collection of interfaces each following the above object structure accessible by the indices of resource.
export type ApprovalResource = 'str1' | 'str2' | 'str3' | 'str4' | 'str5';
export const checkApprovalItem = (given_id: string, resource: ApprovalResource) => {
const shopApprovalData = useShopApprovals();
if (shopApprovalData && shopApprovalData[resource]) {
const resourceApprovalData = shopApprovalData[resource];
if (resourceApprovalData.find(e => e.item.id === id)) {
return true;
}
}
return false;
}
Typescript shows me that shopApprovalData and itemApprovalData is possibly undefined and that the expression find() is not callable since signatures of members of the union type are not compatible with each other. (Apparently, some removes the error, why?)
What approach should I choose instead to check whether the given_id exists in any object of the array?
Based on your usecase, i create this code sandbox: https://codesandbox.io/s/stackoverflow-answer-ke9drk?file=/src/index.ts
explanation:
Type wont compile, so we need something to mark what the interface of the object.
Also i may confused by your code shopApprovalData[resource] what do you want to achieve here? for example, if resource is str1 shopApprovalData[resource] will always return undefined because no index str1 in Array
I hope it help,
Best Regards

Object is possibly 'null'.ts(2531) - React Typescript

I fetch API data by axios. Everything is working correct. I try to convert js to tsx. The code for fetching data is briefly as below:
let list = null;
...
list = response.data
...
console.log(list.list[2]) //here the problem, first "list" item is red underlined, telling that (Object is possibly 'null'.ts(2531) )
The actual result of list is as follows:
{
"city":{...}
"cod":"200"
"message":6.1851422
"cnt":10
"list":[...]
}
I need the array of list.list. The app is working correctly, but I want to get rid of this warning. I am new to typescript, should I define a type for list? Or is there any other way to handle this warning?
I think you want to define an interface for list then passing the type when you initialize list. Then do a check to make sure that list exists.
type Codes = "200" | "400" | "500"
type City = {
city: string;
address: string;
state: string;
}
interface ListResponse {
"city": City;
"cod": Codes
"message": number;
"cnt": number;
"list":string[]
}
let list: ListResponse | null = null
...
list = response.data
...
if(list){
console.log(list.list[2])
}
you can use a ? operator (more about this here)
So, your code would look like:
list?.list
This short-circuits the expression as undefined if it's a nullish object!
Also, you can just wrap your statement around an if block where you check if the list object is null or not!
NOTE: Additionally, you'd need to check the nature of your list.list variable before accessing it as an array!
Hope it helps!

React Query with TypeScript - how to force the rule that the query key always needs to be an array

I am new in TypeScript and we want to somehow "extend" the existing useQuery hook from react-query by the rule that the query key needs to be an array keys with 2 items at least. Something like
const { data } = useQuery<Data, Error>(["module_1", "fetchA"], fetchFn); // OK
const { data } = useQuery<Data, Error>("module_1", fetchFn); // there should be TS error because queryKey is not array
const { data } = useQuery<Data, Error>(["module_1"], fetchFn); // there should be TS error because array has only 1 item
how to "extend" the useQuery hook
how to add such a type in TS
Thank you in advance
You could write a more strict Data type like such:
type Data = [any, any, ...any[]];
This is a tuple telling the compiler Data should at least contain 2 elements and can contain "an infinity" more
Replace the any's with the actual type you need to use. This will result in errors when trying to use something else than an array of length < 2
const a: Data = [1];
// will raise a compiler error:
// Type '[number]' is not assignable to type '[any, any, ...any[]]'.
// Source has 1 element(s) but target requires 2.
From what I gathered here https://react-query.tanstack.com/guides/query-keys queries base type is string | unknown[] so you can try to follow this typing closely with something like this:
type QueryTuple = [unknown, unknown, ...unknown[]];
// ...
const { data } = useQuery<QueryTuple, Error>(["module_1", "fetchA"], fetchFn);
or in your case, simply restrict it to the string type:
type QueryTuple = [string, string, ...string[]];
// ...
const { data } = useQuery<QueryTuple, Error>(["module_1", "fetchA"], fetchFn);

React error- Type must have a '[Symbol.iterator]()' method that returns an iterator

Im using typescript, not too familiar with and am getting the following err for when I want to copy a group.
This is my subGroups data (It's an array):
const subGroupsData = currentGroup().subGroups;
When i want to copy that array like this;
const newSubGroups: GroupRepresentation[] = [...subGroupsData];
I get the following error:
Type 'GroupRepresentation[] | undefined' must have a '[Symbol.iterator]()' method that returns an iterator.
Any help would be so helpful!
Currently typescript thinks subGroupsData might be undefined, visible from the error message:
Type 'GroupRepresentation[] | undefined' must have a...
^^^^^^^^^
so you have to convince it otherwise:
For example:
const newSubGroups: GroupRepresentation[] = undefined === subGroupsData
? []
: [...subGroupsData];

Unexpected token while adding a type to "value"

const count= data.reduce((s:any, {(value:any)}) => s + value, 0);
i am trying to add a new type to "value" , it shows unexxected token, i am new to type script please help
There are a couple of problems there:
There shouldn't be any () around value: any part.
You can't provide the type of a destructured parameter inline like that, because it conflicts with the renaming feature of destructuring syntax. {value: any} means "take the value of value and put it in the variable/parameter called any.
To give the type to a destructuring pattern, you type the pattern as a whole:
// The destructured parameter −−−−−−vvvvv
const count = data.reduce((s: any, {value}: {value: any}) => s + value, 0);
// The type for the object −−−−−−−−−−−−−−−^^^^^^^^^^^^^^
Playground link
In general, the any type annotation isn't best practice. You haven't shown what data is, but in most cases, you shouldn't have to put type annotations on the callback's parameters at all. For example, let's assume data is {value: number;}[] — an array of objects that have a value property that's a number. Given that type for data, TypeScript doesn't need any type annotations on that reduce call at all:
const count = data.reduce((s, {value}) => s + value, 0);
TypeScript knows from the 0 at the end and the definition of data that both s and value will be numbers, and that the result will be a number.
In a comment you've asked how you'd do this with forEach where you also want the index. Again, you probably don't need to specify the types, and you certainly don't need to specify the type of index since TypeScript knows what type it will be in a forEach callback. But if you did, since index isn't destructured, you just specify its type inline:
// If TypeScript knwos the type of `this.data`, you DON'T NEED THESE TYPES
this.data.forEach(({value, text, data}: {value: typeOfValue; text: typeOfText; data: typeOfData}, index: number) => {
// Types −−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^−−−−−−−^^^^^^^^
// ....
}

Resources