TypeScriptのオブジェクトリテラルの型定義


343

TypeScriptクラスでは、プロパティの型を宣言できます。次に例を示します。

class className {
  property: string;
};

オブジェクトリテラルでプロパティの型を宣言するにはどうすればよいですか?

次のコードを試してみましたが、コンパイルできません。

var obj = {
  property: string;
};

次のエラーが発生します。

名前「string」は現在のスコープに存在しません

私は何か間違ったことをしていますか、これはバグですか?

回答:


423

あなたはかなり近い、あなただけ交換する必要があります=:。オブジェクト型リテラル(仕様セクション3.5.3を参照)またはインターフェースを使用できます。オブジェクト型リテラルを使用することは、あなたが持っているものに近いです:

var obj: { property: string; } = { property: "foo" };

しかし、インターフェースを使用することもできます

interface MyObjLayout {
    property: string;
}

var obj: MyObjLayout = { property: "foo" };

14
キャスト演算子を使用した@Rick LoveによるDRY(Do n't Repeat Yourself)オプションは、はるかにきれいに見えます。
投票するの

私はこれが少し前に答えられたことを知っていますが、クラスにメソッドとプロパティがある場合に問題が発生する可能性があるという仮定を誤っていますか?クラスは初期化されず、プロパティを割り当てるだけなので、クラスのメソッドを呼び出すとnull例外が発生します。基本的に、作成するオブジェクトは、その型を割り当てるため、クラスとして「機能する」だけですが、実際にはそのクラスのインスタンスではありません。つまり、「new」キーワードでクラスを作成する必要があります。そして、1に戻ります。newclass(){prop:1};のようなことはできないからです。たとえば、C#でできるようにTSで。
DeuxAlpha

@DeuxAlphaこれは、メソッドを持つことができないインターフェースに割り当てています。このようなクラスに割り当てられるとは思わない。
Mog0

スペックへのリンクがいいでしょう:)
ahong

@DeuxAlphaこれは、クラスオブジェクトではなく、オブジェクトリテラルを作成しています。また、インターフェースはメソッドを持つことができます。インターフェースがメソッドを定義する場合、オブジェクトリテラルもそれを定義する必要があります-それはnullにはなりません。オブジェクトリテラルは、インターフェイスが定義するすべてを満たす必要があります。そうしないと、型システムでエラーが表示されます。
リックラブ

291

2019-05-15の更新(代替としての改善されたコードパターン)

長年にわたってconstより機能的なコードを使用し、その恩恵を受けた後、ほとんどの場合、以下を使用しないことをお勧めします。(オブジェクトを構築するとき、型システムに型を推論させるのではなく、特定の型に型システムを強制することは、多くの場合、何かが間違っていることを示しています)。

代わりにconst、できるだけ変数を使用し、最後のステップとしてオブジェクトを作成することをお勧めします。

const id = GetId();
const hasStarted = true;
...
const hasFinished = false;
...
return {hasStarted, hasFinished, id};
  • これにより、明示的に入力する必要なく、すべてが適切に入力されます。
  • フィールド名を再入力する必要はありません。
  • これは私の経験から最もクリーンなコードにつながります。
  • これにより、コンパイラーはより多くの状態検証を提供できます(例えば、複数の場所に戻る場合、コンパイラーは常に同じタイプのオブジェクトが返されることを保証します-これにより、各位置で戻り値全体を宣言することを奨励します-完全に明確になりますその値の意図)。

追加2020-02-26

遅延初期化できる型が実際に必要な場合:null許容の共用体型(nullまたはType)であるとマークします。型システムは、最初に値があることを確認せずに使用できないようにします。

ではtsconfig.json、必ず厳密なnullチェックを有効にしてください。

"strictNullChecks": true

次に、このパターンを使用して、型システムが偶発的なnull /未定義のアクセスからユーザーを保護できるようにします。



