Typescript: Type 'string | tanımsız ',' dizge 'türüne atanamaz


100

Bir arayüzün herhangi bir özelliğini isteğe bağlı yaptığımda, üyesini başka bir değişkene atarken aşağıdaki gibi bir hata yapıyorum

TS2322: 'string' yazın | tanımsız ',' dizge 'türüne atanamaz. 'Tanımlanmamış' türü, 'dizge' türüne atanamaz.

interface Person {
  name?:string,
  age?:string,
  gender?:string,
  occupation?:string,
}

function getPerson(){
  let person = <Person>{name:"John"};
  return person;
}
let person: Person = getPerson();
let name1:string = person.name;//<<<Error here 

Bu hatayı nasıl aşarım?

Yanıtlar:


186

Artık tam olarak sizin kullanım durumunuz için burada bulunan boş olmayan onaylama işlecini kullanabilirsiniz.

TypeScript'e bir şeyin boş gibi görünse bile, olmadığına size güvenebileceğini söyler:

let name1:string = person.name!; 
//                            ^ note the exclamation mark here  

3
Tam olarak aradığım buydu!
Shautieh

1
ESLint, boş olmayan onaylama operatörünün kullanımını kısıtlamayana kadar :)
Anatoly

3
Böyle bir şeyin var olması gerektiğine şok oldum. 🤯
GONeale

@GONeale, aktarıcının bir değerin boş olamayacağını kendi başına anlayamadığı birçok durum vardır. Bir örnek, örneğin Angular tarafından belirlenen bir değerdir ve Angular, değerin boş olamayacağını garanti etmek için kendi yöntemine sahiptir.
yannick1976

19
Bu berbat bir tavsiye! Bunun yerine, derleyicinin çözmesine yardımcı olun. Özelliğe erişmeden önce, ad ayarlanmamışsa attığınız veya geri döndüğünüz bir kontrol ekleyin.
geon

56

Kullandığım derleme hatasını önlemek için

let name1:string = person.name || '';

Ve sonra boş dizeyi doğrulayın.


1
Ya bir dizge değil de nesne değilse?
Anatoly

1
Eğer bir nesne ise '' yerine {} olacaktır
Kriti

Bu değerler zincirleme zaman yapabileceğiniz bir şeydir ve yanlışlıkla bu tür olsunOptional chain expressions can return undefined by design - using a non-null assertion is unsafe and wrong.
tHeSiD

26

Bunun biraz geç cevap olduğunu biliyorum ama yannick'in cevabının dışında başka bir yol: https://stackoverflow.com/a/57062363/6603342 ! bunu dize olarak çevirmek ve böylece TypeScript'e bunun bir dize olduğundan emin olduğumu söyleyerek

let name1:string = person.name;//<<<Error here 

-e

let name1:string = person.name as string;

Bu, hatayı ortadan kaldıracaktır, ancak herhangi bir şans eseri bu bir dize değilse , türün eşleşmesini sağlamak ve derleme zamanında bu tür hataları önlemek için TypeScript kullandığımız nedenlerden biri olan bir çalışma zamanı hatası alacaksınız .


Bu, hatayı ortadan kaldırabilir, ancak değişkenin gerçek türünü asla değiştirmez.
Mansi

Özür dilerim ama sanırım orada oldukça yanılıyorsunuz, bahsettiğim gibi, eğer tür bir dizge olmazsa veya bir toString yöntemine sahip olamıyorsa, bu aslında bir çalışma zamanı istisnası atacağı için türü değiştirecektir. Bu, orada olan her şeyi bir dizgeye dönüştürecektir, yani bir numaranız var, orada sahip olduğunuz her şeyin .toString işlevini çağırmaya çalışacaktır.
Harry

Ama bu doğru yol olmayacak, diyelim ki ismim içinde "0" rakamı varsa, onu dizgeye dönüştürür ... Bunun yerine bir hata atıp geçersiz isim demesi gerekir. Şahsen, bu typecast'i kullanmazdım ve nesnede geçen türü özellikle kontrol etmezdim .. ama hepimizin farklı kodlama stilleri var, aynı konuda daha fazla tartışmaya açık
Mansi

