किसी फ़ंक्शन का रिटर्न प्रकार प्राप्त करना


100

मेरा निम्नलिखित कार्य है:

function test(): number {
    return 42;
}

मैं फ़ंक्शन के प्रकार का उपयोग करके प्राप्त कर सकता हूं typeof:

type t = typeof test;

यहाँ, tहोगा () => number

क्या फ़ंक्शन का रिटर्न प्रकार प्राप्त करने का एक तरीका है? मैं इसके बजाय tहोना चाहूंगा ।number() => number


2
नहीं, टाइपऑफ वैसे भी नहीं। टाइपोफ़ केवल "फ़ंक्शन" लौटाएगा ( मेरा आवरण गलत हो सकता है )।
इगोर

यह संभव हो जाए तो बहुत अच्छा होगा। कभी-कभी आप प्रकारों को परिभाषित करते हैं क्योंकि आप उन्हें किसी फ़ंक्शन से बाहर निकालते हैं, और इस संरचना को कैप्चर करने का कोई (अच्छा) तरीका नहीं है।
जोर्जेन Tvedt

जवाबों:


163

संपादित करें

टाइपस्क्रिप्ट 2.8 के रूप में यह आधिकारिक तौर पर संभव है ReturnType<T>

type T10 = ReturnType<() => string>;  // string
type T11 = ReturnType<(s: string) => void>;  // void
type T12 = ReturnType<(<T>() => T)>;  // {}
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>;  // number[]

देखें यहाँ जानकारी के लिए।

टाइपस्क्रिप्ट कमाल है!


पुराने स्कूल हैक

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

const fnReturnType = (false as true) && fn();

यह सही के शाब्दिक मूल्य पर गलत कास्टिंग करके काम करता है, ताकि प्रकार प्रणाली को लगता है कि रिटर्न वैल्यू फ़ंक्शन का प्रकार है, लेकिन जब आप वास्तव में कोड चलाते हैं, तो यह गलत पर शॉर्ट सर्किट करता है।

टाइपस्क्रिप्ट सबसे अच्छा है। : डी


52
यीशु, वह भयानक है।
जॉन वीज़

प्रवाह के लिए: const DUMMY = ((null: any): Object) और& fn () निर्यात प्रकार = typeof DUMMY
डेविड जू

किसी भी विचार क्यों जब मैं 2.8 स्थापित करें और कोशिश करें कि मुझे निम्न त्रुटि मिले Cannot find name 'ReturnType':? vscode का उपयोग
NSjonas

1
@NSjonas आपको दूसरे संस्करण का उपयोग करने के लिए vscode बताने की आवश्यकता है। मुझे लगता है कि नीचे दाईं ओर वह स्टेटस बार है।
मेयरियन ह्यूजेस

12
मुझे करना था ReturnType<typeof fn>(उत्तर का तात्पर्य ReturnType<fn>पर्याप्त है)।
spacek33z

49

टाइपस्क्रिप्ट 2.8 में सबसे आसान तरीका:

const foo = (): FooReturnType => {
}

type returnType = ReturnType<typeof foo>;
// returnType = FooReturnType

5

