2016-04-27 5 views
0

前述のように、typescriptは静的な型指定を可能にし、コンパイラの型チェックは早期バインディングまたは遅延バインディングのパラダイムで行われます。私は、タイスクリプトのトランスコンプリータは、早期バインディングスタイルのようなものを使用していると思います。コンパイラは型チェックを完了するために、実行時に型をチェックするために生成されたオブジェクトにいくつかのコードを追加する必要があります。私が見てきたように、typescriptは実行時に型をチェックするための余分なjsコードを追加しません。このスタイルは私たちのチームにとっていくつか問題でした。例えば以下のコードでは、mメソッドを呼び出す論理的な結果は1312であるか、JavaのClassCastExceptionのようないくつかの例外があります。結果は他にもあります:型チェックが貧弱で実行時型チェックのコード生成が不十分であるためにtypescriptが正しくない

function m(a:string){ 
    console.log(a+12) 
} 

var a:any=13 
m(a as string) // result is 25 

この問題のために私たちのプロジェクトのtypescriptをjsに置き換えてください。

+4

* "この問題のために私たちのプロジェクトのtypescriptをjsに置き換えてください。" *これはあなた次第です。この場合、* real *の問題は、作者が 'aが文字列である 'と書いたことです。これはコンパイラにあります(' aは文字列であると主張しています)'(http://www.typescriptlang.org/docs/handbook /jsx.html#the-as-operator)を参照してください。コンパイラにはない*文字列に*変換*する必要があります。 –

+1

私は、** as **キーワードに関して最も大きな混乱があると思います。これは指定された型への**キャスト**ではありません。これは**型のアサーション**です。これを行うことで、コンパイラはaの型を文字列(実際の型に関係なく)とみなすべきです。 – toskv

+0

ToskvとTJ Crowderは正確に正しいです。数値を文字列にキャストするには、.toString()またはJavaScriptのtype coersionを使用する必要があります。 'as'キーワードは、別の型への変数ではありません。 – Martin

答えて

3

Typescriptはライブラリではありません。言語であり、実行時に型の強制がないため、追加の機能はありません(ここではpollyfilのみ)。言われていること

あなたがこれを行う場合ので、あなたの例では、typescriptですがコンパイラに正義を行いません:Neither type 'number' nor type 'string' is assignable to the other

var a: number = 13; 
m(a as string); 

をあなたがエラーを取得します。
さらに複雑な例で:

interface A { 
    a: number; 
} 

interface B { 
    b: string; 
} 

function echoNumber(a: A): number { 
    return a.a; 
} 

console.log(echoNumber(<A> { b : "str" })); 

あなたは同じエラーを取得します。

typescriptはうまくいきますが、それはうまくいきますが、anyを使用すると、javascriptで直接作業する可能性があるため、タイプスクリプトの全体的なポイントanyのタイプではありません(必要な場合のみ)。

+0

はい、しかし、私は 'any'型の存在は、実行時の型チェックのためのいくつかの余分なコードが必要と思う。そして、これがなければ、開発者は型チェックの段階を渡すことができます – Pooya

+0

@Пуяしかし、それは実際の言語(javascript)のランタイムです。そして、哲学としてのタイスクリプトは単なる言語です。タイプ強制。しかし、あなたはそれを自分で実装することができます。また、開発者が適切でないときに 'any'を使用しないようにしてください。 –

+1

+1からNitzan。 'any'型は、人々がTypeScriptプログラム内で動的なJavaScriptに落とせるように特別に設計されています。それを日常的に使用する理由はなく、 'noImplicitAny'を使用して誤った使用を避けることができます。ハンマーを使って窓にぴったり合ってからガラスを割ったと不平を言う。 – Fenton

1

これらのケースでは、TypeScriptをJavascriptにコンパイルするときに、効率が重視されます。つまり、必ずしも必要ではないコード(例えば、__extendまたは__decorate関数)は出力から除外されます。コンパイラに対するは処理すべきものではありませんが、実行時の型のエラーは実際には実際の使用事例からも発生することがあります。

しかし、私はこのような実行時の型の不一致にエレガントなソリューションであることを起こる一つは活字体が提供すべて利点、残すための弱い理由であることを見つけるだろう:decoratorsを。特にreflect-metadataと組み合わせて使用​​する場合。

あなたはクラスのメソッドとしてmを含めるとしたら、あなたは正しい型の値は、実行時に渡されていることを確認するためにmethod decoratorを使用することができます。

IMO
function TypeCheck(
    target: any, 
    propertyKey: string, 
    propertyDescriptor: PropertyDescriptor 
): any { 
    var originalMethod = target[propertyKey].bind(target); 
    var paramTypes = Reflect.getMetadata("design:paramtypes", target, propertyKey); 

    // Return a new property descriptor for the decorated method. 
    return { 
     value: function() { 
      // Check argument types. 
      for (var i = 0; i < arguments.length; i++) { 
       switch (paramTypes[i]) { 
        case String: 
         if (!(arguments[i] instanceof paramTypes[i]) && typeof arguments[i] !== "string") { 
          throw new TypeError(`Expected argument ${i} to be of type 'string'.`); 
         } 
         break; 

        case Number: 
         if (!(arguments[i] instanceof paramTypes[i]) && typeof arguments[i] !== "number") { 
          throw new TypeError(`Expected argument ${i} to be of type 'number'.`); 
         } 
         break; 

        case Boolean: 
         if (!(arguments[i] instanceof paramTypes[i]) && typeof arguments[i] !== "boolean") { 
          throw new TypeError(`Expected argument ${i} to be of type 'boolean'.`); 
         } 
         break; 

        default: 
         if (!(arguments[i] instanceof paramTypes[i])) { 
          throw new TypeError(`Expected argument ${i} to be of type '${paramTypes[i].prototype.toString.call(paramTypes[i]).toString()}'.`); 
         } 
         break; 
       } 

      } 

      // Call original method. 
      return originalMethod.apply(target, arguments); 
     } 
    }; 
} 
class Foo { 
    @TypeCheck 
    public m(a: string) { 
     console.log(a + 12); 
    } 
} 

var foo = new Foo(); 
foo.m(13 as any); // Will throw TypeError. 

これは、最も洗練されたソリューションを提供します。追加のワンタイムセットアップを追加する必要があります。はい、TypeCheckデコレータは肥大化したように見えますが、ので、いくつかの種類がちょうど、追加チェックが必要です。

"some string" instanceof String; // false 

...メタデータを反映させることで、プリミティブのタイプ情報としてラッパーオブジェクトも提供されます。

-1

as stringと混同しています。

エラーは、TypeScriptとは何の関係もありません。これはJavaScriptエラーです。 numbernumberにキャストできるstringを追加すると、JavaScriptはstringnumberにキャストして追加します。

あなたは、単に正しいタイプを使用することによって、この問題を解決することができます。

function m(a: string){ 
    console.log(a + "12") 
} 

var a: string = "13". 
m(a) // result is 1312 

var b = 13.toString(); 
m(b) // result is 1312 

var c = 13; 
m(b.toString()) // result is 1312 

var d = 13; 
m(d) // Combile Error 

var e = "13"; 
m(3) // result is 1312 

また、あなたは活字体タイプガードと一緒にJavaScriptの実行時の型チェックを使用することができます。

function(a: string | number) { 
    If (typeof a == 'number') { 
     console.log('13' + a.toString()); 
    } else { 
     console.log('13' + a); 
    } 
} 
関連する問題