Ustawić typ parametrów funkcji?

161

Czy istnieje sposób, aby powiadomić funkcję javascript, że określony parametr jest określonego typu?

Możliwość zrobienia czegoś takiego byłaby idealna:

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

Dziękuję Ci!

Aktualizacja : Ponieważ odpowiedzią jest głośne "nie", jeśli chcę myDatebyć traktowany jako data (aby wywołać na niej funkcje daty), muszę rzucić ją jako datę wewnątrz funkcji lub ustawić nową zmienną wpisz Data do tego?

dmr
źródło
1
Nie w ogólnym i ogólnym sensie. Możesz to zrobić samodzielnie, ręcznie, ale zależy to od tego, jak zdefiniujesz „określonego typu”
hugomg
2
Nie ma też klas w JavaScript, więc nie ma Datetylko object.
pozbyć się
@Radu: A co z stroną Mozilla Develop Network ?
dmr
@dmr, to nie jest klasa. Datejest funkcją. Zajrzyj na stackoverflow.com/questions/1646698/…, aby dowiedzieć się więcej o newsłowie kluczowym JavaScript . Ponieważ nie ma zajęć, nie ma castingu. Możesz po prostu wywołać wybrane funkcje. Jeśli obiekt je zawiera, będą działać, w przeciwnym razie wystąpi błąd.
pozbyć się
2
Jest stary, ale nikt nie wspomniał o maszynopisie
zestaw

Odpowiedzi:

180

Nie, JavaScript nie jest językiem z typami statycznymi. Czasami może być konieczne ręczne sprawdzenie typów parametrów w treści funkcji.

pronvit
źródło
180
Błogosławieństwo i przekleństwo.
Jeffrey Sweeney
40
@JeffreySweeney ani PHP nie jest wpisywane statycznie. Ale masz możliwość skorzystania z podpowiedzi typu w php. Czy kiedykolwiek spojrzałeś na dużą aplikację backendową nodejs? dokładnie, każda funkcja ma argumenty i NIE masz pojęcia, co to jest. Mówimy o tysiącach argumentów i czytając, musisz przeczytać cały kod, cały kod dzwoniącego i jego rozmówcy itp. Błogosławieństwo? z pewnością żartujesz.
Toskan,
14
oprócz uderzenia kogoś, kto nie nazywa żadnej funkcji umożliwiającej podpowiadanie typu błogosławieństwem, mógłbym zwrócić uwagę na maszynopis: typescriptlang.org w zasadzie podpowiedź typu EM6 ​​+
Toskan
23
@JeffreySweeney To nie jest błogosławieństwo. To rak.
Robo Robok
1
@Toskan Nie powiedziałbym, że to nie jest błogosławieństwo. Używam JavaScript od czterech lat i taka jest po prostu natura niektórych języków. Zestaw języków programowania powinien wahać się od słabo wpisanych do silnie wpisanych, tak jak powinien wahać się od niskiego do wysokiego poziomu. Dodatkowo JavaScript udostępnia słowa kluczowe instanceofi, które typeofmogą w tym pomóc. Chociaż zajmuje to więcej kodu, być może to programista wybiera JavaScript jako język dla czegoś, co w dużej mierze zależy od typów. Co do ogromnych aplikacji backendowych nodejs? Myślę, że powinien to być zdrowy rozsądek.
Marvin
81

Nie w javascript, ale korzystając z zaawansowanego trybu Google Closure Compiler, możesz to zrobić:

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

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

eolsson
źródło
1
działa to również z / włącza edytor JavaScript Eclipse - widok konspektu i uzupełnianie kodu . podczas gdy foo( /*MyType*/ param )sposób opisany tutaj również działa: stackoverflow.com/a/31420719/1915920
Andreas Dietrich
Zdaję sobie sprawę, jak stare jest to pytanie, ale chciałem zaznaczyć, że jest honorowane w IntelliJ. Bardzo zaniżona odpowiedź tutaj.
ChettDM
67

Chociaż nie możesz poinformować JavaScript o języku o typach, możesz poinformować o nich swoje IDE, dzięki czemu otrzymujesz znacznie bardziej przydatne autouzupełnianie.

