Prueba de matriz de tipo de cadena en TypeScript

95

¿Cómo puedo probar si una variable es una matriz de cadena en TypeScript? Algo como esto:

function f(): string {
    var a: string[] = ["A", "B", "C"];

    if (typeof a === "string[]")    {
        return "Yes"
    }
    else {
        // returns no as it's 'object'
        return "No"
    }
};

TypeScript.io aquí: http://typescript.io/k0ZiJzso0Qg/2

Editar: He actualizado el texto para solicitar una prueba para la cadena []. Esto fue solo en el ejemplo de código anteriormente.

Sean Kearon
fuente
Como TypeScript simplemente se compila en JavaScript, las respuestas se pueden encontrar buscando una solución de JavaScript. Además, vale la pena ver algunas de las respuestas, ya que la respuesta depende del host y de cómo se usa y pasa.
WiredPrairie

Respuestas:

164

No puede probar string[]en el caso general, pero puede probar Arrayfácilmente lo mismo que en JavaScript https://stackoverflow.com/a/767492/390330

Si desea específicamente una stringmatriz, puede hacer algo como:

if (Array.isArray(value)) {
   var somethingIsNotString = false;
   value.forEach(function(item){
      if(typeof item !== 'string'){
         somethingIsNotString = true;
      }
   })
   if(!somethingIsNotString && value.length > 0){
      console.log('string[]!');
   }
}
basarat
fuente
instanceof Arrayfalla al verificar matrices a través de marcos. Preferir Array.isArray: twitter.com/mgechev/status/1292709820873748480
axmrnv
@axmrnv Totalmente de acuerdo 🌹
basarat
Además, puede romper el bucle justo después de decir que algo no es una cadena. Con su código, necesariamente recorrerá toda la matriz, lo cual no es necesario.
Kukuster
58

Otra opción es Array.isArray ()

if(! Array.isArray(classNames) ){
    classNames = [classNames]
}
Grigson
fuente
4
Pero esto no comprueba que los elementos sean de tipo string.
Ixx
4
Yeap. Entonces necesitas una verificación adicional. Array.isArray(classNames) && classNames.every(it => typeof it === 'string')
grigson
@grigson ¿qué hay del rendimiento al comprobar más de 400 resultados? ¿Debo descartar este tipo de verificación de tipo, marcar solo el primer niño o es seguro usar este "todo"?
giovannipds
1
@giovannipds Compruebe la respuesta de asmironov .
Dinei
24

Aquí está la solución más concisa hasta ahora:

function isArrayOfStrings(value: any): boolean {
   return Array.isArray(value) && value.every(item => typeof item === "string");
}

Tenga en cuenta que value.everyvolverá truepara una matriz vacía. Si necesitas regresarfalse para una matriz vacía, debe agregar value.lengtha la cláusula de condición:

function isNonEmptyArrayOfStrings(value: any): boolean {
    return Array.isArray(value) && value.length && value.every(item => typeof item === "string");
}

No hay información de tipo en tiempo de ejecución en TypeScript (y no la habrá, consulte Objetivos de diseño de TypeScript> Sin objetivos , 5), por lo que no hay forma de obtener el tipo de una matriz vacía. Para una matriz no vacía, todo lo que puede hacer es verificar el tipo de sus elementos, uno por uno.

axmrnv
fuente
5

Sé que esto ha sido respondido, pero TypeScript introdujo protectores de tipo: https://www.typescriptlang.org/docs/handbook/advanced-types.html#typeof-type-guards

Si tiene un tipo como: Object[] | string[]y qué hacer algo condicionalmente en función de qué tipo es, puede usar este tipo de protección:

function isStringArray(value: any): value is string[] {
  if (value instanceof Array) {
    value.forEach(function(item) { // maybe only check first value?
      if (typeof item !== 'string') {
        return false
      }
    })
    return true
  }
  return false
}

function join<T>(value: string[] | T[]) {
  if (isStringArray(value)) {
    return value.join(',') // value is string[] here
  } else {
    return value.map((x) => x.toString()).join(',') // value is T[] here
  }
}

Hay un problema con una matriz vacía que se escribe como string[], pero eso podría estar bien

Nicholas Boll
fuente
10
El return falseen el forEachno tiene ningún efecto.
Ishtar
4

Puede hacerlo fácilmente usando la Array.prototype.some()siguiente manera.

const isStringArray = (test: any[]): boolean => {
 return Array.isArray(test) && !test.some((value) => typeof value !== 'string')
}
const myArray = ["A", "B", "C"]
console.log(isStringArray(myArray)) // will be log true if string array

Creo que este enfoque es mejor que otros. Es por eso que estoy publicando esta respuesta.

Actualización sobre el comentario de Sebastian Vittersø

Aquí también puedes usar Array.prototype.every().

const isStringArray = (test: any[]): boolean => {
 return Array.isArray(test) && test.every((value) => typeof value === 'string')
}
Sudarshana Dayananda
fuente
1
En lugar de usar la negación en dos lugares aquí, podría hacer:test.every(value => typeof value === 'string')
Sebastián
1
@ SebastianVittersø Gracias por la sugerencia NICE. Actualicé mi respuesta.
Sudarshana Dayananda
2

Prueba esto:

if (value instanceof Array) {
alert('value is Array!');
} else {
alert('Not an array');
}
Tcanarquía
fuente
6
En lugar de copiar otra respuesta, solo señale el duplicado como un comentario, especialmente porque esto no funciona en todos los casos.
WiredPrairie
Esto solo verifica el tipo principal, no todos los hijos de Array.
giovannipds
0

hay un pequeño problema aquí porque el

if (typeof item !== 'string') {
    return false
}

no detendrá el foreach. Entonces, la función devolverá verdadero incluso si la matriz no contiene valores de cadena.

Esto parece funcionar para mí:

function isStringArray(value: any): value is number[] {
  if (Object.prototype.toString.call(value) === '[object Array]') {
     if (value.length < 1) {
       return false;
     } else {
       return value.every((d: any) => typeof d === 'string');
     }
  }
  return false;
}

Saludos Hans

Hans
fuente