const state = {
    instance: null as null | ApiService,
    // OR
    // instance: undefined as undefined | ApiService,

};

const useApi = () => {
    // If I try to use it here, the type system requires a safe way to access it

    // Simple lazy-initialization 
    const api = state?.instance ?? (state.instance = new ApiService());
    api.fun();

    // Also here are some ways to only access it if it has value:

    // The 'right' way: Typescript 3.7 required
    state.instance?.fun();

    // Or the old way: If you are stuck before Typescript 3.7
    state.instance && state.instance.fun();

    // Or the long winded way because the above just feels weird
    if (state.instance) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans way
    if (state.instance != null) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans 
    // AND I was told to always use triple === in javascript even with null checks way
    if (state.instance !== null && state.instance !== undefined) { state.instance.fun(); }
};

class ApiService {
    fun() {
        // Do something useful here
    }
}

99%の場合、以下を行わないでください。

更新2016-02-10-TSXを処理するには(@Joshに感謝)Update 2016-02-10-To Handle TSX(Thanks @Josh)

asTSX の演算子を使用します。

var obj = {
    property: null as string
};

より長い例:

var call = {
    hasStarted: null as boolean,
    hasFinished: null as boolean,
    id: null as number,
};

元の回答

キャスト演算子を使用してこれを簡潔にします(目的の型にnullをキャストします)。

var obj = {
    property: <string> null
};

より長い例:

var call = {
    hasStarted: <boolean> null,
    hasFinished: <boolean> null,
    id: <number> null,
};

これは、2つの部分(タイプを宣言する部分と、デフォルトを宣言する部分)を使用するよりもはるかに優れています。

var callVerbose: {
    hasStarted: boolean;
    hasFinished: boolean;
    id: number;
} = {
    hasStarted: null,
    hasFinished: null,
    id: null,
};

10
TSX(TS with JSX)を使用している場合、山かっこの名前は使用できないため、これらの行は次のようになりproperty: null as string、重要な違いはas演算子です。
Josh、

2
@RickLoveこれは実際にオブジェクト変数のタイプを制約しますか、それとも割り当て時にタイプを指定する方法にすぎませんか?つまり、call2番目の例で変数に割り当てた後、完全に異なる型を変数に割り当てることができますか?
Daniel Griscom 2016

3
これは答えになるはずです
Drew R

4
機能していません。Error:(33, 15) TS2352:Type 'null' cannot be converted to type 'string'.
slideshowp2 2017年

2
これは単に言語の機能の乱用ですか、それとも実際に合法ですか?公式のドキュメントへのモル読書のリンクを提供できますか?ありがとう!
2018

31

誰もこれについて言及していないことに驚いていますが、タイプのペアObjectLiteralを受け入れると呼ばれるインターフェイスを作成することができます:key: valuestring: any

interface ObjectLiteral {
  [key: string]: any;
}

次に、次のように使用します。

let data: ObjectLiteral = {
  hello: "world",
  goodbye: 1,
  // ...
};

追加のボーナスは、このインターフェイスを必要なだけ何度でも再利用できることです。

幸運を。


3
これは悪い考えです。型システムを価値のないものにします。typescriptのポイントは、型システムがエラーを防止し、ツールのオートコンプリート機能を改善できるようにすることです。これにより、基本的にTypescriptのすべての利点が無効になります。上記の例ではインターフェースを使用しない方が良いでしょう。
リック・ラブ

1
@RickLove私は強く同意しません。これは、いくつかのプロパティがオプションである場合に非常に役立ちますが、それでも(たとえば、関数の引数を含む)内のすべてのタイプを明確に定義する必要があります。これは単に構文上の砂糖と見なすことができ、文字通りインターフェイスのプロパティのスプレッドオペレーターのように機能します
CPHPython