Oto dwa sposoby, aby to zrobić:

  1. Użyj JSDoc , systemu do dokumentowania kodu JavaScript w komentarzach. W szczególności będziesz potrzebować @paramdyrektywy :

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

    Możesz także użyć JSDoc do zdefiniowania niestandardowych typów i określenia ich w @paramdyrektywach, ale pamiętaj, że JSDoc nie wykona żadnego sprawdzania typów; to tylko narzędzie do dokumentacji. Aby sprawdzić typy zdefiniowane w JSDoc, zajrzyj do TypeScript , który może analizować tagi JSDoc .

  2. Użyj podpowiedzi typu, określając typ bezpośrednio przed parametrem w
    /* comment */:

    Podpowiedzi typu JavaScript w WebStorm

    Jest to dość rozpowszechniona technika, używana na przykład przez ReactJS . Bardzo przydatne w przypadku parametrów wywołań zwrotnych przekazywanych do bibliotek zewnętrznych.

Maszynopis

W przypadku rzeczywistego sprawdzania typu najbliższym rozwiązaniem jest użycie TypeScript, ( głównie ) nadzbiór języka JavaScript. Oto TypeScript za 5 minut .

Dan Dascalescu
źródło
8
Jak to założyć VSCode?
Anand Undavia
2
Dzięki. Mimo że zależy to od IDE. Używam VI i nie zadziała.
negrotico
@ negrotico19: vijest nadużywanym edytorem, a nie IDE. Możesz robić wiele rzeczy vi, podobnie jak tworzyć teledyski w programie Excel . Dobry pomysł? Prawdopodobnie nie. Użyj odpowiedniego narzędzia do pracy.
Dan Dascalescu
23

Zapoznaj się z nową biblioteką Flow z Facebooka, „statycznym narzędziem do sprawdzania typów, zaprojektowanym do znajdowania błędów typu w programach JavaScript”

Definicja:

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

Sprawdzanie typu:

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

A oto jak to uruchomić .

Renaud
źródło
jak dodać definicję typu, jeśli x był typem daty? tj. foo (x: Date): string {}. czy to jest właściwy sposób, aby to zrobić?
Aakash Sigdel
12

Nie, zamiast tego musisz zrobić coś takiego w zależności od potrzeb:

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

Możesz zaimplementować system, który automatycznie obsługuje sprawdzanie typów , używając opakowania w funkcji.

Dzięki takiemu podejściu możesz zbudować kompletny, declarative type check systemktóry będzie zarządzał sprawdzaniem typu. Jeśli chcesz dokładniej przyjrzeć się tej koncepcji, zajrzyj do biblioteki Functyped

Poniższa implementacja ilustruje główną ideę w uproszczony, ale praktyczny sposób :

/*
 * 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
źródło
11

Edycja: Siedem lat później ta odpowiedź wciąż otrzymuje sporadyczne głosy za. W porządku, jeśli szukasz funkcji sprawdzania w czasie wykonywania, ale teraz zalecałbym sprawdzanie typów w czasie kompilacji za pomocą Typescript lub prawdopodobnie Flow. Więcej informacji znajdziesz na https://stackoverflow.com/a/31420719/610585 powyżej.

Oryginalna odpowiedź:

Nie jest to wbudowane w język, ale możesz to zrobić samodzielnie. Odpowiedź Vibhu jest tym, co uważam za typowy sposób sprawdzania typów w Javascript. Jeśli chcesz czegoś bardziej uogólnionego, spróbuj czegoś takiego: (tylko przykład na początek)

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
nieokreślony
źródło
5

Można to łatwo zrobić za pomocą ArgueJS :

function myFunction ()
{
  arguments = __({myDate: Date, myString: String});
  // do stuff
};
zVictor
źródło
2
wygląda jak wspaniała biblioteka. gratulacje.
FRD
1

Użyj typeoflub 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
źródło
0

Może taka funkcja pomocnicza. Ale jeśli zauważysz, że regularnie używasz takiej składni, prawdopodobnie powinieneś przełączyć się na 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
źródło
0

Też o tym myślałem. W tle C możesz symulować typy kodu powrotu funkcji, a także typy parametrów, używając czegoś podobnego do następującego:

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

Liczba przed funkcją wywołującą zwraca typ Number niezależnie od typu zwracanej wartości rzeczywistej, jak widać w drugim wywołaniu, gdzie typeof rc = number, ale wartość to NaN

console.log dla powyższego to:

1st call
typeof rc: number   rc: 1
2nd call
Parm 1 not correct type
typeof rc: number   rc: NaN
Prostak
źródło
0

TypeScript jest obecnie jednym z najlepszych rozwiązań

TypeScript rozszerza JavaScript, dodając typy do języka.

https://www.typescriptlang.org/

xgqfrms
źródło