Typ für Funktionsparameter einstellen?

161

Gibt es eine Möglichkeit, eine Javascript-Funktion wissen zu lassen, dass ein bestimmter Parameter von einem bestimmten Typ ist?

In der Lage zu sein, so etwas zu tun, wäre perfekt:

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

Danke dir!

Update : Da die Antwort ein klares "Nein" ist myDate, muss ich sie als Datum in die Funktion umwandeln oder eine neue Variable von setzen , wenn ich als Datum behandelt werden möchte (um Datumsfunktionen darauf aufzurufen) Typ Datum dazu?

dmr
quelle
1
Nicht im eingebauten und allgemeinen Sinne. Sie können dies selbst von Hand tun, aber dann hängt es davon ab, wie Sie "eines bestimmten Typs" definieren
hugomg
2
Darüber hinaus gibt es keine Klassen in JavaScript, so gibt es keine Date, nur object.
loswerden
@ Radu: Was ist mit dieser Mozilla Develop Network-Seite ?
dmr
@dmr, das ist keine Klasse. Dateist eine Funktion. Weitere Informationen zum JavaScript- newSchlüsselwort finden Sie unter stackoverflow.com/questions/1646698/… . Da es keine Klassen gibt, gibt es auch kein Casting. Sie können einfach die gewünschten Funktionen aufrufen. Wenn das Objekt sie enthält, werden sie ausgeführt, andernfalls wird eine Fehlermeldung angezeigt.
los
2
Es ist ein altes, aber niemand erwähnte Typoskript
Kit

Antworten:

179

Nein, JavaScript ist keine statisch typisierte Sprache. Manchmal müssen Sie möglicherweise die Parametertypen in Ihrem Funktionskörper manuell überprüfen.

pronvit
quelle
179
Segen und ein Fluch.
Jeffrey Sweeney
39
@JeffreySweeney PHP ist auch nicht statisch typisiert. Aber Sie haben die Möglichkeit, Tipphinweise in PHP zu machen. Haben Sie sich jemals eine große Node-Backend-Anwendung angesehen? Genau, jede Funktion hat Argumente, und Sie haben KEINE Ahnung, was jedes Argument ist. Wir sprechen über Tausende von Argumenten und beim Lesen müssen Sie den gesamten Code und den gesamten Code des Anrufers und seines Anrufers usw. lesen. Segen? Sie müssen sicherlich scherzen.
Toskan
14
abgesehen von jemand bashing , die keine Funktion , mit der Art , die einen Segen ruft Hinting Ich möchte vielleicht Typoskript hinweisen: typescriptlang.org grundsätzlich Hinting + Typ EM6
Toskan
22
@ JeffreySweeney Es ist kein Segen. Es ist Krebs.
Robo Robok
1
@Toskan Ich würde nicht sagen, dass es kein Segen ist. Ich benutze jetzt seit vier Jahren JavaScript, und das ist nur die Natur einiger Sprachen. Der Satz von Programmiersprachen sollte von schwach bis stark typisiert reichen, genauso wie er von niedrig bis hoch reichen sollte. Darüber hinaus bietet JavaScript die Schlüsselwörter instanceofund typeof, um dies zu unterstützen. Obwohl dies mehr Code beansprucht, liegt es möglicherweise am Entwickler, JavaScript als Sprache für etwas zu wählen, das weitgehend vom Typ abhängt. Wie für riesige NodeJS Backend-Anwendungen? Ich denke, es sollte gesunder Menschenverstand sein.
Marvin
81

Nicht in Javascript selbst, aber mit dem erweiterten Modus von Google Closure Compiler können Sie Folgendes tun:

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

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

Eolsson
quelle
1
Dies funktioniert auch mit / aktiviert den Eclipse JavaScript Editor - Gliederungsansicht und Code-Vervollständigung . wohingegen der foo( /*MyType*/ param )hier beschriebene Weg auch funktioniert: stackoverflow.com/a/31420719/1915920
Andreas Dietrich
Mir ist klar, wie alt diese Frage ist, aber ich wollte darauf hinweisen, dass sie in IntelliJ geehrt wird. Sehr unterbewertete Antwort hier.
ChettDM
67

Während Sie JavaScript die Sprache nicht über Typen informieren können, können Sie Ihre IDE darüber informieren, sodass Sie eine viel nützlichere automatische Vervollständigung erhalten.

