Daktilo tipi 'string' tipine yazılamaz


163

Meyvelerde neler var.

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

Şimdi fruit.ts dosyasını başka bir dosya tipine aktarıyorum. İşte sahip olduğum şey

myString:string = "Banana";

myFruit:Fruit = myString;

Ben yaparken

myFruit = myString;

Bir hata alıyorum:

'String' tipi '"Orange" türüne atanamaz | "Elma" | "Muz"'

Özel türdeki bir Fruit değişkenine nasıl dize atayabilirim?


1
İçinde tek ve çift tırnak kullanımından emin misiniz export type Fruit?
Weather Vane

1
@WeatherVane Sadece Fruit.ts'imi kontrol ettim. Orada ihracat türü Meyve için tek tırnak var = 'Turuncu' || 'Apple "||' Muz". Teşekkür ederim
user6123723

Hala bana bazı çift tırnak gibi görünüyor ...
Weather Vane

Yanıtlar:


232

Sen gerekir döküm :

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

let myFruit: Fruit = myString as Fruit;

Ayrıca, dizgi değişmezlerini kullanırken yalnızca bir tane kullanmanız gerektiğini unutmayın|

Düzenle

@Simon_Weaver'ın diğer cevabında belirtildiği gibi, şimdi bunu iddia etmek mümkündür const:

let fruit = "Banana" as const;

11
güzel bir :) çoğu durumda const myFruit: Fruit = "Banana"yapardı.
Jacka

Tersini yapabilir miyim? Bunun gibi bir şey demek let myFruit:Fruit = "Apple" let something:string = myFruit as string Bana hata veriyor: 'Meyve' türünün 'string' türüne dönüştürülmesi bir hata olabilir.
Siraj Alam

@Siraj İyi çalışmalı, as stringparçasına bile ihtiyacınız yok . Kodunuzu oyun alanında denedim ve hata yok.
Nitzan Tomer

@NitzanTomer stackoverflow.com/questions/53813188/… Lütfen detaylı soruma bakın
Siraj Alam

Ama şimdi yazım const myString: string = 'Bananaaa'; çünkü ben döküm nedeniyle derleme hataları alamadım ... türü dize kontrol ederken bunu yapmanın bir yolu yok mu?
blub

67

Daktilo metni 3.4yeni 'sabit' iddiasını tanıttı

Artık değişmez türlerin (örn. 'orange'Veya 'red') stringsözde constiddia ile yazılmaları için 'genişletilmelerini' önleyebilirsiniz .

Şunları yapabileceksiniz:

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

Ve sonra stringartık kendini dönüştürmeyecek - ki bu da sorunun probleminin kökü.


Benim gibi henüz 3.4 yaşında olmayanlar için. <const> herhangi biri ile değiştirilebilir, ancak elbette bu çözüm kadar temiz değildir.
Pieter De Bie

2
Tercih edilen sözdizimi, let fruit = 'orange' as const;köşeli ayraç-türü-onaylama kuralını
uygularken olacaktır

2
Modern dizgiler için doğru cevap budur. Türlerin gereksiz şekilde içe aktarılmasını önler ve yapısal yazmanın işini doğru yapmasına izin verir.
James McMahon

24

Bunu yaptığınızda:

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

... adlı bir tür yaratıyor Fruitsadece değişmezleri içerebileceğini "Orange", "Apple"ve "Banana". Bu tür String, dolayısıyla atanabilir String. Ancak, Stringuzatılmaz "Orange" | "Apple" | "Banana", bu nedenle atanamaz. Stringdaha az spesifiktir . Olabilir herhangi bir dize .

Bunu yaptığınızda:

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

const myString = "Banana";

const myFruit: Fruit = myString;

...işe yarıyor. Neden? Gerçek Çünkü türü arasında myStringbu örnekte olduğu "Banana". Evet, "Banana"bir tür . O uzanır Stringo kadar atanabilir yani String. Ayrıca, bir tür uzanır o uzandığında Birlik Tipi herhangi bileşenlerinin. Bu durumda, "Banana"tür, "Orange" | "Apple" | "Banana"bileşenlerinden birini genişlettiği için genişler. Bu nedenle, veya "Banana"öğesine atanabilir ."Orange" | "Apple" | "Banana"Fruit


2
Aslında koyabileceğiniz komik <'Banana'> 'Banana've bu tür "Banana"için bir dize ' "Banana"!!!'
Simon_Weaver

2
Ama şimdi <const> 'Banana'hangisini daha iyi yapabilirsin :-)
Simon_Weaver

11

Bunun biraz eski olduğunu görüyorum, ancak burada daha iyi bir çözüm olabilir.

Bir dize istediğiniz, ancak dizenin yalnızca belirli değerlerle eşleşmesini istediğinizde, numaralandırmalar kullanabilirsiniz .

Örneğin:

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

let myFruit: Fruit = Fruit.Banana;

Şimdi ne olursa olsun, myFruit'un her zaman "Banana" (ya da seçtiğiniz diğer numaralandırılabilir değer) dizesi olacağını bileceksiniz. Bu, derleyicinin izin verdiği değerleri zorlarken ve kısıtlarken, bunun gibi benzer değerleri gruplandırması veya kullanıcı dostu değerleri makine dostu değerlerle eşleştirmesi gibi birçok şey için yararlıdır.


1
Komik çünkü bunu yapmaktan kaçmaya çalışırken bu sorunu alıyorum. Gittikçe beni deli ediyor. 'Javascripty' olmaya çalışıyorum ve (numaralandırma yerine) bir türle sınırlandırılmış sihirli dizeleri kullanmak ve daha fazla geri teper ve bu hatayla tüm uygulama aracılığıyla dalgalanıyor gibi görünüyor: - /
Simon_Weaver

