object
プリミティブ型この提案では、typescript object
新しいプリミティブ型について説明します。
JavaScriptコアAPIには、パラメーターとしてobject
を受け取るいくつかの関数が含まれています。
Object.getPrototypeOf
Object.getOwnPropertyDescriptor
Object.create
現在、typescriptには、他のプリミティブ型( string
、 number
など)がこれらの関数に渡されるのを防ぐ方法はありません。
たとえば、 Object.create('string')
は、エラーが発生した場合でも、完全に有効なtypescriptステートメントです。
新しいobject
プリミティブ型を作成すると、これらの関数のシグネチャ、および同様の制約を共有するすべての関数をより正確にモデル化できます。
object
タイプは、 {}
から他の基本タイプの割り当て可能性を引いたものに相当します。つまり、次のようになります。
object
割り当てることができませんobject
割り当てることができます{}
とany
のみ割り当てることができますこの動作はjavascriptの動作と一貫性があり、型は制約typeof value === 'object'
とundefined
を尊重するすべての値を表します。
object
: typeof value === 'object'
新しいタイプのガードを導入する必要があります。
オプションで、コンパイラーはObject
関数キャストとの比較を受け入れることもできます: Object(value) === value
。
これの恩恵を受けるObject.
関数以外のいくつかのAPIをリストすると便利です。
Object
を除くjavascriptコアAPIでは、おそらく一部のes6コンストラクトのみがこれから恩恵を受けます(WeakMap、Proxyなど)。
ただし、たとえば、すべてのアンダースコアコレクション関数もより適切な入力を取得します。Reactのようなフレームワークは、オブジェクトまたはnull
、ImmutableJS、Moriなどのみを受け入れる「setState」メソッドを使用します。
編集:アンダースコアコレクションは任意のタイプで機能します
提案検討会で議論。 これはすべて理にかなっていますが、新しいプリミティブ型の複雑さを、エラーの数/提供できる記述の豊富さで正当化する必要があります。 基本的に、プリミティブを操作できないAPIの例、特に「エキスパート」APIではないAPIの例(プロキシなど)
推奨よりも参照として投稿する:wink:
interface String { _primitiveBrand?: string; }
interface Boolean { _primitiveBrand?: boolean; }
interface Number { _primitiveBrand?: number; }
interface ObjectOnly { _primitiveBrand?: void; }
function fn(x: ObjectOnly) { }
// Error
fn(43);
// Error
fn('foo');
// OK
fn({});
// OK
fn(window);
この提案に+1します。 WeakMap
を「エキスパート」APIとは見なしませんが、これを実装するのに十分な理由があると思います。 ランタイムはオブジェクトタイプとプリミティブタイプを区別するため、TypeScriptに区別を行う機能があることだけが意味があります。
この提案は、各プロパティがオプションである「オブジェクトバッグ」の入力の問題も解決しますが、他のプリミティブ型は許可しないでください。
Object.observe
は、非プリミティブターゲットも必要です: http :
タイトルは「プリミティブ」という言葉を使っているので少しわかりにくいと思います。 これは、_ "ECMAScriptオブジェクトタイプ" _または_ "ランタイムオブジェクトタイプ" _と呼ばれることもあります。 これは、プリミティブ型( undefined
型とシンボルを含む)、関数、またはコンストラクター型以外から割り当てることができます。 正当なobject
タイプとは何かの基準は、次のガードに基づく必要があります。
let isObject (x) => typeof x === "object";
MDNによると、これはtypeof
の出力です。
未定義:「未定義」
Null :「オブジェクト」(以下を参照)
ブール値: "boolean"
番号:「番号」
文字列:「文字列」
シンボル(ECMAScript 2015の新機能) :「シンボル」
ホストオブジェクト(JS環境によって提供される) :実装に依存
関数オブジェクト(ECMA-262用語で[[Call]]を実装) : "function"
その他のオブジェクト:「オブジェクト」
このタイプがないと、ユーザー定義のガードであっても、上記のガードの正確なタイプを正しく一致させる方法はありません。 これは、プロパティを持ち、 for in
ループとObject
プロトタイプの呼び出しを許可するオブジェクトを厳密に必要とする関数で使用する場合や、 T extends object
などの一般的な制約を実装する場合にも不可欠です。次に、プロパティを安全に参照するか、プロトタイプ関数を使用します。
ただし、関数とコンストラクターを除外すると、場合によっては少し制限されるため、それらも含めて_ "非プリミティブオブジェクトタイプ" _と呼ばれる別のタイプが存在する可能性があります。 部分的な回避策は、和集合object | Function
可能性がありますが、それを正しく処理するにはキャストまたは追加のガードが必要になります。
PRの受け入れ。 これは一般的な問題のようです。 これは、 interface object { ... }
を書いた勇気のある人にとっては重大な変更になります。 実装は簡単で、上記のルールに従う必要があります。
補足: @fdecampredonがどこにあるのか疑問に
@RyanCavanaugh仕事の町の変更、そして残念ながら私の新しい仕事では多くのタイプスクリプトはありません:D
すごい。 TS1.8でこのタイプを使いたいです。
object
タイプのようなものも見たいです。 ただし、関数が除外されるため、 typeof value === 'object'
に準拠する必要があるかどうか疑問に思います。 代わりに、予想されるobject
タイプは、関数を含むオブジェクト言語タイプを反映する必要があるように思われます。 これにはいくつかの理由があります。
これらを順番に取ります。
オブジェクトのみを受け取るWeakMap
などのAPIは、プレーンオブジェクトだけでなく、オブジェクト言語タイプを受け入れます。 以下は問題ありません。
function theAnswer() {}
let map = new WeakMap();
map.set(theAnswer, 42);
console.log(map.get(theAnswer)); // 42
これは、組み込みAPIの場合と同様にカスタムAPIにも当てはまります。 オブジェクトが必要な場合は、通常、プロパティのバンドルが必要です。 関数は、呼び出し可能なプロパティのバンドルにすぎません。
Function
はObject
コンストラクターを拡張するため、 Object
で使用可能な静的メソッドとインスタンスメソッドを関数でも使用できます。 たとえば、次のことが可能です。
class DeepThought {
static getAnswer() {
return 42;
}
}
let computer = Object.create(DeepThought);
console.log(computer.getAnswer()); // 42
console.log(Object.getPrototypeOf(computer)); // [Function: DeepThought]
上記の例は少しばかげていますが、内部でObject
メソッドを使用するAPIが関数を受け入れることもできることを示しています。
したがって、 object
タイプは、オブジェクト言語タイプに対応する以下に準拠することをお勧めします(ただし、 null
が含まれていますが、TypeScriptではnull
に対する保護はありません。とにかく)。
function isObject(value) {
return typeof value === 'object' || typeof value === 'function';
}
私は、このプロジェクトが呼び出されディープ地図を道に沿ってネストされたオブジェクトと変換プリミティブ値のキーと値のペアによる再帰こと。 そのため、プリミティブ型と非プリミティブ型を区別します。 次のように、カスタムNonPrimitive
インターフェイスを定義する必要がありました。
interface NonPrimitive {
[key: string]: any;
[index: number]: any;
}
export class DeepMap {
// ...
private mapObject(obj: NonPrimitive): NonPrimitive { /* ... */ }
}
NonPrimitive
インターフェースを定義しなければならなかったのはこれが初めてではありません。 私がこれを行うことができればいいのですが:
export class DeepMap {
// ...
private mapObject(obj: object): object { /* ... */ }
}
上で提案したように、 obj
パラメーターが呼び出し可能かどうかはあまり気にしません。 重要なのは、それがObject
_language type_であるということです。つまり、キーと値のペアを反復処理できるプロパティのバンドルであるということです。
関数がobject
ことに同意します。 目的は、プリミティブを除外することです。
わかりました、それが意図だったに違いないと思いました。 typeof value === 'object'
話で何かが足りないと思っただけです。
このobject
タイプは、アドホックなプロパティ割り当て( any
)を許可しますか? 例えば:
const foo: object = {};
foo.bar = 'baz';
番号
の実際的な違いは何ですか
export class DeepMap {
// ...
private mapObject(obj: object): object { /* ... */ }
}
そして
export class DeepMap {
// ...
private mapObject(obj: Object): Object { /* ... */ }
}
? ( object
とObject
)。 Function
はObject
から拡張されているように思われるので、なぜそれができないのかわかりません。 説明できますか?
@trusktr null
とundefined
以外のすべての値は、 Object
タイプに割り当てることができます。 Object
を受け入れる関数は、文字列、数値、ブール値、または記号を取ります。 object
割り当てることができるのは非プリミティブ値のみです。 文字列などを渡すと、コンパイル時エラーが発生します。 object
タイプは、非プリミティブ値が必要であるが、そのプロパティが何であるかを気にしない場合に役立ちます。
最も参考になるコメント
この提案に+1します。
WeakMap
を「エキスパート」APIとは見なしませんが、これを実装するのに十分な理由があると思います。 ランタイムはオブジェクトタイプとプリミティブタイプを区別するため、TypeScriptに区別を行う機能があることだけが意味があります。この提案は、各プロパティがオプションである「オブジェクトバッグ」の入力の問題も解決しますが、他のプリミティブ型は許可しないでください。