A
A
Alex Mirgorodskiy2021-04-29 10:08:47
typescript
Alex Mirgorodskiy, 2021-04-29 10:08:47

What is the correct way to handle multidimensional arrays in typeScript?

Good day to all, I ran into a problem, my property can be either just an array or a multidimensional array. It seems that I described all the conditions correctly, everything works, but for some reason ts swears. Do not tell me how to correctly describe a similar situation so that there is no error

The error itself

Argument of type '{ [x: string]: string; }' is not assignable to parameter of type '{ [key: string]: string; } & { [key: string]: string; }[]'.
Type '{[x:string]:string; }' is missing the following properties from type '{ [key: string]: string; }[]': length, pop, push, concat, and 28 more.


let errorMessage = 'error',
     controlName = 'test'
if (formIndex !== null) {
            form.formParams.errorList[formIndex] = {...form.formParams.errorList[formIndex], [controlName]: errorMessage}
        } else {

            if (Array.isArray(form.formParams.errorList)) {

                form.formParams.errorList.push({[controlName]: errorMessage})
            }

        }


How I typed the errorList in which the error
errorList?: {[key: string]: string}[] | {[key: string]: string}[][]

Answer the question

In order to leave comments, you need to log in

2 answer(s)
X
xenonhammer, 2021-04-29
@xenonhammer

generic might help.

type TArray<T> = T extends { [key: string]: string } ? {[key: string]: string} :  {[key: string]: string}[];

It is better if your errorList will always be one-dimensional, multidimensional arrays in TS are generally a weak side, there will be problems later, and everything will get terribly confused

D
Dmitry Belyaev, 2021-04-30
@bingo347

Problem in ...form.formParams.errorList[formIndex]
Let's go in order:

// допустим у нас есть следующие переменные с типами:
let obj: Obj;
let value: T;

// мы их собираем в такой объект:
const newObj = { ...obj, k: value };
the compiler will deduce the type for newObj from the context and get Obj & { k: T }, exactly from the fact that we combine these entities.
Let's complicate the example:
let objs: Obj[];
let value: T;
let key: string;

const newObj = { ...objs[1], [key]: value };
The output type will be already Obj & { [key: string]: string }, although objs this time we have an array, the compiler sees that we are taking an index.
What will happen if we have objs instead of a simple Obj[]one Obj[] | Obj[][]?
First we take the value by index from objs - this operation will return the type Obj | Obj[].
After we expand it through spread into an object and add the value by index, we get the type (Obj | Obj[]) & { [key: string]: string }:
(Obj & { [key: string]: string }) | (Obj[] & { [key: string]: string })

What if Obj is also { [key: string]: string }? We can collapse the type by simplifying the type equation:
(Obj & Obj) | (Obj[] & Obj)
(Obj) | (Obj[] & Obj)
(Obj & Obj[]) | (Obj & Obj)
(Obj & Obj[]) | (Obj)
Obj & Obj[]
And this is exactly the type that the compiler received from you

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question