Evet ama bu, bu cevabın verildiği sorunun içeriği tamamen dışındadır. Önceden filtrelemek için herhangi bir adım yoksa, bunun bir form olup olmadığını bilmiyoruz. Ayrıca önerdiğiniz şey, gerçekten kirli bazı geçici çözümler olmadan bu aşamada imkansız olurdu.
Harry

Geçici çözümlere gerek yok, değişkene erişmeye çalışmadan önce sadece bir kontrol yapın. Her iki durum da kolaylıkla ele alınacak, hatalar ortadan kalkacak ve kodunuz daha güvenli olacaktır. Deneyin :)
Mansi

21

TypeScript 3.7'den itibaren, sıfır birleştirme operatörü kullanabilirsiniz ??. Bu özelliği, null veya undefined ile uğraşırken varsayılan bir değere "geri dönmenin" bir yolu olarak düşünebilirsiniz.

let name1:string = person.name ?? '';

??Operatör kullanımlarını yerini alabilecek ||bir varsayılan değer kullanmaya çalışıyor vb Boolean, sayılar, ilgilenirken kullanılabilir olduğunda ||kullanılamaz.

TypeScript 4'ten itibaren, ??=atama operatörünü kullanabilirsiniz a ??= b.a = a ?? b;


7

önceden gerçek değerin ne olduğunu bulmaya çalışın. personGeçerli bir varsa name, atayın name1, yoksa atayın undefined.

let name1: string = (person.name) ? person.name : undefined;

2
hmmm. Birden fazla görev yapmak istersem bu çok ayrıntılı olacaktır. Bu özel uyarıyı kapatmanın bir yolu var mı?
asdasd

namesoru işaretini kaldırarak maalesef zorunlu hale getirmiyorum.
Lynx 242

Not: TypeScript'in hangi sürümünü kullanıyorsunuz? 3.2.4 kullanıyorum ve bu Mesajla karşılaşmıyorum. Benim test sınıfımda kod mükemmel bir şekilde derlenir.
Lynx 242

aynı versiyon. Bu hatayı webstorm'da alıyorum ama vscode'da almıyorum
asdasd

Bu garip, çünkü TS kurallarının uygulanması söz konusu olduğunda WebStorm'a benzer olması gereken IntelliJ kullanıyorum ?!
Lynx 242

5

Bunu halletmenin daha üretime hazır bir yolu, gerçekten namemevcut olmasını sağlamaktır . Bunun, bir grup insanın dahil olduğu daha büyük bir projenin minimal bir örneği olduğunu varsayarsak getPerson, gelecekte nasıl değişeceğini bilemezsiniz .

if (!person.name) {
    throw new Error("Unexpected error: Missing name");
}

let name1: string = person.name;

Alternatif olarak, yazabilirsiniz name1olarak string | undefined, ve davalarını undefineddaha da aşağı. Ancak beklenmedik hataları daha önce ele almak genellikle daha iyidir.

Ayrıca, açık türü atlayarak TypeScript'in türü çıkarmasına izin verebilirsiniz: let name1 = person.nameBu, name1örneğin, bir numara olarak yeniden atanmayı yine de engeller .


3

Neler olduğunu anlamanın hızlı bir yolu:

Aşağıdakileri yaptığınızda:

isim? : string

TypeScript'e isteğe bağlı olduğunu söylüyordun. Yine de yaptığınızda:

let name1 : string = person.name; //<<<Error here 

Ona bir seçenek bırakmadın. Üzerinde tanımlanmamış türü yansıtan bir Birlik olması gerekiyordu:

let name1 : string | undefined = person.name; //<<<No error here 

Cevabınızı kullanarak, temelde bir Arayüz, bir Sınıf ve bir Nesne olan aşağıdakileri çizebildim. Bu yaklaşımı daha basit buluyorum, eğer yapmazsan boşver.

// Interface
interface iPerson {
    fname? : string,
    age? : number,
    gender? : string,
    occupation? : string,
    get_person?: any
}

// Class Object
class Person implements iPerson {
    fname? : string;
    age? : number;
    gender? : string;
    occupation? : string;
    get_person?: any = function () {
        return this.fname;
    }
}

