Set type for function parameters?

JavascriptFunction

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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

Solution 2 - Javascript

Not in javascript it self 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 http://code.google.com/closure/compiler/docs/js-for-compiler.html

Solution 3 - Javascript

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.

  1. 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.

Solution 4 - Javascript

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.

Solution 5 - Javascript

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

Solution 6 - Javascript

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

Solution 7 - Javascript

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

Solution 8 - Javascript

TypeScript is one of the best solutions for now.

> TypeScript extends JavaScript by adding types to the language.

https://www.typescriptlang.org/

Solution 9 - Javascript

It can easilly be done with ArgueJS:

function myFunction ()
{
  arguments = __({myDate: Date, myString: String});
  // do stuff
};

Solution 10 - Javascript

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

Solution 11 - Javascript

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

Solution 12 - Javascript

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
}

Solution 13 - Javascript

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

Solution 14 - Javascript

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondmrView Question on Stackoverflow
Solution 1 - JavascriptpronvitView Answer on Stackoverflow
Solution 2 - JavascripteolssonView Answer on Stackoverflow
Solution 3 - JavascriptDan DascalescuView Answer on Stackoverflow
Solution 4 - JavascriptRenaudView Answer on Stackoverflow
Solution 5 - JavascriptundefinedView Answer on Stackoverflow
Solution 6 - JavascriptcolxiView Answer on Stackoverflow
Solution 7 - JavascriptVNOView Answer on Stackoverflow
Solution 8 - JavascriptxgqfrmsView Answer on Stackoverflow
Solution 9 - JavascriptzVictorView Answer on Stackoverflow
Solution 10 - JavascriptPouria MoosaviView Answer on Stackoverflow
Solution 11 - JavascriptfiderView Answer on Stackoverflow
Solution 12 - Javascriptphil294View Answer on Stackoverflow
Solution 13 - JavascriptLouTView Answer on Stackoverflow
Solution 14 - JavascriptCarsonView Answer on Stackoverflow