Menguji larik tipe string di TypeScript

95

Bagaimana cara menguji apakah suatu variabel adalah larik string di TypeScript? Sesuatu seperti ini:

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 di sini: http://typescript.io/k0ZiJzso0Qg/2

Sunting: Saya telah memperbarui teks untuk meminta tes untuk string []. Ini hanya di contoh kode sebelumnya.

Sean Kearon
sumber
Karena TypeScript baru saja dikompilasi ke JavaScript, jawabannya dapat ditemukan dengan mencari solusi JavaScript. Selanjutnya, ada baiknya untuk melihat beberapa jawaban karena jawabannya tergantung pada tuan rumah dan bagaimana jawaban itu digunakan dan diteruskan.
WiredPrairie

Jawaban:

164

Anda tidak dapat menguji string[]dalam kasus umum tetapi Anda dapat menguji Arraydengan mudah sama seperti di JavaScript https://stackoverflow.com/a/767492/390330

Jika Anda secara khusus menginginkan stringarray, Anda dapat melakukan sesuatu seperti:

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
sumber
instanceof Arraygagal saat memeriksa array di seluruh frame. Lebih suka Array.isArray: twitter.com/mgechev/status/1292709820873748480
axmrnv
@axmrnv Sepenuhnya setuju 🌹
basarat
juga, Anda dapat memutus pengulangan setelah memberi tahu sesuatuIsNotString itu. Dengan kode Anda, itu akan selalu mengulang melalui semua larik, yang tidak perlu.
Kukuster
58

Pilihan lainnya adalah Array.isArray ()

if(! Array.isArray(classNames) ){
    classNames = [classNames]
}
grigson
sumber
4
Tapi ini tidak memeriksa elemen menjadi tipe string.
Ixx
4
Yeap. Maka Anda perlu satu pemeriksaan tambahan. Array.isArray(classNames) && classNames.every(it => typeof it === 'string')
grigson
@grigson bagaimana dengan kinerja saat memeriksa 400+ hasil? Haruskah saya tidak mempertimbangkan jenis pemeriksaan ini, hanya memeriksa anak pertama atau apakah aman untuk menggunakan "semua" ini?
giovannipds
1
@giovannipds Silakan periksa jawaban asmironov .
Dinei
24

Berikut adalah solusi paling ringkas sejauh ini:

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

Perhatikan bahwa value.everyakan mengembalikan truearray kosong. Jika Anda perlu mengembalikan falselarik kosong, Anda harus menambahkan value.lengthke klausa kondisi:

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

Tidak ada informasi jenis waktu proses dalam TypeScript (dan tidak akan ada, lihat Sasaran Desain TypeScript> Bukan sasaran , 5), jadi tidak ada cara untuk mendapatkan jenis larik kosong. Untuk larik yang tidak kosong, yang dapat Anda lakukan adalah memeriksa jenis itemnya, satu per satu.

axmrnv.dll
sumber
5

Saya tahu ini telah dijawab, tetapi TypeScript memperkenalkan penjaga tipe: https://www.typescriptlang.org/docs/handbook/advanced-types.html#typeof-type-guards

Jika Anda memiliki tipe seperti: Object[] | string[]dan apa yang harus dilakukan sesuatu secara bersyarat berdasarkan jenisnya - Anda dapat menggunakan tipe penjagaan ini:

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
  }
}

Ada masalah dengan larik kosong yang diketik sebagai string[], tapi itu mungkin tidak masalah

Nicholas Boll
sumber
10
Di return falsedalam forEachtidak berpengaruh.
Ishtar
4

Anda dapat melakukannya dengan mudah menggunakan Array.prototype.some()seperti di bawah ini.

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

Saya percaya pendekatan ini lebih baik dari yang lain. Itulah mengapa saya memposting jawaban ini.

Pembaruan atas komentar Sebastian Vittersø

Di sini Anda juga bisa menggunakannya Array.prototype.every().

const isStringArray = (test: any[]): boolean => {
 return Array.isArray(test) && test.every((value) => typeof value === 'string')
}
Sudarshana Dayananda
sumber
1
Alih-alih menggunakan negasi di dua tempat di sini, Anda dapat melakukan:test.every(value => typeof value === 'string')
Sebastian
1
@ SebastianVittersø Terima kasih atas saran BAGUS. Saya memperbarui jawaban saya.
Sudarshana Dayananda
2

Coba ini:

if (value instanceof Array) {
alert('value is Array!');
} else {
alert('Not an array');
}
Tcanarchy
sumber
6
Daripada menyalin jawaban lain, tunjukkan saja duplikatnya sebagai komentar, terutama karena ini tidak berfungsi di semua kasus.
WiredPrairie
Ini hanya memeriksa tipe utama tidak setiap anak Array.
giovannipds
0

ada sedikit masalah di sini karena

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

tidak akan menghentikan foreach. Jadi fungsi tersebut akan mengembalikan nilai true meskipun array tidak berisi nilai string apa pun.

Ini sepertinya bagus untuk saya:

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;
}

Salam, Hans

hans
sumber