// Object literal
const person1 : Person = {
    fname : 'Steve',
    age : 8,
    gender : 'Male',
    occupation : 'IT'  
}

const p_name: string | undefined = person1.fname;

// Object instance 
const person2: Person = new Person();
person2.fname = 'Steve';
person2.age = 8;
person2.gender = 'Male';
person2.occupation = 'IT';

// Accessing the object literal (person1) and instance (person2)
console.log('person1 : ', p_name);
console.log('person2 : ', person2.get_person());

2

Değişken name1, cadı türü katı dizge olarak ayarlanmış (dizge OLMALIDIR) nesne alanındaki namedeğerle, cadı değer türü isteğe bağlı dizge olarak ayarlanmış (soru işareti nedeniyle dizge veya tanımsız olabilir). Bu davranışa gerçekten ihtiyacınız varsa, şu şekilde değiştirmelisiniz name1:

let name1: string | undefined = person.name;

Ve iyi olacak;


0

Değişken bir diziden veya yıkıcıysa, varsayılan değerleri sağlayabileceğinizi unutmayın:

const { DB_HOST = "localhost", DB_PORT: "5432" } = process.env

db.connect(DB_HOST, DB_PORT);
const connectToDb = (host = "localhost", port: "5432") => db.connect(host, port);


0

NonNullableYardımcı Program Türünü kullanabilirsiniz :

Misal

type T0 = NonNullable<string | number | undefined>;  // string | number
type T1 = NonNullable<string[] | null | undefined>;  // string[]

Dokümanlar .


-1

1.Çözüm: Açık tür tanımını kaldırın

Yana getPersonzaten döndüren Personbir adla, biz anlaşılmaktadır türünü kullanabilirsiniz.

function getPerson(){
  let person = {name:"John"};
  return person;
}

let person = getPerson();

Tanımlayacak person: Personolsaydık, bir bilgi parçasını kaybedeceğiz. getPersonİsteğe bağlı olmayan bir özelliğe sahip bir nesne döndürdüğünü biliyoruz name, ancak onu Personisteğe bağlılığı geri getirecek şekilde tanımlayarak .

2.Çözüm: Daha kesin bir tanım kullanın

type Require<T, K extends keyof T> = T & {
  [P in K]-?: T[P]
};

function getPerson() {
  let person = {name:"John"};
  return person;
}

let person: Require<Person, 'name'> = getPerson();
let name1:string = person.name;

3. Çözüm: Arayüzünüzü yeniden tasarlayın

Tüm özelliklerin isteğe bağlı olduğu bir şekle zayıf tip denir ve genellikle kötü tasarımın bir göstergesidir. nameGerekli bir mülk yaparsak , sorununuz ortadan kalkar.

interface Person {
  name:string,
  age?:string,
  gender?:string,
  occupation?:string,
}

-14

Aynı sorunu yaşadım.

Ben tepki-scrips eklemek öğrenmek "strict": trueiçin tsconfig.json.

Kaldırdıktan sonra her şey harika çalışıyor.

Düzenle

Bu özelliği değiştirmenin şu anlama geldiği konusunda uyarmanız gerekir:

artık potansiyel çalışma zamanı hataları hakkında uyarılmıyor.

olarak tarafından belirtildiği PaulG yorumlarda! Teşekkür ederim :)

"strict": falseSadece neyi etkilediğini tam olarak anladıysanız kullanın !


9
Bu 'işe yarayabilir'. Ancak bu yalnızca, artık potansiyel çalışma süresi hataları hakkında uyarılmamanız anlamında çalışır. Typecript'teki
PaulG

5
OP'nin "Bu hatayı nasıl aşarım?" Diye sorduğunu belirtmeliyim. değil, "Bu sorunu nasıl çözerim?"
devinbost

Basitçe name: string = undefined ekleyerek (json2typescript gibi paketler tarafından önerildiği gibi), katı kapatmadığınız sürece 2322 hatası verir, çoğu insanın yapması gereken şey budur. Kabul edilen bu cevap açık, doğru ve daha pek çok oyu hak ediyor.
AUSTX_RJL
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.