Hier sind zwei Möglichkeiten, dies zu tun:

  1. Verwenden Sie JSDoc , ein System zum Dokumentieren von JavaScript-Code in Kommentaren. Insbesondere benötigen Sie die @paramRichtlinie :

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

    Sie können JSDoc auch verwenden, um benutzerdefinierte Typen zu definieren und diese in @paramAnweisungen anzugeben. Beachten Sie jedoch, dass JSDoc keine Typprüfung durchführt. Es ist nur ein Dokumentationswerkzeug. Um die in JSDoc definierten Typen zu überprüfen, schauen Sie in TypeScript nach , mit dem JSDoc-Tags analysiert werden können .

  2. Verwenden Sie Typhinweise, indem Sie den Typ direkt vor dem Parameter in a angeben
    /* comment */:

    Hinweise auf JavaScript-Typen in WebStorm

    Dies ist eine ziemlich weit verbreitete Technik, die beispielsweise von ReactJS verwendet wird . Sehr praktisch für Parameter von Rückrufen, die an Bibliotheken von Drittanbietern übergeben werden.

Typoskript

Für die eigentliche Typprüfung besteht die beste Lösung darin, TypeScript zu verwenden, eine ( meistens ) Obermenge von JavaScript. Hier ist TypeScript in 5 Minuten .

Dan Dascalescu
quelle
8
Wie komme ich dazu VSCode?
Anand Undavia
2
Vielen Dank. Auch wenn dies von der IDE abhängt. Ich benutze VI und wird nicht funktionieren.
Negrotico19
@ negrotico19: viist ein übermäßig missbrauchter Editor, keine IDE. Sie können eine Menge Dinge erledigen vi, genauso wie Sie Musikvideos in Excel erstellen können . Gute Idee? Wahrscheinlich nicht. Verwenden Sie das richtige Werkzeug für den Job.
Dan Dascalescu
23

Schauen Sie sich die neue Flow- Bibliothek von Facebook an, "eine statische Typprüfung, mit der Typfehler in JavaScript-Programmen gefunden werden können".

Definition:

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

Typprüfung:

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

Und hier erfahren Sie, wie Sie es ausführen .

Renaud
quelle
Wie füge ich eine Typdefinition hinzu, wenn x ein Datumstyp war? dh foo (x: Datum): string {}. Ist das der richtige Weg?
Aakash Sigdel
12

Nein, stattdessen müssten Sie je nach Ihren Anforderungen Folgendes tun:

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

Sie können ein System implementieren, das die Typprüfungen automatisch durchführt , indem Sie einen Wrapper in Ihrer Funktion verwenden.

Mit diesem Ansatz können Sie eine vollständige declarative type check systemDatei erstellen , die die Typprüfungen für Sie verwaltet. Wenn Sie sich dieses Konzept genauer ansehen möchten , überprüfen Sie die Bibliothek Functyped

Die folgende Implementierung veranschaulicht die Hauptidee auf vereinfachte, aber operative Weise :

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

Edit: Sieben Jahre später erhält diese Antwort immer noch gelegentlich positive Stimmen. Es ist in Ordnung, wenn Sie nach einer Laufzeitprüfung suchen, aber ich würde jetzt empfehlen, die Typprüfung zur Kompilierungszeit mit Typescript oder möglicherweise Flow zu überprüfen. Weitere Informationen finden Sie oben unter https://stackoverflow.com/a/31420719/610585 .

Ursprüngliche Antwort:

Es ist nicht in die Sprache eingebaut, aber Sie können es ganz einfach selbst tun. Vibhus Antwort ist die typische Art der Typprüfung in Javascript. Wenn Sie etwas allgemeineres möchten, versuchen Sie Folgendes: (nur ein Beispiel, um Ihnen den Einstieg zu erleichtern)

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
nicht definiert
quelle
5

Mit ArgueJS geht das ganz einfach :

function myFunction ()
{
  arguments = __({myDate: Date, myString: String});
  // do stuff
};
zVictor
quelle
2
sieht aus wie eine tolle Bibliothek. Glückwunsch.
FRD
1

Verwenden Sie typeofoder 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
quelle
0

Vielleicht funktioniert so ein Helfer. Wenn Sie jedoch feststellen, dass Sie diese Syntax regelmäßig verwenden, sollten Sie wahrscheinlich zu Typescript wechseln.

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
quelle
0

Ich habe auch darüber nachgedacht. Auf einem C-Hintergrund können Sie Funktionsrückgabecodetypen sowie Parametertypen mithilfe der folgenden Methoden simulieren:

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

Die Nummer vor der aufrufenden Funktion gibt einen Nummerntyp zurück, unabhängig vom Typ des tatsächlich zurückgegebenen Werts, wie im zweiten Aufruf gezeigt, wobei typeof rc = number ist, der Wert jedoch NaN ist

Das console.log für das oben Genannte lautet:

1st call
typeof rc: number   rc: 1
2nd call
Parm 1 not correct type
typeof rc: number   rc: NaN
Lümmel
quelle
0

TypeScript ist derzeit eine der besten Lösungen

TypeScript erweitert JavaScript um Typen zur Sprache.

https://www.typescriptlang.org/

xgqfrms
quelle