TypeScript: 型 'string | undefined' は型 'string' に割り当てることができません
インターフェースの任意のプロパティをオプションにし、そのメンバーをこのように他の変数に代入するとき:
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
次のようなエラーが発生します:
TS2322: Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
このエラーをどうやって回避すればいいですか?
回答 #1
あなたは今、まさにあなたのユースケースのために用意された非ヌルアサーション演算子を使うことができます。
それは、何かが null である可能性があるように見えても、そうではないと信頼してよいと TypeScript に伝えます。
let name1:string = person.name!;
// ^ note the exclamation mark here
回答 #2
これは少し遅いかもしれないことは知っていますが、yannick の回答以外に ! を使う方法の一つは、それを文字列としてキャストすることです。これにより TypeScript に「これは文字列であると確信しています」と伝え、変換することができます。
let name1:string = person.name; // Error here compile time
〜へ
let name1 = person.name as string; // No error here compile time, runtime though
これによりエラーは解消されますが、もしこれが文字列ではない場合、実行時エラーが発生します… これは、型が一致することを保証し、コンパイル時にそのようなエラーを回避するためにTypeScriptを使用している理由の一つです。
回答 #3
コンパイルエラーを避けるために私は使用した
let name1:string = person.name || '';
そして空の文字列を検証します。
回答 #4
TypeScript 3.7以降では、null合体演算子 ?? を使用できます。この機能は、nullまたはundefinedを扱う際にデフォルト値に「フォールバック」する方法と考えることができます。
let name1:string = person.name ?? '';
?? 演算子は、デフォルト値を使用しようとする際に || の使用を置き換えることができ、|| を使用できないブール値、数値などを扱う場合に使用できます。
TypeScript 4 以降では、??= 代入演算子を a ??= b のように使用できます。これは a=a ?? b; の代替です。
回答 #5
あなたの定義によれば、Person.name は null になり得ますが、name1 はなれません。二つのシナリオがあります:
Person.nameは決してnullではありません
コンパイラに、名前が null でないことを ! を使って伝えます
let name1: string = person.name!;
Person.name は null である可能性があります
name が null の場合にデフォルト値を指定する
let name1: string = person.name ?? "default name";
回答 #6
これをより本番向けに扱う方法は、実際にnameが存在することを確認することです。これは複数の人が関わるより大きなプロジェクトの最小限の例だと仮定すると、将来的にgetPersonがどのように変わるかは分かりません。
if (!person.name) {
throw new Error("Unexpected error: Missing name");
}
let name1: string = person.name;
あるいは、name1 を string | undefined として入力し、下の方で undefined の場合の処理を行うこともできます。しかし、通常は予期しないエラーは早めに処理する方が良いです。
明示的な型を省略することで、TypeScript に型を推論させることもできます:let name1=person.name こうすることで、たとえば name1 を数字に再代入することを防ぐことができます。
回答 #7
何が起こっているのかを素早く把握する方法はこちらです:
あなたが次のことをしたとき:
名前?:文字列
あなたはそれが任意であるとTypeScriptに言っていました。それにもかかわらず、あなたがしたとき:
let name1 : string = person.name; //<<<Error here
あなたはそれに選択肢を残さなかった。それには未定義の型を反映する Union が必要だった:
let name1 : string | undefined = person.name; //<<<No error here
あなたの答えを使って、基本的にはインターフェース、クラス、オブジェクトである次のものを描くことができました。この方法の方が簡単だと思います、あなたがそう思わなくてもかまいません。
// 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());
回答 #8
事前に実際の値が何かを確認するようにしてください。もし person に有効な name がある場合は、それを name1 に代入し、そうでなければ undefined を代入します。
let name1: string = (person.name) ? person.name : undefined;
