Typescript: 提案: `object`プリミティブ型

作成日 2015年01月26日  ·  17コメント  ·  ソース: microsoft/TypeScript

objectプリミティブ型

この提案では、typescript object新しいプリミティブ型について説明します。

使用事例

JavaScriptコアAPIには、パラメーターとしてobjectを受け取るいくつかの関数が含まれています。

  • Object.getPrototypeOf
  • Object.getOwnPropertyDescriptor
  • Object.create
  • ...等

現在、typescriptには、他のプリミティブ型( stringnumberなど)がこれらの関数に渡されるのを防ぐ方法はありません。
たとえば、 Object.create('string')は、エラーが発生した場合でも、完全に有効なtypescriptステートメントです。
新しいobjectプリミティブ型を作成すると、これらの関数のシグネチャ、および同様の制約を共有するすべての関数をより正確にモデル化できます。

型チェック

割り当て可能性

objectタイプは、 {}から他の基本タイプの割り当て可能性を引いたものに相当します。つまり、次のようになります。

  • その他の基本的なタイプはobject割り当てることができません
  • 基本以外のタイプはobject割り当てることができます
  • オブジェクトは{}anyのみ割り当てることができます

この動作はjavascriptの動作と一貫性があり、型は制約typeof value === 'object'undefinedを尊重するすべての値を表します。

タイプガード

objecttypeof value === 'object'新しいタイプのガードを導入する必要があります。
オプションで、コンパイラーはObject関数キャストとの比較を受け入れることもできます: Object(value) === value

Suggestion help wanted

最も参考になるコメント

この提案に+1します。 WeakMapを「エキスパート」APIとは見なしませんが、これを実装するのに十分な理由があると思います。 ランタイムはオブジェクトタイプとプリミティブタイプを区別するため、TypeScriptに区別を行う機能があることだけが意味があります。

この提案は、各プロパティがオプションである「オブジェクトバッグ」の入力の問題も解決しますが、他のプリミティブ型は許可しないでください。

全てのコメント17件

これの恩恵を受ける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タイプは、関数を含むオブジェクト言語タイプを反映する必要があるように思われます。 これにはいくつかの理由があります。

  • 私の知る限り、プレーンオブジェクトを常に受け​​入れるAPIは、関数も受け入れます。
  • 関数Objectコンストラクターから継承します。

これらを順番に取ります。

API

オブジェクトのみを受け取るWeakMapなどのAPIは、プレーンオブジェクトだけでなく、オブジェクト言語タイプを受け入れます。 以下は問題ありません。

function theAnswer() {}

let map = new WeakMap();

map.set(theAnswer, 42);
console.log(map.get(theAnswer)); // 42

これは、組み込みAPIの場合と同様にカスタムAPIにも当てはまります。 オブジェクトが必要な場合は、通常、プロパティのバンドルが必要です。 関数は、呼び出し可能なプロパティのバンドルにすぎません。

継承

FunctionObjectコンストラクターを拡張するため、 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 { /* ... */ }
}

? ( objectObject )。 FunctionObjectから拡張されているように思われるので、なぜそれができないのかわかりません。 説明できますか?

@trusktr nullundefined以外のすべての値は、 Objectタイプに割り当てることができます。 Objectを受け入れる関数は、文字列、数値、ブール値、または記号を取ります。 object割り当てることができるのは非プリミティブ値のみです。 文字列などを渡すと、コンパイル時エラーが発生します。 objectタイプは、非プリミティブ値が必要であるが、そのプロパティが何であるかを気にしない場合に役立ちます。

このページは役に立ちましたか?
0 / 5 - 0 評価