फ़ंक्शन निष्पादित किए बिना नीचे दिया गया कोड काम करता है। यह प्रतिक्रिया-रिड्यूक्स-टाइपस्क्रिप्ट लाइब्रेरी ( https://github.com/alexzywiak/react-redux-typescript/blob/master/utils/redux/typeUtils.ts ) से है

interface Func<T> {
    ([...args]: any, args2?: any): T;
}
export function returnType<T>(func: Func<T>) {
    return {} as T;
}


function mapDispatchToProps(dispatch: RootDispatch, props:OwnProps) {
  return {
    onFinished() {
      dispatch(action(props.id));
    }
  }
}

const dispatchGeneric = returnType(mapDispatchToProps);
type DispatchProps = typeof dispatchGeneric;

4

ऐसा करने का कोई तरीका नहीं है (देखें https://github.com/Microsoft/TypeScript/issues/6606 कार्य आइटम ट्रैकिंग इसे जोड़ने के लिए)।

एक आम समाधान कुछ इस तरह लिखा जाता है:

var dummy = false && test();
type t2 = typeof dummy;

3
मुझे नहीं लगता कि यह वर्कअराउंड अब काम करेगा - क्योंकि नियंत्रण प्रवाह आधारित प्रकार-विश्लेषण की संभावना है।
जेकिलियन

3
@JKillian तुम ठीक कह रहे हैं, उदाहरण के प्रस्तावित नहीं रह गया काम करता है, हालांकि आप आसानी के साथ टाइपप्रति चाल कर सकते हैं !1के बजाय false- typescriptlang.org/play/...
DanielM

3

संपादित करें: यह टीएस 2.8 किसी भी अधिक के साथ की जरूरत नहीं है! ReturnType<F>रिटर्न प्रकार देता है। स्वीकृत उत्तर देखें।


पिछले कुछ उत्तरों में से एक संस्करण, जो मैं उपयोग कर रहा हूं, जो strictNullChecksएक सा जिम्नास्टिक में थोड़ा सा काम करता है और छुपाता है:

function getReturnType<R>(fn: (...args: any[]) => R): R {
  return {} as R;
}

उपयोग:

function foo() {
  return {
    name: "",
    bar(s: string) { // doesn't have to be shorthand, could be `bar: barFn` 
      return 123;
    }
  }
}

const _fooReturnType = getReturnType(foo);
export type Foo = typeof _fooReturnType; // type Foo = { name: string; bar(s: string): number; }

यह फ़ंक्शन को कॉल करता getReturnTypeहै, लेकिन यह मूल फ़ंक्शन को कॉल नहीं करता है। आप कॉल का उपयोग करने से रोक सकते हैं लेकिन IMO इसे और अधिक भ्रमित करता है।getReturnType(false as true) && getReturnType(foo)

मैंने अभी इस विधि का उपयोग कुछ regexp खोजने के लिए किया है / एक पुराने कोणीय 1.x प्रोजेक्ट को माइग्रेट करने के लिए प्रतिस्थापित किया है, जिसमें ~ 1500 फैक्ट्री फ़ंक्शंस इस तरह लिखे गए थे, मूल रूप से JS में, और Fooसभी प्रकारों के लिए सभी प्रकारों का उपयोग किया गया ... अद्भुत टूटे हुए कोड पता कर लेंगे। :)


धन्यवाद! दुःख की बात है कि यह क्रिया की मात्रा को कम कर देता है, यह कम से कम काम करता है!
इकोमानोट

@ecmanaut हमें अब इसकी आवश्यकता नहीं है! TS 2.8 में आप ReturnType<F>फ़ंक्शंस रिटर्न प्रकार प्राप्त करने के लिए उपयोग कर सकते हैं । :)
आरोन बेयल

यहाँ उत्तर प्रश्न के उदाहरण सब्सट्रेट से बहुत भिन्न होते हैं, जिससे यह पता लगाना कठिन हो जाता है कि फ़ंक्शन का लौटा हुआ प्रकार कैसे उत्पन्न किया जाए test। यह उत्तर केवल नाम बदलने के testलिए foo(और वास्तव में किक के लिए अधिक जटिल रिटर्न प्रकार का उत्पादन करने वाले) के लिए अधिक उपयोगी था । दोनों स्वीकृत उत्तर और आपकी टिप्पणी शायद बहुत अच्छी है यदि आप पहले से ही जानते हैं कि उन्हें मूल उदाहरण पर कैसे लागू किया जाए। (यह यहां देर रात है, और तुरंत मुझे स्पष्ट नहीं है कि एक पूर्ण रिटर्न टाइप उदाहरण का वाक्यविन्यास कैसा दिखेगा।)
इत्मिनान

