275

Is there a way to let a javascript function know that a certain parameter is of a certain type?

Being able to do something like this would be perfect:

function myFunction(Date myDate, String myString)
{
    //do stuff
}

Thank you!

Update: Being that the answer is a resounding "no," if I want myDate to be treated as a date (in order to call date functions on it), I have to cast it as a date inside the function or set a new variable of type Date to it?

dmr
  • 21,811
  • 37
  • 100
  • 138
  • 2
    Not in a builtin and general sense. You can do this yourself, by hand, but then it depends on how you define "of a certain type" – hugomg Dec 06 '11 at 22:16
  • 2
    There are also no classes in JavaScript, so there is no `Date`, only `object`. – rid Dec 06 '11 at 22:19
  • @Radu: What about [this Mozilla Develop Network Page](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date)? – dmr Dec 06 '11 at 22:23
  • @dmr, that's not a class. `Date` is a function. Take a look at http://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript to find out more about the JavaScript `new` keyword. Also, since there are no classes, there is no casting. You can simply call the functions you want. If the object contains them, they will run, otherwise you will get an error. – rid Dec 06 '11 at 22:31
  • You can add a `constructor` check, nowadays. Remove the types from the parameter locaction, and just add something like, `if((arguments.length!==2) || (myDate.constructor!==Date) || (myString.constructor!==String)){return undefined;}` or however you'd want to exit/fail it early. `throw`ing `Error`s is now also an option. – kayleeFrye_onDeck Apr 20 '17 at 22:38
  • 3
    It's an old one however no one mentioned typescript – kit Feb 24 '16 at 13:52

14 Answers14

286

No, JavaScript is not a statically typed language. Sometimes you may need to manually check types of parameters in your function body.

pronvit
  • 4,169
  • 1
  • 18
  • 27
  • 57
    @JeffreySweeney neither is PHP statically typed. But you have the option to do type hinting in php. Have you ever looked at a _big_ nodejs backend application? exactly, each function has arguments, and you have NO clue what each argument is. We are talking about thousands of arguments and when reading, you have to read the entire code, and the entire code of the caller and of its caller, etc. Blessing? you certainly must be jesting. – Toskan Mar 29 '16 at 20:21
  • 17
    apart from bashing someone who calls no feature allowing type hinting a blessing I might want to point out typescript: http://www.typescriptlang.org/ basically EM6 + type hinting – Toskan Mar 29 '16 at 20:25
  • 42
    @JeffreySweeney It's not a blessing. It's cancer. – Robo Robok Dec 23 '17 at 19:45
  • 2
    @Toskan I wouldn't say it is not a blessing. I have been using JavaScript for four years now, and that is just the nature of some languages. The set of programming languages _should_ range from weakly typed to strongly typed the same way it should range from low level to high level. Additionally, JavaScript provides the `instanceof` and `typeof` keywords to aid in this. Although this takes up more code, maybe it is on the developer for choosing JavaScript as the language for something that largely depends on types. As for huge nodejs backend applications? I think it should be common sense. – Marvin Jun 03 '19 at 02:27
  • 1
    Does it really matter if the error occurs inside the function, for example because you try to iterate on a parameter that turns out to be a float? Typed parameters only shifts the blame, issuing the error in the caller scope. Either way, you get an error that can easily be traced. Today it seems like throwing exceptions around is the solution to everything - but somewhere and somehow, the actual error has to be handled. Why not learn to do some defensive programming from the start instead of trying to shift the blame? – Christoffer Bubach Jul 20 '20 at 07:21
  • Here is the functional way of type checking: https://stackoverflow.com/a/64794158/1948585 – user1948585 Nov 12 '20 at 03:23
  • There are actually some ways to achieve this. I don't know maybe this answer is old – Pouria Moosavi Dec 28 '20 at 18:09
192

Not in JavaScript itself, but using Google Closure Compiler's advanced mode, you can do that:

/**
 * @param {Date} myDate The date
 * @param {string} myString The string
 */
function myFunction(myDate, myString)
{
    //do stuff
}

See https://code.google.com/closure/compiler/docs/js-for-compiler.html

Pang
  • 9,564
  • 146
  • 81
  • 122