1
Bu da tam tersi soruna neden olur. Artık yapamazsın let myFruit: Fruit = "Banana".
Sean Burton

11

Size bu hatayı verecek birkaç durum vardır. OP durumunda, açıkça bir dize olarak tanımlanan bir değer vardı . Bu yüzden belki bu bir açılan, web hizmeti veya ham JSON dizesinden geldiğini varsaymak zorunda.

Bu durumda basit bir oyuncu <Fruit> fruitStringveya fruitString as Fruittek çözüm budur (diğer cevaplara bakınız). Derleme zamanında bunu hiç geliştiremezsiniz. [ Düzenle: Hakkında diğer cevabımı gör<const> ]!

Ancak, kodunuzda tür dizesi olması amaçlanmamış sabitleri kullanırken aynı hatayla karşılaşmak çok kolaydır . Cevabım şu ikinci senaryoya odaklanıyor:


Her şeyden önce: 'Sihirli' dize sabitleri neden bir numaradan daha iyidir?

  • Bir dize sabitinin bir numaralamaya karşı görünümünü seviyorum - kompakt ve 'javascripty'
  • Kullandığınız bileşen zaten dize sabitleri kullanıyorsa daha anlamlı olur.
  • Sadece bir numaralandırma değeri elde etmek için bir 'numara türü' almak zorunda kalmak kendi başına zahmetli olabilir
  • Ne olursa olsun , sendika türünden geçerli bir değeri kaldırırsanız veya yanlış yazarsam, derleme hatası vermesi GEREKİR bu yüzden güvenli derlemek istiyorum .

Neyse ki tanımladığınızda:

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

... aslında bir tanımlarken türleri birliği'missing' aslında bir türüdür!

'banana'Benim daktilo gibi bir dize varsa ve derleyici bir dize olarak kastettiğini düşünürken sık sık 'atanabilir değil' hata içine çalıştırın , oysa ben gerçekten tür olmasını istedim banana. Derleyicinin ne kadar akıllı olabileceği, kodunuzun yapısına bağlıdır.

İşte bugün bu hatayı aldığımda bir örnek:

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

En kısa sürede ben öğrendim olarak 'invalid'veya 'banana'bir tür ya da ben tekini fark bir dize ya olabileceğini bu tür bir dize assert . Temelde kendi kendine döküm ve derleyiciye hayır bunu bir dize olmasını istemiyorum söyle !

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

Peki, sadece FieldErrorType(veya Fruit) '

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

Zaman güvenli derlemek değil:

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

Neden? Bu daktilo yani <FieldErrorType>bir iddia ve derleyiciye bir köpek bir FieldErrorType olduğunu söylüyorsun ! Ve derleyici buna izin verecek!

AMA aşağıdakileri yaparsanız, derleyici dizeyi bir türe dönüştürür

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

Bunun gibi aptal yazım hatalarına dikkat edin:

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

Sorunu çözmenin başka bir yolu da ana nesneyi dökmektir:

Tanımlarım şöyleydi:

dışa aktarma türü FieldName = 'sayı' | 'expirationDate' | 'CVV'; dışa aktarma türü FieldError = 'none' | 'eksik' | 'geçersiz'; dışa aktarma türü FieldErrorType = {field: FieldName, hata: FieldError};

Diyelim ki bu konuda bir hata alıyoruz (dize atanamaz hatası):

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

Bütün nesneyi şöyle söyleyebiliriz FieldErrorType:

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

Sonra yapmaktan kaçınırız <'invalid'> 'invalid'.

Peki ya yazım hataları? <FieldErrorType>Sadece bu tip olma hakkının ne olduğunu iddia etmekle kalmaz . Değil bu durumda - neyse derleyici OLACAK Bunu eğer imkansız olduğunu biliyorum kadar zeki olduğu için, şikayet:

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

Katı modda incelikler olabilir. Onayladıktan sonra cevabı güncelleyecek.
Simon_Weaver

1

Yukarıdaki yanıtların tümü geçerlidir, ancak String Literal Type'ın başka bir karmaşık türün parçası olduğu bazı durumlar vardır. Aşağıdaki örneği düşünün:

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

Bunu düzeltmek için birden fazla çözümünüz var. Her çözüm geçerlidir ve kendi kullanım durumları vardır.

1) İlk çözüm, boyut için bir tür tanımlamak ve foo.ts'tan dışa aktarmaktır. Size parametresi ile kendi başınıza çalışmanız gerektiğinde bu iyidir. Örneğin, tür büyüklüğünde bir parametreyi kabul eden veya döndüren bir işleviniz var ve bunu yazmak istiyorsunuz.

  // 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) İkinci seçenek sadece ToolbarTheme türüne dökmektir. Bu durumda, ihtiyacınız yoksa ToolbarTheme'in iç kısmını açığa çıkarmanıza gerek yoktur.

  // 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[]Örneğin, bir veri alay ederken yayın yapıyorsanız , bunu değer ve görüntüleme özelliklerine sahip bir nesne dizisi olarak oluşturun.

örnek :

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

0

Aynı sorunla karşılaşıyordum, aşağıda değişiklikler yaptım ve sorun çözüldü.

WatchQueryOptions.d.ts dosyasını açın

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

Sorgu türünü değiştirme herhangi yerine DocumentNode , mutasyon için aynı

Önce:

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

Sonra:

export interface QueryBaseOptions<TVariables = OperationVariables> {
    query: **any**;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.