1

यदि प्रश्न में फ़ंक्शन उपयोगकर्ता परिभाषित वर्ग की एक विधि है, तो आप रनटाइम पर वापसी प्रकार (निर्माण कार्य) निर्धारित करने के लिए रिफ्लेक्ट मेटाडेटा के साथ संयोजन में विधि सज्जाकारों का उपयोग कर सकते हैं (और इसके साथ, जैसा कि आप फिट देखते हैं)।

उदाहरण के लिए, आप इसे कंसोल में लॉग कर सकते हैं:

function logReturnType(
    target: Object | Function,
    key: string,
    descriptor: PropertyDescriptor
): PropertyDescriptor | void {
    var returnType = Reflect.getMetadata("design:returntype", target, key);

    console.log(returnType);
}

बस अपनी पसंद की एक विधि पर इस विधि डेकोरेटर को स्नैप करें और आपके पास उस ऑब्जेक्ट के कंस्ट्रक्टर फ़ंक्शन का सटीक संदर्भ है जिसे विधि कॉल से माना जाता है।

class TestClass {
    @logReturnType // logs Number (a string representation)
    public test(): number {
        return 42;
    }
}

हालाँकि इस दृष्टिकोण में कुछ उल्लेखनीय सीमाएँ हैं:

  • आपको स्पष्ट रूप से इस तरह से सजाए गए तरीके पर रिटर्न प्रकार को परिभाषित करने की आवश्यकता है, अन्यथा आप अपरिभाषित हो जाएंगे Reflect.getMetadata,
  • आप केवल वास्तविक प्रकारों को संदर्भित कर सकते हैं जो संकलन के बाद भी मौजूद हैं; वह है, कोई इंटरफेस या जेनरिक नहीं

इसके अलावा, आपको टाइपस्क्रिप्ट कंपाइलर के लिए निम्न कमांड लाइन तर्क निर्दिष्ट करने की आवश्यकता होगी, क्योंकि डेकोरेटर और प्रतिबिंबित मेटाडाटा दोनों इस पोस्ट को लिखने के रूप में प्रयोगात्मक विशेषताएं हैं:

--emitDecoratorMetadata --experimentalDecorators

0

दुख की बात को निष्पादित किए बिना फ़ंक्शन के रिटर्न प्रकार को पुनर्प्राप्त करने का कोई तरीका नहीं है। ऐसा इसलिए है क्योंकि जब टाइपस्क्रिप्ट जेएस में संकलित हो जाता है, तो आप टाइप के संबंध में सभी जानकारी खो देते हैं।


3
यद्यपि यह तकनीकी रूप से सच है कि TS रनटाइम के दौरान टाइप जानकारी खो देता है, यह तथ्य प्रासंगिक नहीं है, क्योंकि ओपी संकलन समय पर फ़ंक्शन के प्रकार को निर्धारित करना चाहेगा। यह और भी स्पष्ट है कि अब ReturnType<T>टाइपस्क्रिप्ट में लागू किया गया है।
thedayturns

0

मैं निम्नलिखित के साथ आया था, जो अच्छी तरह से काम करता है:

function returnType<A, B, Z>(fn: (a: A, b: B) => Z): Z
function returnType<A, Z>(fn: (a: A) => Z): Z
function returnType<Z>(fn: () => Z): Z
function returnType(): any {
    throw "Nooooo"
}

function complicated(value: number): { kind: 'complicated', value: number } {
    return { kind: 'complicated', value: value }
}

const dummy = (false as true) && returnType(complicated)
type Z = typeof dummy

1
मुझे नहीं लगता कि फंक्शन आर्गन्स को जेनेरिक होने की जरूरत है, क्योंकि आप उन्हें वैसे भी फेंक रहे हैं। fn: (...args: any[]) => Zआपको जो चाहिए वह यह है।
हारून बीलल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.