{"record":{"id":"5d00b75c55e47fcd","repo":"TheAlgorithms/JavaScript","slug":"argument-should-be-string-5d00b7","errorCode":null,"errorMessage":"Argument should be string","messagePattern":"Argument should be string","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"String/CountSubstrings.js","lineNumber":13,"sourceCode":"/**\n * @function countSubstrings\n * @description Given a string of words or phrases, count the occurrences of a substring\n * @param {String} str - The input string\n * @param {String} substring - The substring\n * @return {Number} - The number of substring occurrences\n * @example countSubstrings(\"This is a string\", \"is\") => 2\n * @example countSubstrings(\"Hello\", \"e\") => 1\n */\n\nconst countSubstrings = (str, substring) => {\n  if (typeof str !== 'string' || typeof substring !== 'string') {\n    throw new TypeError('Argument should be string')\n  }\n\n  if (substring.length === 0) return str.length + 1\n\n  let count = 0\n  let position = str.indexOf(substring)\n\n  while (position > -1) {\n    count++\n    position = str.indexOf(substring, position + 1)\n  }\n\n  return count\n}\n\nexport { countSubstrings }\n","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/TheAlgorithms/JavaScript/blob/5c39e87a9a31f279c60f830ad74a845e4788a517/String/CountSubstrings.js#L1-L30","documentation":"Guard in countSubstrings. The function counts non-overlapping occurrences of a substring and requires BOTH arguments to be strings; if either str or substring fails typeof, it throws TypeError. The single shared message does not indicate which argument was invalid.","triggerScenarios":"Calling countSubstrings(null, 'is'), countSubstrings('text', undefined), countSubstrings(123, '1'), countSubstrings('text', ['a']). Either argument non-string.","commonSituations":"An optional substring parameter omitted (becomes undefined); a haystack read from a source that returned null; passing a regex where a string was expected.","solutions":["Ensure both arguments are strings; default the substring when optional.","Validate both typeof str === 'string' && typeof sub === 'string' at the call site.","If substring may be empty, note empty returns str.length+1 by design."],"exampleFix":"// before\ncountSubstrings(haystack, needle)\n\n// after\nif (typeof haystack === 'string' && typeof needle === 'string') {\n  countSubstrings(haystack, needle)\n}","handlingStrategy":"type-guard","validationCode":"if (typeof str !== 'string' || typeof substring !== 'string') {\n  throw new TypeError('both str and substring must be strings')\n}\ncountSubstrings(str, substring)","typeGuard":"const areStrings = (a, b) => typeof a === 'string' && typeof b === 'string'","tryCatchPattern":"try {\n  countSubstrings(haystack, needle)\n} catch (e) {\n  if (e instanceof TypeError) { /* one of the args was not a string */ } else throw e\n}","preventionTips":["Default the substring when it is optional.","The shared message is ambiguous — log both values on failure.","Pre-validate both args together."],"tags":["string","validation","type-guard","substring","ambiguous-message"],"backgroundTag":null,"analyzedSha":"5c39e87a9a31f279c60f830ad74a845e4788a517","analyzedAt":"2026-08-13T04:54:54.474Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}