टाइपस्क्रिप्ट में गुणों के साथ एक फ़ंक्शन ऑब्जेक्ट बनाएँ


87

मैं एक फ़ंक्शन ऑब्जेक्ट बनाना चाहता हूं, जिस पर कुछ गुण भी हैं। उदाहरण के लिए जावास्क्रिप्ट में मैं क्या करूँगा:

var f = function() { }
f.someValue = 3;

अब टाइपस्क्रिप्ट में मैं इस प्रकार का वर्णन कर सकता हूं:

var f: { (): any; someValue: number; };

हालांकि मैं वास्तव में एक कलाकार की आवश्यकता के बिना, इसका निर्माण नहीं कर सकता। जैसे कि:

var f: { (): any; someValue: number; } =
    <{ (): any; someValue: number; }>(
        function() { }
    );
f.someValue = 3;

बिना कास्ट के आप इसे कैसे बनाएंगे?


2
यह आपके प्रश्न का सीधा उत्तर नहीं है, लेकिन जो कोई भी गुण के साथ एक फ़ंक्शन ऑब्जेक्ट का निर्माण करना चाहता है, और कास्टिंग के साथ ठीक है, ऑब्जेक्ट-स्प्रेड ऑपरेटर को चाल करना लगता है var f: { (): any; someValue: number; } = <{ (): any; someValue: number; }>{ ...(() => "Hello"), someValue: 3 };:।
जोनाथन

जवाबों:


31

इसलिए यदि आवश्यकता बिना किसी कलाकार के "फ" के उस फंक्शन को बनाने और असाइन करने की है, तो यहां एक संभव समाधान है:

var f: { (): any; someValue: number; };

f = (() => {
    var _f : any = function () { };
    _f.someValue = 3;
    return _f;
})();

अनिवार्य रूप से, यह एक ऑब्जेक्ट को "निर्माण" करने के लिए एक स्व निष्पादित निष्पादन शाब्दिक का उपयोग करता है जो असाइनमेंट किए जाने से पहले उस हस्ताक्षर से मेल खाएगा। केवल विचित्रता यह है कि फ़ंक्शन की आंतरिक घोषणा को 'किसी भी' प्रकार का होना चाहिए, अन्यथा कंपाइलर रोता है कि आप एक संपत्ति को असाइन कर रहे हैं जो अभी तक ऑब्जेक्ट पर मौजूद नहीं है।

EDIT: कोड को थोड़ा सरल किया।


5
जहां तक ​​मैं समझ सकता हूं कि यह वास्तव में प्रकार की जांच नहीं करेगा, इसलिए .someValue अनिवार्य रूप से कुछ भी हो सकता है।
शबूनक

1
टाइपस्क्रिप्ट 2.0 के लिए 2017/2018 का बेहतर / अद्यतन उत्तर नीचे Meirion Hughes द्वारा पोस्ट किया गया है: stackoverflow.com/questions/12766528/…
user3773048

108

अद्यतन: यह उत्तर टाइपस्क्रिप्ट के पुराने संस्करणों में सबसे अच्छा समाधान था, लेकिन नए संस्करणों में बेहतर विकल्प उपलब्ध हैं (अन्य उत्तर देखें)।

स्वीकृत उत्तर काम करता है और कुछ स्थितियों में आवश्यक हो सकता है, लेकिन वस्तु के निर्माण के लिए किसी प्रकार की सुरक्षा प्रदान करने का नकारात्मक पहलू है। यदि आप अपरिभाषित संपत्ति को जोड़ने का प्रयास करते हैं तो यह तकनीक कम से कम एक प्रकार की त्रुटि को फेंक देगी।

interface F { (): any; someValue: number; }

var f = <F>function () { }
f.someValue = 3

// type error
f.notDeclard = 3

1
मुझे समझ नहीं आता कि var fलाइन में त्रुटि क्यों नहीं होती है, क्योंकि उस समय कोई someValueसंपत्ति नहीं है।

2
@torazaburo इसकी क्योंकि यह जाँच नहीं करता है कि आप कब डालते हैं। चेक टाइप करने के लिए आपको करना var f:F = function(){}होगा : जो उपरोक्त उदाहरण में विफल हो जाएगा। यह उत्तर अधिक जटिल परिस्थितियों के लिए बहुत अच्छा नहीं है क्योंकि आप असाइनमेंट चरण में टाइप जाँच खो देते हैं।
मीरियन ह्यूजेस

1
सही है लेकिन आप इसे फ़ंक्शन एक्सप्रेशन के बजाय फ़ंक्शन एक्सप्रेशन के साथ कैसे करते हैं?
अलेक्जेंडर मिल्स

1
यह अब टीएस के हाल के संस्करणों में काम नहीं करेगा, क्योंकि इंटरफ़ेस की जांच बहुत सख्त है और आवश्यक 'someValue' संपत्ति की अनुपस्थिति के कारण फ़ंक्शन की ढलाई अब संकलित नहीं होगी। हालांकि, क्या काम करेगा,<F><any>function() { ... }
गैलनस जूल

