Typoskript: Geben Sie 'string | ein undefined 'kann nicht dem Typ' string 'zugewiesen werden


100

Wenn ich eine Eigenschaft einer Schnittstelle optional mache, tritt beim Zuweisen ihres Mitglieds zu einer anderen Variablen ein Fehler wie der folgende auf

TS2322: Geben Sie 'string | ein undefined 'kann nicht dem Typ' string 'zugewiesen werden. Der Typ 'undefined' kann nicht dem Typ 'string' zugewiesen werden.

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 

Wie komme ich um diesen Fehler herum?

Antworten:


187

Sie können jetzt den Assertion-Operator ungleich Null verwenden, der genau für Ihren Anwendungsfall hier ist.

Es sagt TypeScript, dass, obwohl etwas so aussieht, als könnte es null sein, es Ihnen vertrauen kann, dass es nicht:

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

3
Genau das habe ich gesucht!
— Shautieh

1
Bis ESLint die Verwendung des Nicht-Null-Assertion-Operators nicht einschränkt :)
— Anatoly

3
Ich bin schockiert, dass so etwas existieren muss. 🤯
— GONeale

@GONeale Es gibt viele Fälle, in denen der Transpiler nicht selbst herausfinden kann, dass ein Wert nicht null sein kann. Ein Beispiel ist ein Wert, der z. B. von Angular festgelegt wurde, und Angular hat seine eigene Methode, um sicherzustellen, dass der Wert nicht null sein kann.
— yannick1976

19
Das ist ein schrecklicher Rat! Helfen Sie stattdessen dem Compiler, es herauszufinden. Fügen Sie vor dem Zugriff auf die Eigenschaft einen Scheck hinzu, den Sie entweder werfen oder zurückgeben, wenn der Name nicht festgelegt ist.
— Geon

56

Um den Kompilierungsfehler zu vermeiden, den ich verwendet habe

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

Überprüfen Sie dann die leere Zeichenfolge.


1
Was ist, wenn es kein String, sondern ein Objekt ist?
— Anatoly

1
Wenn es ein Objekt ist, dann wird es anstelle von '' {}
— Kriti

Dies ist etwas, was Sie tun können, wenn Sie Werte verketten und diese Art von Fehler erhaltenOptional chain expressions can return undefined by design - using a non-null assertion is unsafe and wrong.
— 23.

26

Ich weiß, dass dies eine etwas späte Antwort ist, aber eine andere Möglichkeit als Yannicks Antwort https://stackoverflow.com/a/57062363/6603342 zu verwenden! ist es, es als Zeichenfolge zu konvertieren und so TypeScript zu sagen, dass ich sicher bin, dass dies eine Zeichenfolge ist, die konvertiert

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

zu

let name1:string = person.name as string;

Dadurch wird der Fehler behoben, aber wenn dies zufällig keine Zeichenfolge ist , wird ein Laufzeitfehler angezeigt. Dies ist einer der Gründe, warum wir TypeScript verwenden, um sicherzustellen, dass der Typ übereinstimmt, und um solche Fehler beim Kompilieren zu vermeiden .


Dadurch wird der Fehler möglicherweise behoben, der tatsächliche Typ der Variablen wird jedoch nie geändert.
— Mansi

Es tut mir leid, aber ich denke, Sie irren sich dort ziemlich, da ich erwähnt habe, dass dies tatsächlich den Typ ändert, da es eine Laufzeitausnahme auslöst, wenn der Typ kein String ist oder keine toString-Methode hat. Dadurch wird alles, was sich dort befindet, in eine Zeichenfolge umgewandelt. Wenn Sie also eine Nummer haben, wird versucht, die .toString-Funktion von allem aufzurufen, was Sie dort haben.
— Harry

Aber das ist nicht der richtige Weg, sagen wir, wenn mein Name die Nummer "0" enthält, würde er es einfach in eine Zeichenfolge verwandeln ... Vielmehr sollte es einen Fehler auslösen und einen ungültigen Namen sagen. Persönlich würde ich diesen Typecast nicht verwenden und speziell nach dem im Objekt übergebenen Typ
— Mansi

Ja, aber dies völlig aus dem Kontext der Frage heraus, die diese Antwort gegeben hat. Wir wissen nicht, ob dies ein Formular ist, wenn es keine Schritte gibt, um dies vorher herauszufiltern. Auch was Sie vorschlagen, wäre zu diesem Zeitpunkt ohne einige wirklich schmutzige Problemumgehungen unmöglich.
— Harry

Keine Problemumgehungen erforderlich, nur eine Überprüfung, bevor Sie versuchen, auf die Variable zuzugreifen. Beide Fälle würden leicht behandelt, Fehler würden verschwinden und Ihr Code wird sicherer. Probieren Sie es einfach aus :)
— Mansi

21

Ab TypeScript 3.7 können Sie den nullish coalescing operator verwenden ?? . Sie können sich diese Funktion als eine Möglichkeit vorstellen, auf einen Standardwert zurückzugreifen, wenn Sie mit null oder undefiniert arbeiten

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

Der ??Operator kann Verwendungen von ersetzen, ||wenn versucht wird, einen Standardwert zu verwenden, und kann verwendet werden, wenn Boolesche Werte, Zahlen usw. ||verwendet werden, die nicht verwendet werden können.

Ab TypeScript 4 können Sie den ??=Zuweisungsoperator als a ??= bAlternative zu verwendena = a ?? b;


7

