Establecer tipo para parámetros de función?

161

¿Hay alguna manera de permitir que una función de JavaScript sepa que cierto parámetro es de cierto tipo?

Ser capaz de hacer algo como esto sería perfecto:

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

¡Gracias!

Actualización : Siendo que la respuesta es un rotundo "no", si quiero que me myDatetraten como una fecha (para llamar a las funciones de fecha), tengo que convertirla como una fecha dentro de la función o establecer una nueva variable de escriba Fecha?

dmr
fuente
1
No en un sentido integrado y general. Puede hacerlo usted mismo, a mano, pero luego depende de cómo defina "de cierto tipo"
hugomg
2
Tampoco hay clases en JavaScript, por lo que no hay Date, solo object.
deshacerse del
@dmr, eso no es una clase. DateEs una función. Eche un vistazo a stackoverflow.com/questions/1646698/… para obtener más información sobre la newpalabra clave JavaScript . Además, como no hay clases, no hay casting. Simplemente puede llamar a las funciones que desee. Si el objeto los contiene, se ejecutarán, de lo contrario obtendrá un error.
deshacerse del
2
Es un viejo sin embargo nadie ha mencionado texto mecanografiado
kit

Respuestas:

180

No, JavaScript no es un lenguaje de tipo estático. A veces puede que necesite verificar manualmente los tipos de parámetros en el cuerpo de su función.

pronvit
fuente
180
Bendición y una maldición.
Jeffrey Sweeney
40
@JeffreySweeney tampoco tiene PHP estáticamente escrito. Pero tiene la opción de hacer sugerencias de tipo en php. ¿Alguna vez has visto una gran aplicación de backend de nodejs? exactamente, cada función tiene argumentos, y NO tienes idea de qué es cada argumento. Estamos hablando de miles de argumentos y al leer, debe leer todo el código, y el código completo de la persona que llama y de la persona que llama, etc. ¿Bendición? ciertamente debes estar bromeando.
Toskan
14
aparte de criticar a alguien que no llama a ninguna característica que permita insinuar el tipo una bendición, tal vez quiera señalar typecript : typescriptlang.org básicamente EM6 + tipo insinuación
Toskan
23
@JeffreySweeney No es una bendición. Es cáncer
Robo Robok
1
@Toskan No diría que no es una bendición. He estado usando JavaScript durante cuatro años, y esa es solo la naturaleza de algunos idiomas. El conjunto de lenguajes de programación debe variar de tipeado débil a tipeado fuertemente de la misma manera que debe abarcar desde nivel bajo a nivel alto. Además, JavaScript proporciona las palabras clave instanceofy typeofpara ayudar en esto. Aunque esto requiere más código, tal vez sea el desarrollador quien elija JavaScript como el idioma para algo que depende en gran medida de los tipos. ¿En cuanto a las enormes aplicaciones de backend de nodejs? Creo que debería ser de sentido común.
Marvin
82

No en JavaScript, pero usando el modo avanzado del compilador de cierre de Google puede hacer eso:

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

Ver http://code.google.com/closure/compiler/docs/js-for-compiler.html

Eolsson
fuente
1
esto también funciona con / habilita Eclipse JavaScript Editor - Vista de esquema y finalización de código . mientras que la foo( /*MyType*/ param )forma como se describe aquí también funciona: stackoverflow.com/a/31420719/1915920
Andreas Dietrich
Me doy cuenta de la antigüedad de esta pregunta, pero quería señalar que es honrada en IntelliJ. Respuesta muy subestimada aquí.
ChettDM
67

Si bien no puede informarle a JavaScript el idioma sobre los tipos, puede informar a su IDE sobre ellos, por lo que obtendrá una autocompletación mucho más útil.

