Définir le type des paramètres de fonction?

162

Existe-t-il un moyen de faire savoir à une fonction javascript qu'un certain paramètre est d'un certain type?

Être capable de faire quelque chose comme ça serait parfait:

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

Je vous remercie!

Mise à jour : étant donné que la réponse est un «non» retentissant, si je veux myDateêtre traité comme une date (afin d'appeler des fonctions de date dessus), je dois la convertir en date à l'intérieur de la fonction ou définir une nouvelle variable de tapez la date?

dmr
la source
1
Pas dans un sens intégré et général. Vous pouvez le faire vous-même, à la main, mais cela dépend de la façon dont vous définissez "d'un certain type"
hugomg
2
Il n'y a pas non plus de classes en JavaScript, donc il n'y en a pas Date, seulement object.
débarrasser
@dmr, ce n'est pas une classe. Dateest une fonction. Jetez un œil à stackoverflow.com/questions/1646698/… pour en savoir plus sur le newmot-clé JavaScript . De plus, comme il n'y a pas de classes, il n'y a pas de casting. Vous pouvez simplement appeler les fonctions souhaitées. Si l'objet les contient, ils s'exécuteront, sinon vous obtiendrez une erreur.
débarrasser
2
C'est un vieux mais personne n'a mentionné dactylographié
kit

Réponses:

181

Non, JavaScript n'est pas un langage de type statique. Parfois, vous devrez peut-être vérifier manuellement les types de paramètres dans votre corps de fonction.

pronvit
la source
180
Bénédiction et malédiction.
Jeffrey Sweeney
40
@JeffreySweeney n'est pas non plus typé de manière statique. Mais vous avez la possibilité de faire des conseils de type en php. Avez-vous déjà examiné une grande application backend nodejs? exactement, chaque fonction a des arguments, et vous n'avez AUCUNE idée de ce qu'est chaque argument. On parle de milliers d'arguments et lors de la lecture, il faut lire le code entier, et le code entier de l'appelant et de son appelant, etc. Bénédiction? vous devez certainement plaisanter.
Toskan
14
en dehors de dénigrer quelqu'un qui n'appelle aucune fonctionnalité permettant de taper suggérant une bénédiction, je pourrais vouloir souligner dactylographié: typescriptlang.org essentiellement un indice de type EM6 +
Toskan
23
@JeffreySweeney Ce n'est pas une bénédiction. C'est le cancer.
Robo Robok
1
@Toskan Je ne dirais pas que ce n'est pas une bénédiction. J'utilise JavaScript depuis quatre ans maintenant, et c'est juste la nature de certains langages. L'ensemble des langages de programmation devrait aller de faiblement typé à fortement typé de la même manière qu'il devrait aller du bas niveau au haut niveau. De plus, JavaScript fournit les mots clés instanceofet typeofpour vous aider. Bien que cela prenne plus de code, c'est peut-être au développeur de choisir JavaScript comme langage pour quelque chose qui dépend en grande partie des types. Quant aux énormes applications backend de nodejs? Je pense que cela devrait être du bon sens.
Marvin
82

Pas en javascript mais en utilisant le mode avancé de Google Closure Compiler, vous pouvez le faire:

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

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

Eolsson
la source
1
cela fonctionne également avec / active l' éditeur JavaScript Eclipse - Vue d'ensemble et achèvement de code . alors que la foo( /*MyType*/ param )manière décrite ici fonctionne également: stackoverflow.com/a/31420719/1915920
Andreas Dietrich
Je me rends compte de l'âge de cette question mais je tenais à souligner qu'elle est honorée dans IntelliJ. Réponse très sous-estimée ici.
ChettDM
67

Bien que vous ne puissiez pas informer JavaScript du langage sur les types, vous pouvez en informer votre IDE, ce qui vous permet d'obtenir une saisie semi-automatique beaucoup plus utile.

Voici deux façons de procéder:

  1. Utilisez JSDoc , un système de documentation du code JavaScript dans les commentaires. En particulier, vous aurez besoin de la @paramdirective :

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

    Vous pouvez également utiliser JSDoc pour définir des types personnalisés et les spécifier dans les @paramdirectives, mais notez que JSDoc ne fera aucune vérification de type; ce n'est qu'un outil de documentation. Pour vérifier les types définis dans JSDoc, regardez dans TypeScript , qui peut analyser les balises JSDoc .

  2. Utilisez l'indication de type en spécifiant le type juste avant le paramètre dans un
    /* comment */:

    Indication de type JavaScript dans WebStorm

    C'est une technique assez répandue, utilisée par ReactJS par exemple. Très pratique pour les paramètres des rappels passés à des bibliothèques tierces.

Manuscrit

Pour la vérification de type réelle, la solution la plus proche consiste à utiliser TypeScript, un sur-ensemble ( principalement ) de JavaScript. Voici TypeScript en 5 minutes .

Dan Dascalescu
la source
8
Comment faire ça VSCode?
Anand Undavia
2
Merci. Même si cela dépend de l'IDE. J'utilise VI et ne fonctionnera pas.
negrotico19
@ negrotico19: viest un éditeur abusé, pas un IDE. Vous pouvez faire beaucoup de choses vi, tout comme vous pouvez créer des clips vidéo dans Excel . Bonne idée? Probablement pas. Utilisez le bon outil pour le travail.
Dan Dascalescu le
23

Découvrez la nouvelle bibliothèque Flow de Facebook, "un vérificateur de type statique, conçu pour trouver les erreurs de type dans les programmes JavaScript"

Définition:

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

Vérification de type:

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

Et voici comment l'exécuter .

Renaud
la source
comment ajouter une définition de type si x était un type de date? ie toto (x: Date): chaîne {}. Est-ce que c'est la bonne façon de le faire?
Aakash Sigdel
12

Non, vous devrez plutôt faire quelque chose comme ça en fonction de vos besoins:

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

Vous pouvez implémenter un système qui gère automatiquement les vérifications de type , en utilisant un wrapper dans votre fonction.

Avec cette approche, vous pouvez construire un système complet declarative type check systemqui gérera pour vous les vérifications de type. Si vous souhaitez approfondir ce concept, consultez la bibliothèque Functyped

L'implémentation suivante illustre l'idée principale, d'une manière simpliste mais opérationnelle :

/*
 * 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
la source
11

Edit: Sept ans plus tard, cette réponse reçoit encore des votes positifs occasionnels. C'est bien si vous recherchez une vérification à l'exécution, mais je recommanderais maintenant la vérification de type à la compilation à l'aide de Typescript, ou éventuellement de Flow. Voir https://stackoverflow.com/a/31420719/610585 ci-dessus pour en savoir plus.

Réponse originale:

Ce n'est pas intégré à la langue, mais vous pouvez le faire vous-même assez facilement. La réponse de Vibhu est ce que je considérerais comme la méthode typique de vérification de type en Javascript. Si vous voulez quelque chose de plus généralisé, essayez quelque chose comme ceci: (juste un exemple pour commencer)

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
indéfini
la source
5

Cela peut facilement être fait avec ArgueJS :

function myFunction ()
{
  arguments = __({myDate: Date, myString: String});
  // do stuff
};
zVictor
la source
2
ressemble à une grande bibliothèque. félicitations.
FRD
1

Utilisez typeofou 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
la source
0

Peut-être une fonction d'aide comme celle-ci. Mais si vous vous voyez utiliser régulièrement une telle syntaxe, vous devriez probablement passer à 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
}
phil294
la source
0

J'y ai pensé aussi. À partir d'un arrière-plan C, vous pouvez simuler des types de code de retour de fonction, ainsi que des types de paramètres, en utilisant quelque chose comme ce qui suit:

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

Le nombre avant la fonction appelante renvoie un type Number quel que soit le type de la valeur réelle renvoyée, comme vu dans le 2ème appel où typeof rc = number mais la valeur est NaN

le console.log pour ce qui précède est:

1st call
typeof rc: number   rc: 1
2nd call
Parm 1 not correct type
typeof rc: number   rc: NaN
Voyou
la source
0

TypeScript est l'une des meilleures solutions pour le moment

TypeScript étend JavaScript en ajoutant des types au langage.

https://www.typescriptlang.org/

xgqfrms
la source