टाइपस्क्रिप्ट टाइप 'स्ट्रिंग' टाइप करने के लिए असाइन नहीं है


161

यहाँ मैं क्या फल में है

export type Fruit = "Orange" | "Apple" | "Banana"

अब मैं एक अन्य टाइपस्क्रिप्ट फ़ाइल में fruit.ts आयात कर रहा हूं। यहाँ मेरे पास क्या है

myString:string = "Banana";

myFruit:Fruit = myString;

जब मैं करता हूं

myFruit = myString;

मुझे एक त्रुटि मिली:

"ऑरेंज" टाइप करने के लिए 'स्ट्रिंग' टाइप करने योग्य नहीं है "सेब" | "केला"'

मैं कस्टम प्रकार के फल के एक स्ट्रिंग को कैसे निर्दिष्ट कर सकता हूं फल?


1
क्या आप एकल और दोहरे उद्धरण चिह्नों के उपयोग के बारे में निश्चित हैं export type Fruit?
वेदर

1
@WeatherVane ने मेरे फलों की जांच की। मेरे पास निर्यात प्रकार फल = 'ऑरेंज' के लिए सिंगल कोट्स हैं || 'Apple' || 'बनाना' धन्यवाद
user6123723

अभी भी मुझे कुछ दोहरे उद्धरण की तरह लगता है ...
वेदर

जवाबों:


231

आपको इसे डालना होगा :

export type Fruit = "Orange" | "Apple" | "Banana";
let myString: string = "Banana";

let myFruit: Fruit = myString as Fruit;

यह भी ध्यान रखें कि स्ट्रिंग शाब्दिक का उपयोग करते समय आपको केवल एक का उपयोग करने की आवश्यकता होती है|

संपादित करें

जैसा कि @Simon_Weaver द्वारा अन्य उत्तर में उल्लेख किया गया है, अब इस पर जोर देना संभव है const:

let fruit = "Banana" as const;

11
अच्छा एक :) ज्यादातर मामलों में const myFruit: Fruit = "Banana"
Jacka

क्या मैं इसका उल्टा कर सकता हूँ? मेरा मतलब कुछ इस तरह है कि यह let myFruit:Fruit = "Apple" let something:string = myFruit as string मुझे त्रुटि दे रहा है: टाइप करने के लिए 'फ्रूट' टाइप करने के लिए 'स्ट्रिंग' एक गलती हो सकती है।
सिराज आलम

@ सिराज यह ठीक काम करना चाहिए, आपको as stringभाग की भी आवश्यकता नहीं है । मैंने खेल के मैदान में आपके कोड की कोशिश की है और कोई त्रुटि नहीं है।
नित्ज़न तोमर

@NitzanTomer stackoverflow.com/questions/53813188/… कृपया मेरा विस्तृत प्रश्न देखें
सिराज आलम

लेकिन अब अगर मैं टाइपो करता const myString: string = 'Bananaaa'; हूं तो मुझे कास्टिंग की वजह से कंप्लीशन एरर नहीं मिलते ... क्या स्ट्रिंग को चेक करते समय ऐसा करने का कोई तरीका नहीं है?
blub

66

टाइपस्क्रिप्ट 3.4नए ' कॉन्स्टेंस ' दावे का परिचय देता है

अब आप तथाकथित प्रकार के साथ टाइप करने के लिए शाब्दिक प्रकार (जैसे। 'orange'या 'red') को 'चौड़ा' होने से रोक सकते हैं ।stringconst

आप कर सकेंगे:

let fruit = 'orange' as const;  // or...
let fruit = <const> 'orange';

और फिर यह खुद को stringअब और नहीं बदलेगा - जो प्रश्न में समस्या की जड़ है।


मेरे जैसे लोगों के लिए, 3.4 पर अभी तक नहीं हैं। <const> किसी भी द्वारा प्रतिस्थापित किया जा सकता है, लेकिन निश्चित रूप से इस समाधान के रूप में साफ नहीं है।
पीटर डी

2
पसंदीदा सिंटैक्स तब होगा let fruit = 'orange' as const;जब कोई कोण-कोष्ठक-प्रकार-अभिकथन नियम का पालन न करें
थंडरडेव

2
आधुनिक टाइपस्क्रिप्ट के लिए यह सही उत्तर है। यह प्रकारों के अनावश्यक आयात को रोकता है और संरचनात्मक टाइपिंग को सही ढंग से करने देता है।
जेम्स मैकमोहन

