टाइपस्क्रिप्ट में पैरामीटर के रूप में दृढ़ता से टाइप किए गए कार्य संभव हैं?


558

टाइपस्क्रिप्ट में, मैं फ़ंक्शन के एक पैरामीटर को एक प्रकार्य फ़ंक्शन के रूप में घोषित कर सकता हूं। क्या ऐसा करने का एक "प्रकार-सुरक्षित" तरीका है जो मुझे याद आ रहा है? उदाहरण के लिए, इस पर विचार करें:

class Foo {
    save(callback: Function) : void {
        //Do the save
        var result : number = 42; //We get a number from the save operation
        //Can I at compile-time ensure the callback accepts a single parameter of type number somehow?
        callback(result);
    }
}

var foo = new Foo();
var callback = (result: string) : void => {
    alert(result);
}
foo.save(callback);

सेव कॉलबैक सुरक्षित नहीं है, मैं इसे कॉलबैक फ़ंक्शन दे रहा हूं जहां फ़ंक्शन का पैरामीटर एक स्ट्रिंग है लेकिन मैं इसे एक नंबर दे रहा हूं, और कोई त्रुटि नहीं है। क्या मैं प्रकार-सुरक्षित फ़ंक्शन को सहेजने में परिणाम पैरामीटर बना सकता हूं?

TL; DR संस्करण: टाइपस्क्रिप्ट में .NET प्रतिनिधि के बराबर है?

जवाबों:


803

ज़रूर। एक फ़ंक्शन का प्रकार इसके तर्क के प्रकार और इसके वापसी प्रकार के होते हैं। यहां हम निर्दिष्ट करते हैं कि callbackपैरामीटर का प्रकार "फ़ंक्शन होना चाहिए जो एक संख्या को स्वीकार करता है और प्रकार टाइप करता है any":

class Foo {
    save(callback: (n: number) => any) : void {
        callback(42);
    }
}
var foo = new Foo();

var strCallback = (result: string) : void => {
    alert(result);
}
var numCallback = (result: number) : void => {
    alert(result.toString());
}

foo.save(strCallback); // not OK
foo.save(numCallback); // OK

यदि आप चाहें, तो आप इसे टाइप करने के लिए एक अन्य उपनाम को परिभाषित कर सकते हैं :

type NumberCallback = (n: number) => any;

class Foo {
    // Equivalent
    save(callback: NumberCallback) : void {
        callback(42);
    }
}

6
(n: number) => anyकिसी भी फ़ंक्शन हस्ताक्षर का मतलब है?
nikk

16
@ मिनीकवॉन्ग का मतलब है कि फ़ंक्शन एक पैरामीटर (ए number) लेता है, लेकिन रिटर्न प्रकार बिल्कुल भी प्रतिबंधित नहीं है (कोई भी मूल्य हो सकता है, या यहां तक ​​कि void)
डैनियल ईयरविकेर

16
nइस वाक्यविन्यास में क्या है ? क्या इनपुट और आउटपुट प्रकार अकेले पर्याप्त नहीं होंगे?
युहुआन जियांग

4
इनलाइन फ़ंक्शंस बनाम नामित फ़ंक्शंस का उपयोग करने के बीच एक साइड इफ़ेक्ट (इस उत्तर के नीचे उत्तर) इस "वैरिएबल" नामांकित फ़ंक्शन के साथ अपरिभाषित है, जबकि इसे इनलाइन फ़ंक्शन के भीतर परिभाषित किया गया है। जावास्क्रिप्ट कोडर के लिए कोई आश्चर्य नहीं, लेकिन निश्चित रूप से अन्य कोडिंग पृष्ठभूमि के लिए स्पष्ट नहीं है।
स्टीवो

3
@YuhuanJiang यह पोस्ट आपके लिए ब्याज की हो सकती है
Ophidian

93

यहां कुछ सामान्य .NET प्रतिनिधियों के टाइपस्क्रिप्ट समकक्ष हैं:

interface Action<T>
{
    (item: T): void;
}

interface Func<T,TResult>
{
    (item: T): TResult;
}

2
शायद देखने में उपयोगी है, लेकिन यह वास्तव में इस प्रकार के उपयोग के लिए एक विरोधी पैटर्न होगा। वैसे भी वे C # डेलीगेट्स की तुलना में जावा एसएएम प्रकार के अधिक दिखते हैं। निश्चित रूप से वे नहीं हैं और वे प्रकार के उपनाम के समान हैं जो कार्यों के लिए सिर्फ अधिक सुरुचिपूर्ण है
अलाउन हदद

