2017-07-31 5 views
0

私のTSコードはstrictNullChecksnoImplicitAnyを使用してコンパイルされており、対処する選択肢がたくさんあります。私は、変数(および他の関連する変数)を定義する必要があるかどうかを示すブールチェッカー関数を使用したいと思います。簡単な例:ブール値フラグに基づいて複数の関連変数をnull以外で未定義でないと宣言する

class Person { 
    private firstName: string; 
    private firstNameSyllables: number; 

    private middleName?: string; 
    private middleNameSyllables?: number; 
    private hasMiddleName: boolean; 

    constructor(firstName: string, middleName?: string){ 
     this.firstName = firstName; 
     this.firstNameSyllables = calculateSyllables(firstName); 

     if(typeof middleName !== "undefined"){ 
      this.middleName = middleName; 
      this.middleNameSyllables = calculateSyllables(middleName); 
      this.hasMiddleName = true; 
     } else { 
      this.hasMiddleName = false; 
     } 
    } 

    // Stub function 
    calculateSyllables(name: string): number { return name.length/3; } 
    hasMiddleNameCheck(): boolean { return this.hasMiddleName; } 

    getStartOfNameWithSyllables(): string { 
     if(this.hasMiddleNameCheck()){ 
      // ERROR: middleName and middleNameSyllables may be undefined 
      return `${this.firstName}: ${this.firstNameSyllables},` + 
        `${this.middleName}: ${this.middleNameSyllables}`; 
     } else { 
      return `${this.firstName}: ${this.firstNameSyllables}`; 
     } 
    } 
} 

は、どのように私は、コンパイラがmiddleNamemiddleNameSyllables両方がtrueを返すthis.hasMiddleNameCheck()の結果として、定義されるべきであることを推測するために得ることができますか?現在は、middleName as stringmiddleName!などの型アサーションを使用して問題を回避する必要がありますが、変数をオプションにするリファクタでは、定義されていない可能性のある変数をすべて1回だけ使用するため、これは望ましくありません。

+0

「ヌル」値はどうですか?フィールド自体が値を持っているかどうかチェックできるかどうか、なぜブール値フラグを使用したいのですか?コンパイラには限界があります。それは魔法ではありません。 –

+0

なぜフラグを捨てて、 'if(this.middleName!= null && this.middleNameSyllables!= null)'を明示的にチェックして、次のステートメントの内容と明確に一致するのはなぜですか? 'x!= null'は' x === null'と 'x === undefined'の両方に当てはまります。 – Duncan

答えて

1

あなたはuser-defined type guardspecial typeでこれを行うことができます:再び型推論はどちらも、あなたがそれを使用する場合undefinedではないことを知っているだろう

class Person { 
    ... 
    protected middleName?: string; 
    protected middleNameSyllables?: number; 
    protected hasMiddleName: boolean; 
    ... 
} 

、あなたは(あなたが実際にインスタンス化するつもりはありません)PersonWithMiddleNameと呼ばれる新しいサブクラスを宣言することができPerson宣言の後:

最後に
class PersonWithMiddleName extends Person { 
    hasMiddleName: true; 
    middleName: string; 
    middleNameSyllables: number; 
} 

hasMiddleNameCheck()の戻り値の型に変更:

hasMiddleNameCheck(): this is PersonWithMiddleName { 
    return this.hasMiddleName; 
} 

すべてがうまくいくはずです。 private/protectedあなたが守ろうとしているメンバーの性質はこれをより複雑にします。彼らが一般公開されている場合は、Personをサブクラス化する必要はありません。


これはあなたにあまりにも複雑に感じている場合は、関連する変数に

interface MiddleName { 
    name: string; 
    syllables: number; 
} 

のような単一のオブジェクトを作成することもできますし、その後PersonはオプションMiddleNameを持っています

class Person { 
    ... 
    private middleName?: MiddleName; 
    ... 
} 

は、次に、this.middleNameが定義されているかどうかを確認し、this.middleName.namethis.middleName.syllablesにアクセスしてください。これはmucではありませんより冗長であり、これらがすべて定義されているか、すべて定義されていないことが非常に明白です。

希望に役立ちます。がんばろう!

+0

最初のものは美しい解決策です。私が探していたもの、感謝! 2つ目の解決策は単純なケースで機能しますが、2つの異なる状況でオプションのプロパティが定義されている場合(つまり、 'MiddleName'のように1つのクラスの下にオプションプロパティをネストすることができない場合) –

0

すべての中で最も簡単な修正は、オプションでthis.middleNameSyllablesを持たないことですが、デフォルトでは0になります。代わりに、フラグ変数のthis.middleName != nullのための明示的なチェックをし、コンパイラが両方の値と幸せになることを組み合わせる:

private middleNameSyllables: number = 0; 
... 
getStartOfNameWithSyllables(): string { 
    if(this.middleName != null){ 
     return `${this.firstName}: ${this.firstNameSyllables},` + 
       `${this.middleName}: ${this.middleNameSyllables}`; 
    } else { 
     return `${this.firstName}: ${this.firstNameSyllables}`; 
    } 
} 

それともあなただけの状態で両方の値をチェックし、同様にオプションの数を維持することを好む場合あなたがprotectedにごprivateメンバーの一部を変更する許可した場合

getStartOfNameWithSyllables(): string { 
    if(this.middleName != null && this.middleNameSyllables != null){ 
     return `${this.firstName}: ${this.firstNameSyllables},` + 
       `${this.middleName}: ${this.middleNameSyllables}`; 
    } else { 
     return `${this.firstName}: ${this.firstNameSyllables}`; 
    } 
} 
関連する問題