24

जब आप ऐसा करते हैं:

export type Fruit = "Orange" | "Apple" | "Banana"

... आप एक ऐसा प्रकार बना रहे हैं , Fruitजिसमें केवल शाब्दिक शब्द हो सकते हैं "Orange", "Apple"और "Banana"। यह प्रकार विस्तारित होता है String, इसलिए इसे सौंपा जा सकता है String। हालाँकि, Stringयह विस्तारित नहीं होता है "Orange" | "Apple" | "Banana", इसलिए इसे इसे नहीं सौंपा जा सकता है। Stringहै कम विशिष्ट । यह कोई भी तार हो सकता है ।

जब आप ऐसा करते हैं:

export type Fruit = "Orange" | "Apple" | "Banana"

const myString = "Banana";

const myFruit: Fruit = myString;

...यह काम करता हैं। क्यों? क्योंकि वास्तविक प्रकार के myStringइस उदाहरण में है "Banana"। हाँ, "Banana"है प्रकार । यह फैली हुई है, Stringइसलिए यह सच है String। इसके अतिरिक्त, एक प्रकार का विस्तार जब यह फैली हुई है एक यूनियन प्रकार किसी भी उसके घटकों के। इस मामले में "Banana", प्रकार, फैली हुई है "Orange" | "Apple" | "Banana"क्योंकि यह अपने घटकों में से एक का विस्तार करता है। इसलिए, "Banana"के लिए आबंटित है "Orange" | "Apple" | "Banana"या Fruit


2
यह अजीब बात है कि आप वास्तव में डाल सकते हैं <'Banana'> 'Banana'और यह एक "Banana"स्ट्रिंग को ' "Banana"टाइप ' कर देगा !!!
साइमन_वेर

2
लेकिन अब आप कर सकते हैं <const> 'Banana'जो बेहतर है :-)
शमौन_वेअर

11

मैं देखता हूं कि यह थोड़ा पुराना है, लेकिन यहां बेहतर समाधान हो सकता है।

जब आप एक स्ट्रिंग चाहते हैं, लेकिन आप चाहते हैं कि स्ट्रिंग केवल कुछ मूल्यों से मेल खाए, तो आप एनम का उपयोग कर सकते हैं

उदाहरण के लिए:

enum Fruit {
    Orange = "Orange",
    Apple  = "Apple",
    Banana = "Banana"
}

let myFruit: Fruit = Fruit.Banana;

अब आपको पता चल जाएगा कि कोई बात नहीं, myFruit हमेशा स्ट्रिंग "बनाना" होगा (या जो भी आपके द्वारा चुने जाने योग्य अन्य मूल्यवान मूल्य है)। यह कई चीजों के लिए उपयोगी है, चाहे वह इस तरह के समान मूल्यों को समूहीकृत कर रहा हो, या उपयोगकर्ता के अनुकूल मूल्यों को मशीन-अनुकूल मानों के लिए मैप कर रहा हो, सभी संकलक को उन मूल्यों को लागू करने और प्रतिबंधित करने की अनुमति देगा।


1
यह हास्यास्पद है क्योंकि मुझे ऐसा करने से दूर होने की कोशिश करते समय यह मुद्दा मिलता है। यह तेजी से मुझे पागल कर रहा है। मैं 'javascripty' बनने की कोशिश कर रहा हूं और एक प्रकार के बजाय (एक परिक्रमण के लिए) जादू के तार का उपयोग कर रहा हूं और यह इस त्रुटि के साथ मेरे पूरे आवेदन के माध्यम से अधिक से अधिक तरंगित करने के लिए लगता है: - /
Simon'Seaver

1
यह विपरीत समस्या का कारण भी बनता है। अब आप नहीं कर सकते let myFruit: Fruit = "Banana"
सीन बर्टन

11

कई परिस्थितियां हैं जो आपको यह विशेष त्रुटि देगी। ओपी के मामले में एक स्ट्रिंग के रूप में स्पष्ट रूप से परिभाषित मूल्य था । इसलिए मुझे यह मानना ​​होगा कि शायद यह एक ड्रॉपडाउन, या वेब सर्विस या रॉ JSON स्ट्रिंग से आया है।

