Impostare il tipo per i parametri della funzione?


161

C'è un modo per far sapere a una funzione javascript che un determinato parametro è di un certo tipo?

Essere in grado di fare qualcosa del genere sarebbe perfetto:

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

Grazie!

Aggiornamento : Essendo che la risposta è un "no" clamoroso se voglio myDateessere trattato come una data (per chiamare funzioni di data su di essa), devo lanciarlo come una data all'interno della funzione o impostare una nuova variabile di tipo Data ad esso?


1
Non in senso intrinseco e generale. Puoi farlo tu stesso, a mano, ma poi dipende da come definisci "di un certo tipo"
hugomg

2
Non ci sono anche classi in JavaScript, quindi non c'è Date, solo object.
sbarazzarsi del


@dmr, questa non è una classe. Dateè una funzione. Dai un'occhiata a stackoverflow.com/questions/1646698/… per saperne di più sulla newparola chiave JavaScript . Inoltre, poiché non ci sono classi, non esiste casting. Puoi semplicemente chiamare le funzioni che desideri. Se l'oggetto li contiene, verranno eseguiti, altrimenti verrà visualizzato un errore.
liberare il

2
È vecchio ma nessuno ha menzionato dattiloscritto
kit

Risposte:


180

No, JavaScript non è un linguaggio tipicamente statico. A volte potrebbe essere necessario controllare manualmente i tipi di parametri nel corpo della funzione.


180
Benedizione e maledizione.
Jeffrey Sweeney,

40
@JeffreySweeney non è nemmeno PHP tipizzato staticamente. Ma hai la possibilità di digitare il suggerimento in php. Hai mai visto un'applicazione backend di grandi nodi? esattamente, ogni funzione ha argomenti e NON hai idea di cosa sia ogni argomento. Stiamo parlando di migliaia di argomenti e durante la lettura, devi leggere l'intero codice e l'intero codice del chiamante e del suo chiamante, ecc. Benedizione? devi sicuramente scherzare.
Toskan,

14
oltre a colpire qualcuno che non chiama nessuna funzionalità che consente il suggerimento del tipo una benedizione, potrei voler evidenziare dattiloscritto: typescriptlang.org sostanzialmente EM6 + suggerimento sul tipo
Toskan

23
@JeffreySweeney Non è una benedizione. È il cancro.
Robo Robok,

1
@Toskan Non direi che non è una benedizione. Uso JavaScript da quattro anni ormai, ed è proprio la natura di alcune lingue. L'insieme dei linguaggi di programmazione dovrebbe variare da tipicamente debolmente a fortemente tipizzato nello stesso modo in cui dovrebbe variare da un livello basso a un livello alto. Inoltre, JavaScript fornisce le parole chiave instanceofe typeofper aiutare in questo. Anche se questo richiede più codice, forse è lo sviluppatore a scegliere JavaScript come lingua per qualcosa che dipende in gran parte dai tipi. Per quanto riguarda le enormi applicazioni di backend nodejs? Penso che dovrebbe essere il buonsenso.
Marvin,

82

Non in javascript, ma usando la modalità avanzata di Google Closure Compiler puoi farlo:

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

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


1
funziona anche con / abilita l' Editor JavaScript di Eclipse - Vista struttura e Completamento codice . considerando che foo( /*MyType*/ param )funziona anche come descritto qui: stackoverflow.com/a/31420719/1915920
Andreas Dietrich,

Mi rendo conto di quanti anni ha questa domanda, ma volevo sottolineare che è onorato in IntelliJ. Risposta molto sottostimata qui.
ChettDM,

67

Sebbene non sia possibile informare JavaScript della lingua sui tipi, è possibile informare l'IDE su di essi, in modo da ottenere un completamento automatico molto più utile.

Ecco due modi per farlo:

  1. Usa JSDoc , un sistema per documentare il codice JavaScript nei commenti. In particolare, avrai bisogno della @paramdirettiva :

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

    È inoltre possibile utilizzare JSDoc per definire tipi personalizzati e specificarli nelle @paramdirettive, ma si noti che JSDoc non eseguirà alcun controllo del tipo; è solo uno strumento di documentazione. Per verificare i tipi definiti in JSDoc, cerca in TypeScript , che può analizzare i tag JSDoc .

  2. Utilizzare il suggerimento del tipo specificando il tipo immediatamente prima del parametro in a
    /* comment */:

    Suggerimenti sul tipo JavaScript in WebStorm

    Questa è una tecnica piuttosto diffusa, usata ad esempio da ReactJS . Molto utile per i parametri di callback passati a librerie di terze parti.

Dattiloscritto

Per il controllo del tipo effettivo, la soluzione più vicina è utilizzare TypeScript, un superset ( principalmente ) di JavaScript. Ecco TypeScript in 5 minuti .


8
Come accenderlo VSCode?
Anand Undavia,

2
Grazie. Anche se questo dipende dall'IDE. Uso VI e non funzionerà.
negrotico19,

@ negrotico19: viè un editor eccessivamente abusato, non un IDE. Puoi fare un sacco di cose dentro vi, proprio come puoi fare video musicali in Excel . Buona idea? Probabilmente no. Usa lo strumento giusto per il lavoro.
Dan Dascalescu,

23

Scopri la nuova libreria Flow da Facebook, "un controllo di tipo statico, progettato per trovare errori di tipo nei programmi JavaScript"

Definizione:

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

Tipo di controllo:

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

Ed ecco come eseguirlo .


come aggiungere la definizione del tipo se x era un tipo di data? ovvero foo (x: Date): string {}. è questo il modo giusto di farlo?
Aakash Sigdel,

12

No, invece dovresti fare qualcosa del genere a seconda delle tue esigenze:

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

12

È possibile implementare un sistema che gestisce automaticamente i controlli del tipo , utilizzando un wrapper nella funzione.

Con questo approccio, puoi creare un completo declarative type check systemche gestirà per te i controlli del tipo. Se sei interessato a dare uno sguardo più approfondito a questo concetto, controlla la libreria di Functyped

La seguente implementazione illustra l'idea principale, in modo semplicistico, ma operativo :

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

Modifica: sette anni dopo, questa risposta ottiene ancora voti occasionali. Va bene se stai cercando il controllo del runtime, ma ora consiglierei il controllo del tipo in fase di compilazione utilizzando Typescript o eventualmente Flow. Vedi https://stackoverflow.com/a/31420719/610585 sopra per ulteriori informazioni.

Risposta originale:

Non è integrato nella lingua, ma puoi farlo da solo abbastanza facilmente. La risposta di Vibhu è quella che considererei il modo tipico di controllare i tipi in Javascript. Se vuoi qualcosa di più generalizzato, prova qualcosa del genere: (solo un esempio per iniziare)

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

5

Può facilmente essere fatto con ArgueJS :

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

2
sembra una grande biblioteca. congratulazioni.
FRD

1

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

0

Forse una funzione di supporto come questa. Ma se ti vedi ad usare questa sintassi regolarmente, probabilmente dovresti passare a 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

Ci ho pensato anche io. Da uno sfondo C, è possibile simulare i tipi di codice di ritorno della funzione, nonché i tipi di parametro, usando qualcosa di simile al seguente:

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

Il numero prima della funzione chiamante restituisce un tipo di numero indipendentemente dal tipo del valore effettivo restituito, come visto nella seconda chiamata in cui typeof rc = numero ma il valore è NaN

console.log per quanto sopra è:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.