5
@AluanHaddad क्या आप इस बारे में विस्तार से सोच सकते हैं कि आप इसे एक प्रतिमान क्यों मानते हैं?
मैक्स आर मैक्कार्टी

8
इसका कारण टाइपस्क्रिप्ट में एक संक्षिप्त फ़ंक्शन प्रकार शाब्दिक सिंटैक्स है जो इस तरह के इंटरफेस की आवश्यकता को कम करता है। C में # प्रतिनिधि नाममात्र के होते हैं, Actionऔर Funcप्रतिनिधि विशेष प्रतिनिधि प्रकारों की सबसे अधिक आवश्यकता को देखते हैं, और दिलचस्प बात यह है कि संरचनात्मक टाइपिंग के समान # सी # देते हैं। इन प्रतिनिधियों के लिए नकारात्मक पक्ष यह है कि उनके नाम का कोई मतलब नहीं है, लेकिन अन्य फायदे आम तौर पर इससे आगे निकल जाते हैं। टाइपस्क्रिप्ट में हमें केवल इन प्रकारों की आवश्यकता नहीं है। तो विरोधी पैटर्न होगा function map<T, U>(xs: T[], f: Func<T, U>)। पसंद करेंfunction map<T, U>(xs: T[], f: (x: T) => U)
एलुआन हदद

6
यह स्वाद की बात है, क्योंकि ये एक भाषा में समान रूप होते हैं जिनमें रन-टाइम प्रकार नहीं होते हैं। आजकल आप इंटरफेस के बजाय टाइप एलियास का भी उपयोग कर सकते हैं।
ड्रू नोक

18

मुझे लगता है कि यह पोस्ट पुरानी है, लेकिन एक अधिक कॉम्पैक्ट दृष्टिकोण है जो कि पूछा गया था, की तुलना में थोड़ा अलग है, लेकिन एक बहुत ही उपयोगी विकल्प हो सकता है। आप अनिवार्य रूप से जब विधि (बुला इन-लाइन समारोह घोषणा कर सकते हैं Fooकी save()इस मामले में)। यह कुछ इस तरह दिखेगा:

class Foo {
    save(callback: (n: number) => any) : void {
        callback(42)
    }

    multipleCallbacks(firstCallback: (s: string) => void, secondCallback: (b: boolean) => boolean): void {
        firstCallback("hello world")

        let result: boolean = secondCallback(true)
        console.log("Resulting boolean: " + result)
    }
}

var foo = new Foo()

// Single callback example.
// Just like with @RyanCavanaugh's approach, ensure the parameter(s) and return
// types match the declared types above in the `save()` method definition.
foo.save((newNumber: number) => {
    console.log("Some number: " + newNumber)

    // This is optional, since "any" is the declared return type.
    return newNumber
})

// Multiple callbacks example.
// Each call is on a separate line for clarity.
// Note that `firstCallback()` has a void return type, while the second is boolean.
foo.multipleCallbacks(
    (s: string) => {
         console.log("Some string: " + s)
    },
    (b: boolean) => {
        console.log("Some boolean: " + b)
        let result = b && false

        return result
    }
)

multipleCallback()दृष्टिकोण नेटवर्क कॉल कि सफल या विफल हो सकता है जैसी चीजों के लिए बहुत उपयोगी है। एक नेटवर्क कॉल उदाहरण को स्वीकार करते हुए, जब multipleCallbacks()कहा जाता है, तो सफलता और विफलता दोनों के लिए व्यवहार को एक ही स्थान पर परिभाषित किया जा सकता है, जो भविष्य के कोड पाठकों के लिए अधिक स्पष्टता के लिए उधार देता है।

आम तौर पर, मेरे अनुभव में, यह दृष्टिकोण अधिक संक्षिप्त, कम अव्यवस्था और समग्र रूप से अधिक स्पष्टता के लिए उधार देता है।

अच्छा भाग्य सभी के लिए!


16
type FunctionName = (n: inputType) => any;

class ClassName {
    save(callback: FunctionName) : void {
        callback(data);
    }
}

यह निश्चित रूप से कार्यात्मक प्रोग्रामिंग प्रतिमान के साथ संरेखित करता है।


6
आपको इसे inputTypeनहीं बल्कि आपको बुलाना returnTypeचाहिए? inputTypeवह प्रकार कहाँ है dataजिसमें आप callbackफ़ंक्शन के लिए एक पैरामीटर पास करते हैं।
क्रिस डब्ल्यूडब्ल्यू