Versuchen Sie vorher herauszufinden, wie hoch der tatsächliche Wert ist. Wenn personeine gültige vorhanden ist name, weisen Sie sie zu name1, andernfalls weisen Sie sie zu undefined.

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

2
Hmmm. Das ist zu ausführlich, wenn ich mehrere Aufgaben ausführen möchte. Gibt es eine Möglichkeit, diese spezielle Warnung auszuschalten?
— Asdasd

leider nicht, außer Sie machen nameobligatorisch durch Entfernen des Fragezeichens.
— Lynx 242

PS: Welche Version von TypeScript verwenden Sie? Ich benutze 3.2.4 und stoße nicht auf diese Nachricht. In meiner Testklasse wird der Code perfekt kompiliert.
— Lynx 242

gleiche Version. Ich bekomme diesen Fehler im Webstorm, aber nicht in vscode
— asdasd

Das ist seltsam, weil ich IntelliJ verwende, das WebStorm ähneln soll, wenn es um die Anwendung von TS-Regeln geht?!
— Lynx 242

5

Eine produktionsfähigere Möglichkeit, dies zu handhaben, besteht darin, sicherzustellen, dass diese namevorhanden ist. Angenommen, dies ist ein minimales Beispiel für ein größeres Projekt, an dem eine Gruppe von Menschen beteiligt ist, wissen Sie nicht, wie getPersonsich dies in Zukunft ändern wird.

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

let name1: string = person.name;

Alternativ können Sie name1als string | undefinedeingeben und Fälle undefinedweiter unten behandeln. In der Regel ist es jedoch besser, unerwartete Fehler früher zu behandeln.

Sie können TypeScript auch auf den Typ schließen lassen, indem Sie den expliziten Typ weglassen: let name1 = person.nameDadurch wird weiterhin verhindert name1, dass er beispielsweise als Nummer neu zugewiesen wird.


3

Hier ist ein schneller Weg, um zu erfahren, was gerade passiert:

Als Sie Folgendes getan haben:

Name? : string

Sie sagten zu TypeScript, es sei optional. Trotzdem, als du es getan hast:

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

Sie haben keine Wahl gelassen. Sie mussten eine Union haben, die den undefinierten Typ widerspiegelt:

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

Mit Ihrer Antwort konnte ich Folgendes skizzieren, nämlich eine Schnittstelle, eine Klasse und ein Objekt. Ich finde diesen Ansatz einfacher, egal wenn Sie es nicht tun.

// 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

Sie versuchen, eine Variable name1festzulegen, wobei der Hexentyp als strenge Zeichenfolge festgelegt wird (es MUSS eine Zeichenfolge sein), wobei der Wert aus dem Objektfeld stammt name, und der Hexentyp als optionale Zeichenfolge festgelegt wird (er kann aufgrund des Fragezeichens eine Zeichenfolge oder undefiniert sein). Wenn Sie dieses Verhalten wirklich benötigen, müssen Sie den Typ folgendermaßen ändern name1:

let name1: string | undefined = person.name;

Und es wird in Ordnung sein;


0

Beachten Sie, dass Sie Standardwerte angeben können, wenn die Variable aus einem Array oder einer Destrukturierung stammt:

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

Sie können den NonNullableDienstprogrammtyp verwenden:

Beispiel

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

Docs .


-1

Lösung 1: Entfernen Sie die explizite Typdefinition

Da getPersonbereits a Personmit einem Namen zurückgegeben wird, können wir den abgeleiteten Typ verwenden.

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

let person = getPerson();

Wenn wir definieren person: Personwürden, würden wir eine Information verlieren. Wir wissen, dass getPersonein Objekt mit einer nicht optionalen Eigenschaft namens zurückgegeben wird name, es jedoch so beschreibt, als Personwürde es die Optionalität zurückbringen.

Lösung 2: Verwenden Sie eine genauere Definition

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;

Lösung 3: Gestalten Sie Ihre Benutzeroberfläche neu

Eine Form, in der alle Eigenschaften optional sind, wird als schwacher Typ bezeichnet und ist normalerweise ein Indikator für schlechtes Design. Wenn wir nameeine erforderliche Immobilie herstellen, verschwindet Ihr Problem.

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

-14

Hatte das gleiche Problem.

Ich finde heraus, dass React-Scrips "strict": truedazu beitragen tsconfig.json.

Nachdem ich es entfernt habe, funktioniert alles super.

Bearbeiten

Sie müssen warnen, dass das Ändern dieser Eigenschaft Folgendes bedeutet:

nicht mehr vor möglichen Laufzeitfehlern gewarnt werden.

wie von PaulG in Kommentaren hervorgehoben! Danke :)

Verwenden Sie "strict": falsenur , wenn Sie verstehen , was es wirkt!


9
Dies kann "funktionieren". Dies funktioniert jedoch nur in dem Sinne, dass Sie nicht mehr vor möglichen Laufzeitfehlern gewarnt werden. Ich würde dazu ermutigen, Nachforschungen darüber anzustellen,
— PaulG

5
Ich sollte erwähnen, dass das OP fragte: "Wie komme ich um diesen Fehler herum?" nicht "Wie behebe ich dieses Problem?"
— Devinbost

Durch einfaches Hinzufügen des Namens: string = undefined (wie von Paketen wie json2typescript empfohlen) wird der Fehler 2322 ausgelöst, es sei denn, Sie deaktivieren strikt, was die meisten Benutzer tun müssen. Diese akzeptierte Antwort ist klar, richtig und verdient viel mehr Stimmen.
— AUSTX_RJL
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.