उस मामले में एक साधारण कास्ट <Fruit> fruitStringया fruitString as Fruitएकमात्र समाधान है (अन्य उत्तर देखें)। आप कभी भी संकलन के समय इस पर सुधार नहीं कर पाएंगे। [ संपादित करें: मेरे अन्य उत्तर देखें<const> ]!

हालांकि आपके कोड में स्थिरांक का उपयोग करते समय यह उसी त्रुटि में चलाना बहुत आसान है जो कभी भी टाइप स्ट्रिंग के लिए अभिप्रेत नहीं है । मेरा उत्तर उस दूसरे परिदृश्य पर केंद्रित है:


सबसे पहले: क्यों 'जादू' स्ट्रिंग स्थिरांक अक्सर एक एनम से बेहतर होते हैं?

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

सौभाग्य से जब आप परिभाषित करते हैं:

export type FieldErrorType = 'none' | 'missing' | 'invalid'

... आप वास्तव में प्रकारों के एक संघ को परिभाषित कर रहे हैं जहां 'missing'वास्तव में एक प्रकार है!

अगर मैं 'banana'अपनी टाइपस्क्रिप्ट में एक स्ट्रिंग की तरह है , तो मैं अक्सर 'नियत नहीं' त्रुटि में चला जाता हूं और संकलक सोचता है कि मेरा मतलब एक स्ट्रिंग के रूप में था, जबकि मैं वास्तव में चाहता था कि यह टाइप का हो banana। कंपाइलर कितना स्मार्ट हो सकता है, यह आपके कोड की संरचना पर निर्भर करेगा।

आज मुझे यह त्रुटि कब मिली, इसका एक उदाहरण है:

// this gives me the error 'string is not assignable to type FieldErrorType'
fieldErrors: [ { fieldName: 'number', error: 'invalid' } ]

जैसे ही मुझे पता चला कि 'invalid'या 'banana'तो एक प्रकार या एक स्ट्रिंग हो सकता है मुझे एहसास हुआ कि मैं उस प्रकार में एक स्ट्रिंग को मुखर कर सकता हूं । अनिवार्य रूप से इसे खुद को कास्ट करें , और संकलक को बताएं कि मैं नहीं चाहता कि यह एक स्ट्रिंग हो !

// so this gives no error, and I don't need to import the union type too
fieldErrors: [ { fieldName: 'number', error: <'invalid'> 'invalid' } ]

तो क्या सिर्फ (कास्टिंग ) FieldErrorTypeया ( Fruit) के लिए गलत है

// why not do this?
fieldErrors: [ { fieldName: 'number', error: <FieldErrorType> 'invalid' } ]

यह संकलित समय सुरक्षित नहीं है:

 <FieldErrorType> 'invalidddd';  // COMPILER ALLOWS THIS - NOT GOOD!
 <FieldErrorType> 'dog';         // COMPILER ALLOWS THIS - NOT GOOD!
 'dog' as FieldErrorType;        // COMPILER ALLOWS THIS - NOT GOOD!

क्यों? यह टाइपस्क्रिप्ट है, इसलिए <FieldErrorType>यह एक जोर है और आप कंपाइलर को एक कुत्ता एक FieldErrorType बता रहे हैं ! और संकलक इसे अनुमति देगा!

लेकिन अगर आप निम्नलिखित करते हैं, तो संकलक स्ट्रिंग को एक प्रकार में बदल देगा

 <'invalid'> 'invalid';     // THIS IS OK  - GOOD
 <'banana'> 'banana';       // THIS IS OK  - GOOD
 <'invalid'> 'invalidddd';  // ERROR       - GOOD
 <'dog'> 'dog';             // ERROR       - GOOD

बस इस तरह बेवकूफ टाइपो के लिए बाहर देखो:

 <'banana'> 'banan';    // PROBABLY WILL BECOME RUNTIME ERROR - YOUR OWN FAULT!

समस्या को हल करने का दूसरा तरीका मूल ऑब्जेक्ट को कास्टिंग करके है:

मेरी परिभाषाएँ इस प्रकार थीं:

निर्यात प्रकार FieldName = 'संख्या' | 'समाप्ति ’| 'सीवीवी'; निर्यात प्रकार FieldError = 'कोई नहीं' | 'लापता' | 'अमान्य'; निर्यात प्रकार FieldErrorType = {फ़ील्ड: FieldName, त्रुटि: FieldError};

