Đặt loại cho tham số chức năng?


161

Có cách nào để cho một hàm javascript biết rằng một tham số nhất định thuộc một loại nhất định không?

Có thể làm một cái gì đó như thế này sẽ là hoàn hảo:

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

Cảm ơn bạn!

Cập nhật : Vì câu trả lời là "không", nếu tôi muốn myDateđược coi là một ngày (để gọi các hàm ngày trên nó), tôi phải đặt nó là một ngày bên trong hàm hoặc đặt một biến mới là gõ ngày vào nó?


1
Không theo nghĩa tích hợp và chung chung. Bạn có thể tự làm điều này bằng tay, nhưng sau đó, nó phụ thuộc vào cách bạn xác định "của một loại nhất định"
hugomg

2
Cũng không có lớp trong JavaScript, vì vậy không có Date, chỉ có object.
thoát

@Radu: Điều gì về Trang web Phát triển Mozilla này ?
dmr

@dmr, đó không phải là một lớp học. Datelà một chức năng. Hãy xem stackoverflow.com/questions/1646698/ trên để tìm hiểu thêm về newtừ khóa JavaScript . Ngoài ra, vì không có lớp nên không có casting. Bạn chỉ có thể gọi các chức năng bạn muốn. Nếu đối tượng chứa chúng, chúng sẽ chạy, nếu không bạn sẽ gặp lỗi.
thoát

2
Đó là một bản cũ tuy nhiên không ai nhắc đến bản thảo
bộ

Câu trả lời:


180

Không, JavaScript không phải là ngôn ngữ được nhập tĩnh. Đôi khi bạn có thể cần kiểm tra thủ công các loại tham số trong thân hàm.


179
Phước lành và một lời nguyền.
Jeffrey Sweeney

39
@JeffreySweeney cũng không phải là PHP được gõ tĩnh. Nhưng bạn có tùy chọn để thực hiện gợi ý gõ trong php. Bạn đã bao giờ nhìn vào một ứng dụng phụ trợ nodejs lớn chưa? chính xác, mỗi hàm có các đối số và bạn KHÔNG có đầu mối nào cho từng đối số. Chúng ta đang nói về hàng ngàn đối số và khi đọc, bạn phải đọc toàn bộ mã, và toàn bộ mã của người gọi và người gọi của nó, v.v. bạn chắc chắn phải nói đùa
Toskan

14
ngoài bashing người gọi không có tính năng cho phép loại gợi ý những lời chúc tôi có thể muốn chỉ ra nguyên cảo: typescriptlang.org cơ bản EM6 + loại gián tiếp
Toskan

22
@JeffreySweeney Đó không phải là một phước lành. Đó là ung thư.
Robo Robok

1
@Toskan Tôi sẽ không nói đó không phải là một phước lành. Tôi đã sử dụng JavaScript được bốn năm và đó chỉ là bản chất của một số ngôn ngữ. Tập hợp các ngôn ngữ lập trình nên có phạm vi từ gõ yếu đến gõ mạnh giống như cách nó sẽ dao động từ cấp thấp đến cấp cao. Ngoài ra, JavaScript cung cấp instanceoftypeoftừ khóa để hỗ trợ việc này. Mặc dù điều này chiếm nhiều mã hơn, nhưng có lẽ nhà phát triển đã chọn JavaScript làm ngôn ngữ cho thứ gì đó chủ yếu phụ thuộc vào các loại. Đối với các ứng dụng phụ trợ nodejs lớn? Tôi nghĩ nó nên là lẽ thường.
Marvin

81

Không phải trong javascript, nhưng sử dụng chế độ nâng cao của Google Clos Compiler, bạn có thể làm điều đó:

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

Xem http://code.google.com.vn/clenses/compiler/docs/js-for-compiler.html


1
điều này cũng hoạt động với / cho phép Trình soạn thảo JavaScript của Eclipse - Chế độ xem phác thảohoàn thành mã . trong khi foo( /*MyType*/ param )cách thức như được mô tả ở đây cũng hoạt động: stackoverflow.com/a/31420719/1915920
Andreas Dietrich

Tôi nhận ra câu hỏi này bao nhiêu tuổi nhưng tôi muốn chỉ ra rằng nó được vinh danh trong IntelliJ. Câu trả lời rất thiếu ở đây.
ChettDM

67

Mặc dù bạn không thể thông báo cho JavaScript ngôn ngữ về các loại, bạn có thể thông báo cho IDE của mình về chúng, để bạn có thể tự động hoàn thành hữu ích hơn nhiều.

