Не удается вызвать Array.every() с типом объединения typescript

#typescript #types #type-conversion #union-types

Вопрос:

Приведенный ниже код выдаст ошибку при использовании с Array.every()

 // In my code, data it would be assigned from an API response;
let data: string[] | string[][] = []; 

// Need to use every() and some() for checking
let isChecked = false;

// Check if the type is string[][], got error with every()
if (data.length amp;amp; data[0] instanceof Array) {
    isChecked = data.every(...);
}

// Check if the type is string[], no error with some()
if (data.length amp;amp; typeof data[0] === 'string') {
    isChecked = data.some(...);
}
 

Машинопись покажет эту ошибку при every() :

 Each member of the union type 
'{ <S extends string>(predicate: (value: string, index: number, array: string[]) => value is S, thisArg?: any): this is S[]; 
(predicate: (value: string, index: number, array: string[]) => unknown, thisArg?: any): boolean; } | { ...; }' 
has signatures, but none of those signatures are compatible with each other
 

Как мне преодолеть эту ошибку. Вот пример игровой площадки с машинописным текстом

Ответ №1:

 let a: string[] | string[][] = [];


const isArrOfArr = (arg: any): arg is string[][] => Array.isArray(arg) amp;amp; Array.isArray(arg[0])

const isArrOfArr_super_safe = (arg: any): arg is string[][] => Array.isArray(arg) amp;amp; arg.every(Array.isArray)


if (isArrOfArr(a)) {
    let b = a.every(elem => elem) // ok
}
 

TS не рассматривается data[0] instanceof Array как типографика для первого элемента, поскольку массивы по умолчанию изменчивы.

Для этой цели вы можете использовать свой собственный типограф

Ответ №2:

Вы можете сделать что-то подобное. Код немного длинноват, но он будет служить целям безопасности типов.

 let a: Array<string> | Array<Array<string>> = [];


if (a.length amp;amp; a[0] instanceof Array) {
    let b = (a as Array<Array<string>>).every((item: Array<string>) => {
        if (typeof item === "string" amp;amp; item) return true
        else {
            if (Array.isArray(item)) {
                return item.every(subItem => subItem)
            }
            return false
        }
    })
    console.log(b)
}
 

Вот ссылка на игровую площадку