@CPHPython特定のタイプのオプションパラメータを指定しないのはなぜですか?これが意味を持つのは、名前がコード時に不明な場合(つまり、データベースまたは外部ソースから取得された場合)だけです。また、引数の複雑な組み合わせの場合、共用体型はうまく機能します。特定の名前に対してコーディングする場合は、可能であれば定義する必要があります。ロジックに影響を与えないのがデータだけの場合は、もちろん型システムから除外します。
Rick Love、

1
@RickLove "名前はコードの時点では不明です"->これは良い実用的な例です。これらのキータイプの値は既知であり、すべて同じです(例:string)。マインドは、私が唯一の使用を提唱していること[key: string]の部分を、ない任意の値の型定義など一部...それは確かに種類の有用性を取ると思います。
CPHPython

1
文字列と数字を追加できるようにしたいが、他のタイプは許可しない場合はどうすればよいですか?
DonkeyBanana

14

型注釈を記述しようとしている場合、構文は次のとおりです。

var x: { property: string; } = ...;

オブジェクトリテラルを記述しようとしている場合、構文は次のとおりです。

var x = { property: 'hello' };

コードが値の位置で型名を使用しようとしています。


10
あなたvar x: { property: string; } = ...;はいじめです!省略記号がの省略形として有効な構文であることを願っていますvar x: { property: string; } = { property: 'hello' };
Jason Kleban 2013年

10

TypeScriptでは、オブジェクトを宣言する場合、次の構文を使用します。

[access modifier] variable name : { /* structure of object */ }

例えば:

private Object:{ Key1: string, Key2: number }

7

あなたがタイピングを追加しようとしている場合は破壊さ関数の引数には、たとえば、オブジェクトリテラル、構文は次のとおりです。

function foo({ bar, baz }: { bar: boolean, baz: string }) {
  // ...
}

foo({ bar: true, baz: 'lorem ipsum' });

5

プロパティのタイプが同じ場合は、事前定義されたユーティリティタイプを使用できますRecord

type Keys = "property" | "property2"

var obj: Record<Keys, string> = {
  property: "my first prop",
  property2: "my second prop",
};

もちろん、さらに進んで、プロパティ値のカスタムタイプを定義できます。

type Keys = "property" | "property2"
type Value = "my prop" | "my other allowed prop"

var obj: Record<Keys, Value> = {
  property: "my prop",
  property2: "my second prop", // TS Error: Type '"my second prop"' is not assignable to type 'Value'.
};

2
まさに私が必要としたもの。ありがとう!勝利のためのタイプスクリプト!
Audacitus

こちらのlet代わりにも使用しvarます。
Fwd079

3
// Use ..

const Per = {
  name: 'HAMZA',
  age: 20,
  coords: {
    tele: '09',
    lan: '190'
  },
  setAge(age: Number): void {
    this.age = age;
  },
  getAge(): Number {
    return age;
  }
};
const { age, name }: { age: Number; name: String } = Per;
const {
  coords: { tele, lan }
}: { coords: { tele: String; lan: String } } = Per;

console.log(Per.getAge());

3
SOへようこそ。あなたの答えを少し広げることができますか?これがどのように/なぜ機能するのかを説明することは役に立ちます。
パーティリング

1

あなたのコードで:

var obj = {
  myProp: string;
};

オブジェクトリテラルを実際に作成し、変数文字列をプロパティmyPropに割り当てています。非常に悪い習慣ですが、これは実際には有効なTSコードです(これは使用しないでください)。

var string = 'A string';

var obj = {
  property: string
};

ただし、必要なのは、オブジェクトリテラルが型指定されていることです。これはさまざまな方法で実現できます。

インターフェース:

interface myObj {
    property: string;
}

var obj: myObj = { property: "My string" };

カスタムタイプ:

type myObjType = {
    property: string
};

var obj: myObjType = { property: "My string" };

キャスト演算子:

var obj = {
    myString: <string> 'hi',
    myNumber: <number> 132,
};

オブジェクト型リテラル:

var obj: { property: string; } = { property: "Mystring" };
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.