Definir tipo para parâmetros de função?


161

Existe uma maneira de permitir que uma função javascript saiba que um determinado parâmetro é de um determinado tipo?

Ser capaz de fazer algo assim seria perfeito:

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

Obrigado!

Atualização : Sendo a resposta um retumbante "não", se eu quiser myDateser tratado como uma data (para chamar funções de data), preciso defini-la como uma data dentro da função ou definir uma nova variável de tipo Data para ele?


1
Não no sentido interno e geral. Você pode fazer isso sozinho, com a mão, mas, em seguida, isso depende de como você define "de um certo tipo"
hugomg

2
Também não há classes em JavaScript, portanto não há Dateapenas object.
livrar


@ DMR, isso não é uma classe. Dateé uma função. Dê uma olhada em stackoverflow.com/questions/1646698/… para descobrir mais sobre a newpalavra-chave JavaScript . Além disso, como não há classes, não há transmissão. Você pode simplesmente chamar as funções que deseja. Se o objeto os contiver, eles serão executados; caso contrário, você receberá um erro.
livrar

2
É um velho no entanto ninguém mencionou typescript
kit

Respostas:


180

Não, o JavaScript não é uma linguagem de tipo estaticamente. Às vezes, pode ser necessário verificar manualmente os tipos de parâmetros em seu corpo funcional.


180
Bênção e maldição.
Jeffrey Sweeney

40
@JeffreySweeney também não é estaticamente digitado em PHP. Mas você tem a opção de digitar dicas no php. Você já olhou para um grande aplicativo back-end do nodejs? exatamente, cada função tem argumentos e você NÃO TEM idéia do que é cada argumento. Estamos falando de milhares de argumentos e, ao ler, você precisa ler o código inteiro e todo o código do chamador e do chamador, etc. Bênção? você certamente deve estar brincando.
Toskan 29/03

14
Além de atacando alguém que chama não permitindo que tipo de recurso insinuando uma bênção que eu poderia querer apontar typescript: typescriptlang.org basicamente EM6 tipo + insinuando
Toskan

23
@JeffreySweeney Não é uma bênção. É câncer.
Robo Robok

1
@ Tskan Eu não diria que não é uma bênção. Uso JavaScript há quatro anos, e essa é apenas a natureza de algumas linguagens. O conjunto de linguagens de programação deve variar de fracamente digitado a fortemente, da mesma forma que deve variar de baixo a alto nível. Além disso, o JavaScript fornece as palavras-chave instanceofe typeofpara ajudar nisso. Embora isso exija mais código, talvez o desenvolvedor tenha escolhido o JavaScript como idioma para algo que depende muito dos tipos. Quanto aos enormes aplicativos de back-end do nodejs? Eu acho que deveria ser bom senso.
Marvin

81

Não em javascript, mas usando o modo avançado do Google Closure Compiler, você pode fazer isso:

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

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


1
isso também funciona com / habilita o Eclipse JavaScript Editor - exibição de estrutura de tópicos e conclusão de código . considerando que a foo( /*MyType*/ param )maneira descrita aqui também funciona: stackoverflow.com/a/31420719/1915920
Andreas Dietrich

Percebo a idade dessa pergunta, mas gostaria de salientar que ela é honrada no IntelliJ. Resposta muito subestimada aqui.
ChettDM

67

Embora você não possa informar ao JavaScript o idioma sobre os tipos, é possível informar seu IDE sobre eles, para obter um preenchimento automático muito mais útil.

Aqui estão duas maneiras de fazer isso:

  1. Use o JSDoc , um sistema para documentar o código JavaScript nos comentários. Em particular, você precisará da @paramdiretiva :

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

    Você também pode usar o JSDoc para definir tipos personalizados e especificar aqueles nas @paramdiretivas, mas observe que o JSDoc não fará nenhuma verificação de tipo; é apenas uma ferramenta de documentação. Para verificar os tipos definidos no JSDoc, consulte o TypeScript , que pode analisar as tags JSDoc .

  2. Use a dica de tipo especificando o tipo logo antes do parâmetro em
    /* comment */:

    Sugestão de tipo JavaScript no WebStorm

    Essa é uma técnica bastante difundida, usada pelo ReactJS, por exemplo. Muito útil para parâmetros de retornos de chamada passados ​​para bibliotecas de terceiros.

TypeScript

Para uma verificação de tipo real, a solução mais próxima é usar o TypeScript, um superconjunto ( principalmente ) de JavaScript. Aqui está o TypeScript em 5 minutos .


8
Como fazer isso VSCode?
Anand Undavia

2
Obrigado. Mesmo que isso dependa do IDE. Eu uso VI e não funciona.
negrotico19

@ negrotico19: vié um editor excessivamente abusado, não um IDE. Você pode fazer muitas coisas vi, assim como criar vídeos de música no Excel . Boa ideia? Provavelmente não. Use a ferramenta certa para o trabalho.
Dan Dascalescu 03/02

23

Confira a nova biblioteca Flow do Facebook, "um verificador de tipo estático, projetado para encontrar erros de tipo em programas JavaScript"

Definição:

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

Verificação de tipo:

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

E aqui está como executá-lo .


como adicionar definição de tipo se x era um tipo de data? ou seja, foo (x: Date): string {}. Esse é o jeito certo de fazer?
Aakash Sigdel

12

Não, em vez disso, você precisaria fazer algo assim, dependendo de suas necessidades:

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

12

Você pode implementar um sistema que lida com as verificações de tipo automaticamente , usando um wrapper em sua função.

Com essa abordagem, você pode criar um completo declarative type check systemque gerenciará para você as verificações de tipo. Se você estiver interessado em examinar mais detalhadamente esse conceito, consulte a biblioteca Functyped

A implementação a seguir ilustra a ideia principal, de uma maneira simplista, mas operacional :

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

Edit: Sete anos depois, esta resposta ainda recebe votos ocasionais. Tudo bem se você estiver procurando por verificação em tempo de execução, mas agora eu recomendaria a verificação de tipo em tempo de compilação usando o Typecript, ou possivelmente o Flow. Consulte https://stackoverflow.com/a/31420719/610585 acima para obter mais informações.

Resposta original:

Não está embutido no idioma, mas você pode fazer isso facilmente. A resposta de Vibhu é o que eu consideraria a maneira típica de verificar o tipo em Javascript. Se você quiser algo mais generalizado, tente algo como isto: (apenas um exemplo para você começar)

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

Isso pode ser feito facilmente com o ArgueJS :

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

2
parece uma ótima biblioteca. Parabéns.
FRD

1

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

0

Talvez um ajudante funcione assim. Mas se você se vê usando essa sintaxe regularmente, provavelmente deve mudar para o 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
}

0

Eu estive pensando sobre isso também. Em um plano de fundo C, você pode simular tipos de código de retorno de função, bem como tipos de parâmetro, usando algo como o seguinte:

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

O número antes da função de chamada retorna um tipo de número, independentemente do tipo do valor real retornado, como visto na segunda chamada em que typeof rc = number, mas o valor é NaN

o console.log para o acima é:

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.