eolsson
  • 12,567
  • 3
  • 41
  • 43
  • 1
    this also works with/enables Eclipse *JavaScript Editor* - *Outline View* and *Code Completion*. whereas the `foo( /*MyType*/ param )` way as described here also works: http://stackoverflow.com/a/31420719/1915920 – Andreas Covidiot Feb 17 '16 at 08:37
  • 3
    I realize how old this question is but I wanted to point out that it's honored in IntelliJ. Very underated answer here. – ChettDM Jul 05 '20 at 05:33
  • 7
    Also used in VSCode. – Cullub Aug 05 '20 at 14:50
  • 1
    This is actually the correct answer, most editors (at least VS Code) will honor this. – Kokodoko Apr 03 '23 at 08:23
123

While you can't inform JavaScript the language about types, you can inform your IDE about them, so you get much more useful autocompletion.

Here are two ways to do that:

  1. Use JSDoc, a system for documenting JavaScript code in comments. In particular, you'll need the @param directive:

    /**
     * @param {Date} myDate - The date
     * @param {string} myString - The string
     */
    function myFunction(myDate, myString) {
      // ...
    }
    

    You can also use JSDoc to define custom types and specify those in @param directives, but note that JSDoc won't do any type checking; it's only a documentation tool. To check types defined in JSDoc, look into TypeScript, which can parse JSDoc tags.

  2. Use type hinting by specifying the type right before the parameter in a
    /* comment */:

    JavaScript type hinting in WebStorm

    This is a pretty widespread technique, used by ReactJS for instance. Very handy for parameters of callbacks passed to 3rd party libraries.

TypeScript