Đây là hai cách để làm điều đó:

  1. Sử dụng JSDoc , một hệ thống để ghi lại mã JavaScript trong các bình luận. Cụ thể, bạn sẽ cần @paramchỉ thị :

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

    Bạn cũng có thể sử dụng JSDoc để xác định các loại tùy chỉnh và chỉ định các loại trong @paramchỉ thị, nhưng lưu ý rằng JSDoc sẽ không thực hiện bất kỳ kiểm tra loại nào; nó chỉ là một công cụ tài liệu. Để kiểm tra các loại được xác định trong JSDoc, hãy xem TypeScript , có thể phân tích các thẻ JSDoc .

  2. Sử dụng gợi ý loại bằng cách chỉ định loại ngay trước tham số trong
    /* comment */:

    Gợi ý loại JavaScript trong WebStorm

    Đây là một kỹ thuật khá phổ biến, được sử dụng bởi ReactJS chẳng hạn. Rất thuận tiện cho các tham số của cuộc gọi lại được chuyển đến thư viện bên thứ 3.

TypeScript

Để kiểm tra loại thực tế, giải pháp gần nhất là sử dụng TypeScript, một phần lớn ( phần lớn ) của JavaScript. Đây là TypeScript trong 5 phút .


8
Làm thế nào để có được điều này trên VSCode?
Anand Undavia

2
Cảm ơn. Mặc dù điều này phụ thuộc vào IDE. Tôi sử dụng VI và sẽ không làm việc.
negrotico19

@ negrotico19: vilà một biên tập viên bị lạm dụng quá mức, không phải là IDE. Bạn có thể thực hiện nhiều thứ trong đó vi, giống như bạn có thể tạo video nhạc trong Excel . Ý tưởng tốt? Chắc là không. Sử dụng các công cụ thích hợp cho công việc.
Dan Dascalescu

23

Kiểm tra thư viện Flow mới từ Facebook, "trình kiểm tra kiểu tĩnh, được thiết kế để tìm lỗi loại trong các chương trình JavaScript"

Định nghĩa:

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

Kiểm tra loại:

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

Và đây là cách chạy nó .


Làm thế nào để thêm định nghĩa kiểu nếu x là kiểu ngày? tức là foo (x: Ngày): chuỗi {}. Đây có phải là cách đúng đắn để làm việc này?
Aakash Sigdel

12

Không, thay vào đó, bạn sẽ cần phải làm một cái gì đó như thế này tùy thuộc vào nhu cầu của bạn:

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

12

Bạn có thể thực hiện một hệ thống tự động xử lý kiểm tra loại , sử dụng trình bao bọc trong chức năng của bạn.

Với phương pháp này, bạn có thể xây dựng một bản hoàn chỉnh declarative type check systemsẽ quản lý cho bạn các loại kiểm tra. Nếu bạn muốn tìm hiểu sâu hơn về khái niệm này, hãy kiểm tra thư viện Functyped

Việc thực hiện dưới đây minh hoạ ý tưởng chính, trong một đơn giản, nhưng cách tác :

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

Chỉnh sửa: Bảy năm sau, câu trả lời này vẫn thỉnh thoảng được nâng cấp. Sẽ tốt thôi nếu bạn đang tìm kiếm kiểm tra thời gian chạy, nhưng bây giờ tôi sẽ khuyên bạn nên kiểm tra kiểu thời gian biên dịch bằng cách sử dụng Typecript hoặc có thể là Flow. Xem https://stackoverflow.com/a/31420719/610585 ở trên để biết thêm.

Câu trả lời gốc:

Nó không được tích hợp vào ngôn ngữ, nhưng bạn có thể tự làm điều đó khá dễ dàng. Câu trả lời của Vibhu là những gì tôi sẽ xem xét cách kiểm tra loại điển hình trong Javascript. Nếu bạn muốn một cái gì đó khái quát hơn, hãy thử một cái gì đó như thế này: (chỉ là một ví dụ để bạn bắt đầu)

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

Nó có thể dễ dàng thực hiện với ArgueJS :

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

2
trông giống như một thư viện tuyệt vời chúc mừng.
FRD

1

Sử dụng typeofhoặc 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

Có lẽ một chức năng trợ giúp như thế này. Nhưng nếu bạn thấy mình sử dụng cú pháp như vậy thường xuyên, có lẽ bạn nên chuyển sang Bản đánh máy.

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

Tôi cũng đã suy nghĩ về điều này. Từ nền C, bạn có thể mô phỏng các loại mã trả về hàm, cũng như các loại tham số, bằng cách sử dụng một cái gì đó như sau:

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

Số trước hàm gọi trả về loại Số bất kể loại giá trị thực được trả về, như đã thấy trong lệnh gọi thứ 2 trong đó typeof rc = number nhưng giá trị là NaN

console.log cho phần trên là:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.