जब आप tslint का उपयोग करते हैं: अनुशंसित, टाइपकास्ट काम नहीं करता है और आपको जो उपयोग करने की आवश्यकता है वह है: (इसे एक अभिव्यक्ति बनाने के लिए कोष्ठक में फ़ंक्शन को लपेटें; फिर किसी भी F के रूप में उपयोग करें):var f = (function () {}) as any as F;
NikhilWanpal

80

यह अब आसानी से प्राप्य है (टाइपस्क्रिप्ट 2.x) Object.assign(target, source)

उदाहरण:

यहां छवि विवरण दर्ज करें

यहां जादू है कि चौराहेObject.assign<T, U>(t: T, u: U) पर लौटने के लिए टाइप किया गया है T & U

यह जानते हुए कि यह एक ज्ञात इंटरफ़ेस को हल करता है, वह भी सीधा-आगे है। उदाहरण के लिए:

interface Foo {
  (a: number, b: string): string[];
  foo: string;
}

let method: Foo = Object.assign(
  (a: number, b: string) => { return a * a; },
  { foo: 10 }
); 

असंगत टाइपिंग के कारण कौन सी त्रुटियां:

त्रुटि: foo: foo के लिए उपलब्ध नहीं संख्या: स्ट्रिंग
त्रुटि: स्ट्रिंग के लिए उपलब्ध नहीं संख्या [] (वापसी प्रकार)

चेतावनी: यदि आप की आवश्यकता हो सकती polyfill Object.assign अगर पुराने ब्राउज़र को लक्षित।


1
शानदार, धन्यवाद। फरवरी 2017 तक, यह सबसे अच्छा उत्तर है (टाइपस्क्रिप्ट 2.x उपयोगकर्ताओं के लिए)।
एंड्रयू फॉल्कनर

47

टाइपस्क्रिप्ट को विलय के माध्यम से इस मामले को संभालने के लिए डिज़ाइन किया गया है :

आप फ़ंक्शन बनाने और फ़ंक्शन पर गुण जोड़कर फ़ंक्शन को आगे बढ़ाने के जावास्क्रिप्ट अभ्यास से भी परिचित हो सकते हैं। टाइपस्क्रिप्ट एक प्रकार से सुरक्षित तरीके से परिभाषाएँ बनाने के लिए घोषणा विलय का उपयोग करता है।

घोषणा विलय से हम यह कह सकते हैं कि कुछ एक फ़ंक्शन और एक नामस्थान (आंतरिक मॉड्यूल) है:

function f() { }
namespace f {
    export var someValue = 3;
}

यह टाइपिंग को संरक्षित करता है और हमें दोनों f()और लिखने देता है f.someValue.d.tsमौजूदा जावास्क्रिप्ट कोड के लिए फ़ाइल लिखते समय , उपयोग करें declare:

declare function f(): void;
declare namespace f {
    export var someValue: number;
}

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


उत्तर में परिवेश मॉड्यूल का उल्लेख करने के लिए अपवोट। मौजूदा जेएस मॉड्यूल को परिवर्तित या एनोटेट करते समय यह बहुत विशिष्ट मामला है। बिल्कुल मैं क्या देख रहा हूँ!
निफेरिस

लवली। यदि आप ईएस 6 मॉड्यूल के साथ इसका उपयोग करना चाहते हैं, तो आप बस function hello() { .. } namespace hello { export const value = 5; } export default hello;आईएमओ कर सकते हैं यह ऑब्जेक्ट.साइन या इसी तरह के रनटाइम हैक्स की तुलना में बहुत क्लीनर है। कोई क्रम नहीं, कोई प्रकार का जोर नहीं, कुछ नहीं।
स्क्रेबेल

यह उत्तर बहुत अच्छा है, लेकिन आप सिंबल जैसे प्रतीक को किसी फ़ंक्शन में कैसे संलग्न करते हैं?
kzh

ऊपर के लिंक किसी भी अधिक, सही काम नहीं करता होगा typescriptlang.org/docs/handbook/declaration-merging.html
iJungleBoy

आपको पता होना चाहिए कि कुछ काफी विजयी जावास्क्रिप्ट में परिणाम विलय की घोषणा। यह एक अतिरिक्त क्लोजर जोड़ता है जो मुझे एक साधारण संपत्ति असाइनमेंट के लिए अत्यधिक लगता है। यह बहुत ही अन-जावास्क्रिप्ट तरीका है। यह निर्भरता समस्या के एक आदेश को भी प्रस्तुत करता है जहां परिणामी मूल्य आवश्यक रूप से एक फ़ंक्शन नहीं है जब तक कि आप निश्चित नहीं हैं कि फ़ंक्शन आवश्यक होना पहली बात है ।
जॉन लीडग्रेन

3

मैं यह नहीं कह सकता कि यह बहुत सीधा है, लेकिन यह निश्चित रूप से संभव है:

interface Optional {
  <T>(value?: T): OptionalMonad<T>;
  empty(): OptionalMonad<any>;
}