For actual type checking, the closest solution is to use TypeScript, a (mostly) superset of JavaScript. Here's TypeScript in 5 minutes.

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • 11
    How to get this on `VSCode`? – Anand Undavia Apr 16 '18 at 11:26
  • 3
    Thanks. Even though this depends on the IDE. I use VI and won't work. – JeanCarlos Chavarria Aug 26 '18 at 20:02
  • 4
    @negrotico19: `vi` is an overly abused editor, not an IDE. You can do a lot of stuff in `vi`, just as you can make [music videos in Excel](https://www.wired.com/2012/08/stop-motion-excel-music-video/). Good idea? Probably not. Use the right tool for the job. – Dan Dascalescu Feb 03 '20 at 22:46
  • 1
    @AnandUndavia For VSCode, you can go with Option 1, but only with the [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) extension, as far as I know. Sorry for the (extremely) late reply, by the way. – fwoosh Aug 22 '20 at 03:38
  • To install: `npm install jsdoc` – toadead Jan 27 '22 at 21:43
27

Check out the new Flow library from Facebook, "a static type checker, designed to find type errors in JavaScript programs"

Definition:

/* @flow */
function foo(x: string, y: number): string {
  return x.length * y;
}
foo('Hello', 42);

Type checking:

$> flow
hello.js:3:10,21: number
This type is incompatible with
  hello.js:2:37,42: string

And here is how to run it.

Renaud
  • 16,073
  • 6
  • 81
  • 79
16

Edit: Seven years later, this answer still gets occasional upvotes. It's fine if you are looking for runtime checking, but I would now recommend compile-time type checking using Typescript, or possibly Flow. See https://stackoverflow.com/a/31420719/610585 above for more.

Original answer:

It's not built into the language, but you can do it yourself quite easily. Vibhu's answer is what I would consider the typical way of type checking in Javascript. If you want something more generalized, try something like this: (just an example to get you started)

typedFunction = function(paramsList, f){
    //optionally, ensure that typedFunction is being called properly  -- here's a start:
    if (!(paramsList instanceof Array)) throw Error('invalid argument: paramsList must be an array');

    //the type-checked function
    return function(){
        for(var i=0,p,arg;p=paramsList[i],arg=arguments[i],i<paramsList.length; i++){
            if (typeof p === 'string'){
                if (typeof arg !== p) throw new Error('expected type ' + p + ', got ' + typeof arg);
            }
            else { //function
                if (!(arg instanceof p)) throw new Error('expected type ' + String(p).replace(/\s*\{.*/, '') + ', got ' + typeof arg);
            }
        }
        //type checking passed; call the function itself
        return f.apply(this, arguments);
    }
}

//usage:
var ds = typedFunction([Date, 'string'], function(d, s){
    console.log(d.toDateString(), s.substr(0));
});

ds('notadate', 'test');
//Error: expected type function Date(), got string
ds();
//Error: expected type function Date(), got undefined
ds(new Date(), 42);
//Error: expected type string, got number
ds(new Date(), 'success');
//Fri Jun 14 2013 success
undefined
  • 6,208
  • 3
  • 49
  • 59
14

You can implement a system that handles the type checks automatically, using a wrapper in your function.

With this approach, you can build a complete declarative type check system that will manage for you the type checks . If you are interested in taking a more in depth look at this concept, check the Functyped library

The following implementation illustrates the main idea, in a simplistic, but operative way :

/*
 * checkType() : Test the type of the value. If succeds return true, 
 * if fails, throw an Error
 */
function checkType(value,type, i){
  // perform the appropiate test to the passed 
  // value according to the provided type
  switch(type){
    case Boolean : 
      if(typeof value === 'boolean') return true;
      break;
    case String : 
      if(typeof value === 'string') return true;
      break;
    case Number : 
      if(typeof value === 'number') return true;
      break;
    default :
      throw new Error(`TypeError : Unknown type provided in argument ${i+1}`);
  }
  // test didn't succeed , throw error
  throw new Error(`TypeError : Expecting a ${type.name} in argument ${i+1}`);
}


/*
 * typedFunction() : Constructor that returns a wrapper
 * to handle each function call, performing automatic 
 * arguments type checking
 */
function typedFunction( parameterTypes, func ){
  // types definitions and function parameters 
  // count must match
  if(parameterTypes.length !== func.length) throw new Error(`Function has ${func.length} arguments, but type definition has ${parameterTypes.length}`);
  // return the wrapper...
  return function(...args){
    // provided arguments count must match types
    // definitions count
    if(parameterTypes.length !== args.length) throw new Error(`Function expects ${func.length} arguments, instead ${args.length} found.`);
    // iterate each argument value, and perform a
    // type check against it, using the type definitions
    // provided in the construction stage
    for(let i=0; i<args.length;i++) checkType( args[i], parameterTypes[i] , i)
    // if no error has been thrown, type check succeed
    // execute function!
    return func(...args);
  }
}

// Play time! 
// Declare a function that expects 2 Numbers
let myFunc = typedFunction( [ Number, Number ],  (a,b)=>{
  return a+b;
});

// call the function, with an invalid second argument
myFunc(123, '456')
// ERROR! Uncaught Error: TypeError : Expecting a Number in argument 2
colxi
  • 7,640
  • 2
  • 45
  • 43
12

No, instead you would need to do something like this depending on your needs:

function myFunction(myDate, myString) {
  if(arguments.length > 1 && typeof(Date.parse(myDate)) == "number" && typeof(myString) == "string") {
    //Code here
  }
}
VNO
  • 3,645
  • 1
  • 16
  • 25
10

TypeScript is one of the best solutions for now.

TypeScript extends JavaScript by adding types to the language.

typescript version demo

// type alias
type myDateType = Date;
type myStringType = string;

function myFunction(myDate: myDateType, myString: myStringType) {
  // do stuff
  console.log(`myDate =`, myDate);
  console.log(`myString =`, myString);
}

myFunction(new Date(), 'TypeScript is awesome!');

try this playground online

refs

https://www.typescriptlang.org/

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
5

It can easilly be done with ArgueJS:

function myFunction ()
{
  arguments = __({myDate: Date, myString: String});
  // do stuff
};
zVictor
  • 3,610
  • 3
  • 41
  • 56
3

Explanation

I'm not sure if my answer is direct answer to original question, but as I suppose a lot of people come here to just find a way to tell their IDEs to understand types, I'll share what I found.

If you want to tell VSCode to understand your types, do as follows. Please pay attention that js runtime and NodeJS does not care about these types at all.

Solution

1- Create a file with .d.ts ending: e.g: index.d.ts. You can create this file in another folder. for example: types/index.d.ts
2- Suppose we want to have a function called view. Add these lines to index.d.ts:

/**
 * Use express res.render function to render view file inside layout file.
 *
 * @param {string} view The path of the view file, relative to view root dir.
 * @param {object} options The options to send to view file for ejs to use when rendering.
 * @returns {Express.Response.render} .
 */
view(view: string, options?: object): Express.Response.render;

3- Create a jsconfig.json file in you project's root. (It seems that just creating this file is enough for VSCode to search for your types).

A bit more

Now suppose we want to add this type to another library types. (As my own situation). We can use some ts keywords. And as long as VSCode understands ts we have no problem with it.
For example if you want to add this view function to response from expressjs, change index.d.ts file as follows:

export declare global {
  namespace Express {
    interface Response {
      /**
       * Use express res.render function to render view file inside layout file.
       *
       * @param {string} view The path of the view file, relative to view root dir.
       * @param {object} options The options to send to view file for ejs to use when rendering.
       * @returns {Express.Response.render} .
       */
      view(view: string, options?: object): Express.Response.render;
    }
  }
}

Result

enter image description here

enter image description here

Pouria Moosavi
  • 662
  • 7
  • 22
1

Use typeof or instanceof:

const assert = require('assert');

function myFunction(Date myDate, String myString)
{
    assert( typeof(myString) === 'string',  'Error message about incorrect arg type');
    assert( myDate instanceof Date,         'Error message about incorrect arg type');
}
fider
  • 1,976
  • 26
  • 29
0

Maybe a helper function like this. But if you see yourself using such syntax regularly, you should probably switch to TypeScript.

function check(caller_args, ...types) {
    if(!types.every((type, index) => {
        if(typeof type === 'string')
            return typeof caller_args[index] === type
        return caller_args[index] instanceof type;
    })) throw Error("Illegal argument given");
}

function abc(name, id, bla) {
   check(arguments, "string", "number", MyClass)
   // code
}
Pang
  • 9,564
  • 146
  • 81
  • 122
phil294
  • 10,038
  • 8
  • 65
  • 98
0

I've been thinking about this too. From a C background, you can simulate function return code types, as well as, parameter types, using something like the following:

function top_function() {
    var rc;
    console.log("1st call");
    rc = Number(test_function("number", 1, "string", "my string"));
    console.log("typeof rc: " + typeof rc + "   rc: " + rc);
    console.log("2nd call");
    rc = Number(test_function("number", "a", "string", "my string"));
    console.log("typeof rc: " + typeof rc + "   rc: " + rc);
}
function test_function(parm_type_1, parm_val_1, parm_type_2, parm_val_2) {
    if (typeof parm_val_1 !== parm_type_1) console.log("Parm 1 not correct type");
    if (typeof parm_val_2 !== parm_type_2) console.log("Parm 2 not correct type");
    return parm_val_1;
}

The Number before the calling function returns a Number type regardless of the type of the actual value returned, as seen in the 2nd call where typeof rc = number but the value is NaN

the console.log for the above is:

1st call
typeof rc: number   rc: 1
2nd call
Parm 1 not correct type
typeof rc: number   rc: NaN
Mato
  • 13
  • 3
LouT
  • 1
0

I assume you allow IDE to help you; then the below answer may help you.

IDE: jetbrains/Golang That's ok if your IDE is not this. I believe all the IDE which support JSDoc, and then it can satisfy you most request.

and it can show JSDoc very well.

Demo

my /pkg/encoding/base64.js

/**
 * Convert string to the base64 format.
 *
 * @param str {string} Input string
 * @returns {string} some message about return...
 * @example
 *  - btoa(toBinary("☸☹☺☻☼☾☿"))
 *  - Str2base64("☸☹☺☻☼☾☿")
 * @see https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa#unicode_strings
 */
export function Str2base64(str) {
  return btoa(toBinary(str))
}

test.js

import * as base64 from "../pkg/encoding/base64"
const filenameB64 = base64.Str2base64("test")

enter image description here

Useful JSDoc Documentation

Other links

Carson
  • 6,105
  • 2
  • 37
  • 45