Aquí hay dos formas de hacerlo:

  1. Use JSDoc , un sistema para documentar el código JavaScript en los comentarios. En particular, necesitará la @paramdirectiva :

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

    También puede usar JSDoc para definir tipos personalizados y especificarlos en las @paramdirectivas, pero tenga en cuenta que JSDoc no realizará ninguna verificación de tipo; Es solo una herramienta de documentación. Para verificar los tipos definidos en JSDoc, busque en TypeScript , que puede analizar etiquetas JSDoc .

  2. Use sugerencias de tipo especificando el tipo justo antes del parámetro en a
    /* comment */:

    Sugerencia de tipo JavaScript en WebStorm

    Esta es una técnica bastante extendida, utilizada por ReactJS por ejemplo. Muy útil para parámetros de devoluciones de llamada pasados ​​a bibliotecas de terceros.

Mecanografiado

Para la verificación de tipo real, la solución más cercana es usar TypeScript, un superconjunto ( principalmente ) de JavaScript. Aquí está TypeScript en 5 minutos .

Dan Dascalescu
fuente
8
¿Cómo conseguir esto VSCode?
Anand Undavia el
2
Gracias. Aunque esto depende del IDE. Yo uso VI y no funcionará.
negrotico19
@ negrotico19: vies un editor excesivamente abusado, no un IDE. Puedes hacer muchas cosas vi, así como puedes hacer videos musicales en Excel . ¿Buena idea? Probablemente no. Use la herramienta adecuada para el trabajo.
Dan Dascalescu
23

Consulte la nueva biblioteca Flow de Facebook, "un verificador de tipos estático, diseñado para encontrar errores de tipo en programas JavaScript"

Definición:

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

Comprobación de tipo:

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

Y aquí está cómo ejecutarlo .

Renaud
fuente
¿Cómo agregar una definición de tipo si x era un tipo de fecha? es decir, foo (x: Fecha): cadena {}. ¿Esta es la manera correcta de hacerlo?
Aakash Sigdel
12

No, en su lugar, deberías hacer algo como esto según tus necesidades:

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

Puede implementar un sistema que maneje las verificaciones de tipo automáticamente , utilizando un contenedor en su función.

Con este enfoque, puede crear un completo declarative type check systemque gestionará por usted las verificaciones de tipo. Si está interesado en profundizar en este concepto, consulte la biblioteca Functyped

La siguiente implementación ilustra la idea principal, de una manera simplista, pero operativa :

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

Editar: Siete años después, esta respuesta todavía recibe votos positivos ocasionales. Está bien si está buscando la verificación en tiempo de ejecución, pero ahora recomendaría la verificación de tipos en tiempo de compilación usando TypeScript o posiblemente Flow. Ver https://stackoverflow.com/a/31420719/610585 arriba para obtener más información.

Respuesta original:

No está integrado en el lenguaje, pero puede hacerlo usted mismo con bastante facilidad. La respuesta de Vibhu es lo que consideraría la forma típica de verificación de tipos en Javascript. Si desea algo más generalizado, intente algo como esto: (solo un ejemplo para comenzar)

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
indefinido
fuente
5

Se puede hacer fácilmente con ArgueJS :

function myFunction ()
{
  arguments = __({myDate: Date, myString: String});
  // do stuff
};
zVictor
fuente
2
Parece una gran biblioteca. Felicidades
FRD
1

Usar typeofo 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
fuente
0

Tal vez una función auxiliar como esta. Pero si te ves usando tal sintaxis regularmente, probablemente deberías cambiar a Typecript.

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
}
phil294
fuente
0

He estado pensando en esto también. Desde un fondo C, puede simular tipos de código de retorno de función, así como, tipos de parámetros, usando algo como lo siguiente:

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

El número antes de la función de llamada devuelve un tipo de número independientemente del tipo del valor real devuelto, como se ve en la segunda llamada donde typeof rc = número pero el valor es NaN

El console.log para lo anterior es:

1st call
typeof rc: number   rc: 1
2nd call
Parm 1 not correct type
typeof rc: number   rc: NaN
Patán
fuente