设置功能参数的类型?


161

有没有办法让javascript函数知道某个参数属于某种类型?

能够做这样的事情将是完美的:

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

谢谢!

更新:答案是肯定的“否”,如果我想myDate被视为日期(以便在其上调用日期函数),则必须将其强制转换为日期,或者在函数中设置一个新变量输入日期吗?


1
不是内在的和一般的意义。您可以手动完成此操作,但这取决于您如何定义“某种类型”
hugomg 2011年

2
还有没有课在JavaScript中,所以没有Date,只有object
摆脱


@dmr,那不是一堂课。Date是一个功能。查看stackoverflow.com/questions/1646698/…,以了解有关JavaScript new关键字的更多信息。另外,由于没有类,所以没有强制转换。您可以简单地调用所需的函数。如果对象包含它们,它们将运行,否则您将得到一个错误。
摆脱

2
这是一本古老的书,但是没有人提到打字稿
套件

Answers:


180

不,JavaScript不是静态类型的语言。有时您可能需要手动检查函数主体中的参数类型。


180
祝福和诅咒。
Jeffrey Sweeney

40
@JeffreySweeney也不是PHP的静态类型。但是您可以选择在php中进行类型提示。您是否看过大型的 nodejs后端应用程序?确切地说,每个函数都有参数,并且您不知道每个参数是什么。我们正在谈论成千上万个参数,在阅读时,您必须阅读整个代码,以及调用者及其调用者的整个代码,等等。你一定是在开玩笑。
Toskan

14
除了扑打没有呼叫功能的人以外,我还想指出打字稿:typescriptlang.org基本上是EM6 +类型暗示
Toskan

23
@JeffreySweeney这不是祝福。是癌症
Robo Robok

1
@Toskan我不会说这不是祝福。我已经使用JavaScript四年了,那只是某些语言的本质。编程语言集应从弱类型到强类型,其范围应从低级到高级。另外,JavaScript提供了instanceoftypeof关键字来帮助实现这一点。尽管这占用了更多的代码,但也许是由开发人员选择JavaScript作为主要依赖类型的语言。至于庞大的nodejs后端应用程序?我认为应该是常识。
马文(Marvin)

81

不使用JavaScript本身,而是使用Google Closure Compiler的高级模式,您可以这样做:

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

请参阅http://code.google.com/closure/compiler/docs/js-for-compiler.html


1
这也可用于/启用Eclipse JavaScript编辑器 - 大纲视图代码完成。而foo( /*MyType*/ param )此处描述的方法也有效:stackoverflow.com/a/31420719/1915920
Andreas Dietrich

我意识到这个问题有多久了,但我想指出,它在IntelliJ中得到了认可。非常低估的答案在这里。
ChettDM

67

虽然您无法向JavaScript告知有关类型的语言,但是可以向您的IDE告知它们有关类型的信息,因此您可以获得更多有用的自动完成功能。

有两种方法可以做到这一点:

  1. 使用JSDoc,该系统用于在注释中记录JavaScript代码。特别是,您将需要以下@param指令

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

    您还可以使用JSDoc 定义自定义类型,并在@param指令中指定自定义类型,但请注意,JSDoc不会进行任何类型检查。它只是一个文档工具。要检查JSDoc中定义的类型,请查看TypeScript,它可以解析JSDoc标签

  2. 通过在类型的参数之前指定类型来使用类型提示
    /* comment */

    WebStorm中的JavaScript类型提示

    这是一种相当普遍的技术,例如被ReactJS使用。对于传递给第三方库的回调参数非常方便。

打字稿

对于实际的类型检查,最接近的解决方案是使用TypeScript(JavaScript 的(主要是)超集)。这是5分钟内TypeScript


8
如何得到这个VSCode
Anand Undavia

2
谢谢。即使这取决于IDE。我使用VI,无法正常工作。
negrotico18年

@ negrotico19:vi是一个滥用过度的编辑器,而不是IDE。vi就像在Excel中制作音乐视频一样,您可以做很多事情。好主意?可能不是。使用正确的工具完成工作。
Dan Dascalescu

23

查看新 从Facebook中 Flow库,“静态类型检查器,旨在在JavaScript程序中查找类型错误”

定义:

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

类型检查:

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

这是如何运行它


如果x是日期类型,如何添加类型定义?即foo(x:Date):字符串{}。这是正确的方法吗?
Aakash Sigdel '16

12

不,相反,您需要根据自己的需要执行以下操作:

function myFunction(myDate, myString) {
  if(arguments.length > 1 && typeof(Date.parse(myDate)) == "number" && typeof(myString) == "string") {
    //Code here
  }
}

12

您可以使用功能中的包装器来实现一个自动处理类型检查的系统。

使用这种方法,您可以构建一个declarative type check system可以为您管理类型检查的完整文件。如果您有兴趣深入了解此概念,请检查Functyped库

以下实现以简单但可操作的方式说明了主要思想:

/*
 * 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


11

编辑:七年后,这个答案仍然偶尔得到支持。如果您正在寻找运行时检查,那很好,但是我现在建议使用Typescript或可能的Flow进行编译时类型检查。参见https://stackoverflow.com/a/31420719/610585更多信息,上面的。

原始答案:

它不是语言内置的内容,但是您可以轻松地自己完成。Vibhu的答案是我认为Javascript中类型检查的典型方法。如果您想要更一般化的内容,请尝试如下操作:(仅是示例,可以帮助您入门)

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


1

使用typeofinstanceof

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

0

也许像这样的辅助功能。但是,如果您发现自己定期使用此类语法,则可能应该切换到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
}

0

我也一直在考虑这个。在C背景中,您可以使用以下类似方法来模拟函数返回码类型以及参数类型:

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

调用函数之前的Number会返回Number类型,而与返回的实际值的类型无关,如第二次调用所示,其中typeof rc = number但值是NaN

上面的console.log是:

1st call
typeof rc: number   rc: 1
2nd call
Parm 1 not correct type
typeof rc: number   rc: NaN

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.