मान लें कि हमें इसके साथ एक त्रुटि मिलती है (स्ट्रिंग उपलब्ध नहीं त्रुटि):

  fieldErrors: [ { field: 'number', error: 'invalid' } ]

हम पूरी वस्तु को FieldErrorTypeइस तरह 'मुखर' कर सकते हैं :

  fieldErrors: [ <FieldErrorType> { field: 'number', error: 'invalid' } ]

तब हम करने से बचते हैं <'invalid'> 'invalid'

लेकिन टाइपो के बारे में क्या? नहीं करता है <FieldErrorType>बस ज़ोर जो कुछ उस प्रकार के होने का अधिकार पर है। इस मामले में नहीं - सौभाग्य से कंपाइलर शिकायत करेगा यदि आप ऐसा करते हैं, क्योंकि यह काफी चालाक है यह जानना असंभव है:

  fieldErrors: [ <FieldErrorType> { field: 'number', error: 'dog' } ]

सख्त मोड के साथ सूक्ष्मता हो सकती है। पुष्टि करने के बाद जवाब अपडेट करेंगे।
सिमोन_विवर

1

उपरोक्त सभी उत्तर मान्य हैं, हालांकि, कुछ मामले हैं कि स्ट्रिंग लिटरल टाइप दूसरे जटिल प्रकार का हिस्सा है। निम्नलिखित उदाहरण पर विचार करें:

  // in foo.ts
  export type ToolbarTheme = {
    size: 'large' | 'small',
  };

  // in bar.ts
  import { ToolbarTheme } from './foo.ts';
  function useToolbarTheme(theme: ToolbarTheme) {/* ... */}

  // Here you will get the following error: 
  // Type 'string' is not assignable to type '"small" | "large"'.ts(2322)
  ['large', 'small'].forEach(size => (
    useToolbarTheme({ size })
  ));

इसे ठीक करने के लिए आपके पास कई उपाय हैं। प्रत्येक समाधान मान्य है और इसके अपने उपयोग के मामले हैं।

1) पहला उपाय आकार के लिए एक प्रकार को परिभाषित करना और foo.ts से निर्यात करना है। यह तब अच्छा होता है जब आपको अपने हिसाब से आकार पैरामीटर के साथ काम करने की आवश्यकता होती है। उदाहरण के लिए, आपके पास एक फ़ंक्शन है जो प्रकार के आकार के एक पैरामीटर को स्वीकार या रिटर्न करता है और आप इसे टाइप करना चाहते हैं।

  // in foo.ts
  export type ToolbarThemeSize = 'large' | 'small';
  export type ToolbarTheme = {
    size: ToolbarThemeSize
  };

  // in bar.ts
  import { ToolbarTheme, ToolbarThemeSize } from './foo.ts';
  function useToolbarTheme(theme: ToolbarTheme) {/* ... */}
  function getToolbarSize(): ToolbarThemeSize  {/* ... */}

  ['large', 'small'].forEach(size => (
    useToolbarTheme({ size: size as ToolbarThemeSize })
  ));

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

  // in foo.ts
  export type ToolbarTheme = {
    size: 'large' | 'small'
  };

  // in bar.ts
  import { ToolbarTheme } from './foo.ts';
  function useToolbarTheme(theme: ToolbarTheme) {/* ... */}

  ['large', 'small'].forEach(size => (
    useToolbarTheme({ size } as ToolbarTheme)
  ));

0

यदि आप dropdownvalue[]उदाहरण के लिए डेटा का मखौल उड़ाते हुए कास्टिंग कर रहे हैं , तो इसे मान और प्रदर्शन गुणों वाली वस्तुओं की एक सरणी के रूप में लिखें।

उदाहरण :

[{'value': 'test1', 'display1': 'test display'},{'value': 'test2', 'display': 'test display2'},]

0

मैं उसी मुद्दे का सामना कर रहा था, मैंने नीचे बदलाव किए और समस्या हल हो गई।

WatchQueryOptions.d.ts फ़ाइल खोलें

\apollo-client\core\watchQueryOptions.d.ts

परिवर्तन के लिए DocumentNode , Same के बजाय किसी भी प्रकार का क्वेरी बदलें

इससे पहले:

export interface QueryBaseOptions<TVariables = OperationVariables> {
    query: **DocumentNode**;

उपरांत:

export interface QueryBaseOptions<TVariables = OperationVariables> {
    query: **any**;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.