【问题标题】:Set type for function parameters?设置函数参数的类型?
【发布时间】:2012-01-14 12:14:40
【问题描述】:

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

能够做这样的事情就完美了:

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

谢谢!

更新:如果我希望 myDate 被视为日期(以便在其上调用日期函数),那么答案是响亮的“否”,我必须强制转换将它作为函数内部的日期还是为其设置一个 Date 类型的新变量?

【问题讨论】:

  • 不是内置的和一般意义上的。您可以自己手动完成,但这取决于您如何定义“特定类型”
  • JavaScript中也没有类,所以没有Date,只有object
  • @dmr,那不是一门课。 Date 是一个函数。查看 stackoverflow.com/questions/1646698/… 以了解有关 JavaScript new 关键字的更多信息。此外,由于没有类,因此没有强制转换。你可以简单地调用你想要的函数。如果对象包含它们,它们将运行,否则会出错。
  • 这是一个旧的但是没有人提到打字稿

标签: javascript function


【解决方案1】:

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

【讨论】:

  • @JeffreySweeney PHP 也不是静态类型的。但是您可以选择在 php.ini 中进行类型提示。你有没有看过 big nodejs 后端应用程序?确切地说,每个函数都有参数,你不知道每个参数是什么。我们正在谈论成千上万的参数,在阅读时,您必须阅读整个代码,以及调用者及其调用者的整个代码等。祝福?你肯定是在开玩笑。
  • 除了抨击那些没有功能允许类型提示的人之外,我可能想指出打字稿:typescriptlang.org 基本上是 EM6 + 类型提示
  • @JeffreySweeney 这不是祝福。这是癌症。
  • @Toskan 我不会说这不是一种祝福。我已经使用 JavaScript 四年了,这只是某些语言的本质。编程语言集应该从弱类型到强类型,就像它应该从低级到高级一样。此外,JavaScript 提供了 instanceoftypeof 关键字来帮助实现这一点。尽管这会占用更多代码,但可能是开发人员选择 JavaScript 作为主要依赖于类型的语言的语言。至于庞大的 nodejs 后端应用程序?我认为这应该是常识。
  • 遗憾的是,@Marvin,开发人员并不总是能像他们希望的那样控制他们使用哪种语言。例如,如果您想为 Google 表格制作一个脚本,那么(据我所知)它在到达 Google 的末尾时必须是 JS。
【解决方案2】:

不是在 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

【讨论】:

  • 这也适用于/启用 Eclipse JavaScript Editor - Outline ViewCode Completion。而这里描述的foo( /*MyType*/ param ) 方式也适用:stackoverflow.com/a/31420719/1915920
  • 我知道这个问题有多老了,但我想指出它在 IntelliJ 中很受尊重。这里的答案被低估了。
  • 在 VSCode 中也有使用。
【解决方案3】:

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

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

  1. 使用JSDoc,一个用于在 cmets 中记录 JavaScript 代码的系统。特别是,您需要@param directive:

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

    您也可以使用 JSDoc 到 define custom types 并在 @param 指令中指定它们,但请注意 JSDoc 不会进行任何类型检查;它只是一个文档工具。要检查 JSDoc 中定义的类型,请查看 TypeScript,它可以是 parse JSDoc tags

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

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

打字稿

对于实际的类型检查,最接近的解决方案是使用 TypeScript,它是 JavaScript 的 (mostly) 超集。这是TypeScript in 5 minutes

【讨论】:

  • 如何在VSCode获得这个?
  • 谢谢。即使这取决于 IDE。我用 VI 不行。
  • @negrotico19: vi 是一个过度滥用的编辑器,而不是一个 IDE。你可以在vi 中做很多事情,就像你可以在music videos in Excel 中做的一样。好主意?可能不是。为工作使用正确的工具。
  • @AnandUndavia 对于 VSCode,据我所知,您可以使用选项 1,但只能使用 ESLint 扩展名。顺便说一下,很抱歉(非常)迟回复。
【解决方案4】:

查看来自 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

这里是how to run it

【讨论】:

  • 如果 x 是日期类型,如何添加类型定义?即 foo(x: Date) : string { }。这是正确的做法吗?
【解决方案5】:

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

通过这种方法,您可以构建一个完整的declarative type check system,它将为您管理类型检查。 如果您有兴趣更深入地了解这个概念,请查看Functyped library

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

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

【讨论】:

    【解决方案6】:

    编辑:七年后,这个答案仍然偶尔得到支持。如果您正在寻找运行时检查,那很好,但我现在建议使用 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
    

    【讨论】:

      【解决方案7】:

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

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

      【讨论】:

        【解决方案8】:

        TypeScript 是目前最好的解决方案之一。

        TypeScript 通过向语言添加类型来扩展 JavaScript。

        https://www.typescriptlang.org/

        【讨论】:

          【解决方案9】:

          ArgueJS 可以轻松完成:

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

          【讨论】:

          • 看起来像一个很棒的图书馆。恭喜。
          【解决方案10】:

          说明

          我不确定我的回答是否是对原始问题的直接回答,但我想很多人来这里只是为了找到一种方法来告诉他们的 IDE 理解类型,我'会分享我的发现。

          如果您想告诉 VSCode 了解您的类型,请执行以下操作。请注意js runtime 和NodeJS 根本不关心这些类型。

          解决方案

          1- 创建一个以.d.ts 结尾的文件:例如:index.d.ts。您可以在另一个文件夹中创建此文件。例如:types/index.d.ts
          2-假设我们想要一个名为view的函数。将这些行添加到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- 在项目的根目录中创建一个jsconfig.json 文件。 (似乎只需创建这个文件就足以让 VSCode 搜索您的类型)。

          多一点

          现在假设我们想将此类型添加到另一个库类型中。 (根据我自己的情况)。我们可以使用一些ts 关键字。只要 VSCode 理解ts,我们就没有问题。
          例如,如果您想将这个 view 函数添加到来自 expressjs 的响应中,请将 index.d.ts 文件更改如下:

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

          结果

          【讨论】:

            【解决方案11】:

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

            【讨论】:

              【解决方案12】:

              也许是这样的辅助函数。但如果你发现自己经常使用这样的语法,你可能应该改用 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
              }
              

              【讨论】:

                【解决方案13】:

                我也一直在考虑这个问题。在 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
                

                【讨论】:

                  【解决方案14】:

                  我假设您允许 IDE 帮助您;那么下面的答案可能会对你有所帮助。

                  IDE:jetbrains/Golang 如果你的 IDE 不是这个也没关系。我相信所有支持 JSDoc 的 IDE 都能满足你的大部分要求。

                  它可以很好地显示JSDoc

                  演示

                  我的/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")
                  

                  有用的 JSDoc 文档

                  其他链接

                  【讨论】:

                    猜你喜欢
                    • 2021-04-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-02-28
                    • 2021-09-11
                    • 1970-01-01
                    • 2019-08-30
                    • 2018-10-01
                    相关资源
                    最近更新 更多