const Optional = (<T>(value?: T) => OptionalCreator(value)) as Optional;
Optional.empty = () => OptionalCreator();

यदि आप जिज्ञासु हैं तो यह टाइपस्क्रिप्ट / जावास्क्रिप्ट संस्करण के साथ मेरा एक जिस्ट से हैOptional


2

एक शॉर्टकट के रूप में, आप ['संपत्ति'] एक्सेसर का उपयोग करके ऑब्जेक्ट वैल्यू को गतिशील रूप से असाइन कर सकते हैं:

var f = function() { }
f['someValue'] = 3;

यह जाँच के प्रकार को दरकिनार कर देता है। हालांकि, यह बहुत सुरक्षित है क्योंकि आपको जानबूझकर संपत्ति को उसी तरह से एक्सेस करना होगा:

var val = f.someValue; // This won't work
var val = f['someValue']; // Yeah, I meant to do that

हालाँकि, यदि आप वास्तव में संपत्ति के मूल्य के लिए जाँच करना चाहते हैं, तो यह काम नहीं करेगा।


1

एक अद्यतन जवाब: चौराहे के प्रकार के अलावा के माध्यम से &, यह मक्खी पर दो अनुमान लगाया प्रकार "मर्ज" करने के लिए संभव है।

यहां एक सामान्य सहायक है जो किसी वस्तु के गुणों को पढ़ता है fromऔर उन्हें किसी वस्तु पर कॉपी करता है onto। यह एक ही वस्तु देता है ontoलेकिन एक नए प्रकार के साथ जिसमें संपत्तियों के दोनों सेट शामिल होते हैं, इसलिए रनटाइम व्यवहार का सही वर्णन करते हैं:

function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
    Object.keys(from).forEach(key => onto[key] = from[key]);
    return onto as T1 & T2;
}

यह निम्न-स्तरीय सहायक अभी भी एक प्रकार का दावा करता है, लेकिन यह डिजाइन द्वारा टाइप-सुरक्षित है। इस सहायक के साथ, हमारे पास एक ऑपरेटर है जिसका उपयोग हम ओपी की समस्या को पूर्ण प्रकार की सुरक्षा के साथ हल करने के लिए कर सकते हैं:

interface Foo {
    (message: string): void;
    bar(count: number): void;
}

const foo: Foo = merge(
    (message: string) => console.log(`message is ${message}`), {
        bar(count: number) {
            console.log(`bar was passed ${count}`)
        }
    }
);

टाइपस्क्रिप्ट प्लेग्राउंड में इसे आज़माने के लिए यहां क्लिक करें । ध्यान दें कि हमने fooटाइप करने के लिए विवश किया है Foo, इसलिए इसका परिणाम mergeपूर्ण होना है Foo। इसलिए यदि आप नाम बदलते barहैं badतो आपको एक प्रकार की त्रुटि मिलती है।

एनबी अब भी यहाँ एक प्रकार का छेद है। टाइपस्क्रिप्ट एक प्रकार के पैरामीटर को "फ़ंक्शन नहीं" होने के लिए बाध्य करने का एक तरीका प्रदान नहीं करता है। तो आप भ्रमित हो सकते हैं और दूसरे तर्क के रूप में अपने कार्य को पारित कर सकते हैं merge, और यह काम नहीं करेगा। इसलिए जब तक यह घोषित नहीं किया जा सकता, हमें इसे रनटाइम पर पकड़ना होगा:

function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
    if (typeof from !== "object" || from instanceof Array) {
        throw new Error("merge: 'from' must be an ordinary object");
    }
    Object.keys(from).forEach(key => onto[key] = from[key]);
    return onto as T1 & T2;
}

1

पुराना प्रश्न है, लेकिन 3.1 से शुरू होने वाले टाइपस्क्रिप्ट के संस्करणों के लिए, आप संपत्ति के असाइनमेंट को सीधे सादे जेएस में कर सकते हैं, जब तक आप एक फ़ंक्शन घोषणा या constअपने चर के लिए कीवर्ड का उपयोग करते हैं:

function f () {}
f.someValue = 3; // fine
const g = function () {};
g.someValue = 3; // also fine
var h = function () {};
h.someValue = 3; // Error: "Property 'someValue' does not exist on type '() => void'"

संदर्भ और ऑनलाइन उदाहरण


0

यह मजबूत टाइपिंग से निकलता है, लेकिन आप कर सकते हैं

var f: any = function() { }
f.someValue = 3;

यदि आप दमनकारी मजबूत टाइपिंग के बारे में जानने की कोशिश कर रहे हैं, जैसे कि मुझे यह प्रश्न मिला था। अफसोस की बात यह है कि टाइपस्क्रिप्ट पूरी तरह से मान्य जावास्क्रिप्ट पर विफल रहता है इसलिए आपको टाइपस्क्रिप्ट को वापस बताने के लिए कहना होगा।

"आप जावास्क्रिप्ट पूरी तरह से वैध टाइपस्क्रिप्ट हैं" झूठी का मूल्यांकन करता है। (नोट: 0.95 का उपयोग करके)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.