हां @ क्रिस आप सही हैं, इनपुट टाइप अधिक समझ में आता है। धन्यवाद!
कृष्णा गनेरीवाल

2

टीएस में हम निम्नलिखित शिष्टाचार में कार्य टाइप कर सकते हैं:

प्रकार / हस्ताक्षर

इसका उपयोग फ़ंक्शंस / वास्तविक तरीकों के वास्तविक कार्यान्वयन के लिए किया जाता है, इसमें निम्नलिखित सिंटैक्स होते हैं:

(arg1: Arg1type, arg2: Arg2type) : ReturnType

उदाहरण:

function add(x: number, y: number): number {
    return x + y;
}

class Date {
  setTime(time: number): number {
   // ...
  }

}

समारोह प्रकार साहित्य

फ़ंक्शन प्रकार शाब्दिक फ़ंक्शन के प्रकार को घोषित करने का एक और तरीका है। वे आमतौर पर एक उच्च-क्रम फ़ंक्शन के फ़ंक्शन हस्ताक्षर में लागू होते हैं। एक उच्च-क्रम फ़ंक्शन एक फ़ंक्शन है जो फ़ंक्शन को पैरामीटर के रूप में स्वीकार करता है या जो एक फ़ंक्शन देता है। इसमें निम्नलिखित सिंटैक्स है:

(arg1: Arg1type, arg2: Arg2type) => ReturnType

उदाहरण:

type FunctionType1 = (x: string, y: number) => number;

class Foo {
    save(callback: (str: string) => void) {
       // ...
    }

    doStuff(callback: FunctionType1) {
       // ...
    }

}

1

यदि आप पहले फ़ंक्शन प्रकार को परिभाषित करते हैं, तो इसे देखा जाएगा

type Callback = (n: number) => void;

class Foo {
    save(callback: Callback) : void {        
        callback(42);
    }
}

var foo = new Foo();
var stringCallback = (result: string) : void => {
    console.log(result);
}

var numberCallback = (result: number) : void => {
    console.log(result);
}

foo.save(stringCallback); //--will be showing error
foo.save(numberCallback);

सादे संपत्ति सिंटैक्स का उपयोग करके फ़ंक्शन प्रकार के बिना यह होगा:

class Foo {
    save(callback: (n: number) => void) : void {        
        callback(42);
    }
}

var foo = new Foo();
var stringCallback = (result: string) : void => {
    console.log(result);
}

var numberCallback = (result: number) : void => {
    console.log(result);
}

foo.save(stringCallback); //--will be showing error
foo.save(numberCallback);

यदि आप c # जेनेरिक प्रतिनिधियों जैसे इंटरफ़ेस फ़ंक्शन का उपयोग करके चाहते हैं, तो यह होगा:

interface CallBackFunc<T, U>
{
    (input:T): U;
};

class Foo {
    save(callback: CallBackFunc<number,void>) : void {        
        callback(42);
    }
}

var foo = new Foo();
var stringCallback = (result: string) : void => {
    console.log(result);
}

var numberCallback = (result: number) : void => {
    console.log(result);
}

let strCBObj:CallBackFunc<string,void> = stringCallback;
let numberCBObj:CallBackFunc<number,void> = numberCallback;

foo.save(strCBObj); //--will be showing error
foo.save(numberCBObj);

0

इसके अलावा अन्य ने क्या कहा, एक सामान्य समस्या यह है कि एक ही फ़ंक्शन के प्रकार घोषित करना जो अतिभारित है। विशिष्ट मामला EventEmitter on () विधि है जो कई प्रकार के श्रोताओं को स्वीकार करेगा। ऐसा तब भी हो सकता है जब Redux क्रियाओं के साथ काम कर रहे हों - और आप ओवरलोडिंग को चिह्नित करने के लिए शाब्दिक के रूप में क्रिया प्रकार का उपयोग करते हैं, EventEmitters के मामले में, आप ईवेंट नाम शाब्दिक प्रकार का उपयोग करते हैं:

interface MyEmitter extends EventEmitter {
  on(name:'click', l: ClickListener):void
  on(name:'move', l: MoveListener):void
  on(name:'die', l: DieListener):void
  //and a generic one
  on(name:string, l:(...a:any[])=>any):void
}

type ClickListener = (e:ClickEvent)=>void
type MoveListener = (e:MoveEvent)=>void
... etc

// will type check the correct listener when writing something like:
myEmitter.on('click', e=>...<--- autocompletion
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.