web-dev-qa-db-ja.com

TypeScriptアノテーションで複数のタイプのメンバーを組み合わせることが可能ですか?

私がやろうとしていることは不可能のようですが、それが本当に可能であることを願っています。

基本的に、私は2つのインターフェースを持っていますが、両方の組み合わせとして単一の関数パラメーターに注釈を付けたいと思います。

interface ClientRequest {
    userId:     number
    sessionKey: string
}

interface Coords {
    lat:  number
    long: number
}

そして、関数で、私はこのようなことをしたいです:

function(data: ClientRequest&Coords) { ... }

そのため、「データ」オブジェクトには、両方のタイプのすべてのメンバーを含めることができます。

「型のメンバーの結合」の下にある spec preview で参照されているものを見ましたが、これはまだ組み込まれていないようです。

それが不可能な場合、私の解決策は次のようになります。

interface ClientRequest<T> {
    userId:     number
    sessionKey: string
    data?:       T
}

function(data: ClientRequest<Coords>) { ... }

これはこの場合はうまくいきますが、私が望むほど動的ではありません。アノテーション自体で複数の(2+)タイプを組み合わせることができるようになりたいです。

function(data: TypeA&TypeB&TypeC) { ... }

従来の解決策は、これらの型を拡張する型を定義することだと思いますが、柔軟性は低いようです。タイプを追加する場合は、次のいずれかを行う必要があります

  • (a)宣言に戻って書き直すか、
  • (b)まったく新しいインターフェースを作成します。余分なオーバーヘッドに同意するかどうかはわかりません。

TypeScriptの専門家は私を正しい方向に向けようとしていますか?

28
Joshua

あなたの質問に対する具体的な回答は次のとおりです。いいえ、結合または拡張されたタイプを示す単一のインライン注釈はありません。

解決しようとしている問題のベストプラクティスは、他の2つを拡張する3番目のタイプを作成することです。

interface IClientRequestAndCoords extends IClientRequest, ICoords {} 

function(data: IClientRequestAndCoords) 

[〜#〜]更新[〜#〜] 2018-10-30

TypeScriptに型の交差があります。だからあなたは今簡単に行うことができます:

interface ClientRequest {
  userId:     number
  sessionKey: string
}

interface Coords {
  lat:  number
  long: number
}

function log(data: ClientRequest & Coords) { 
  console.log(
    data.userId,
    data.sessionKey,
    data.lat,
    data.long
  );
}
35
Martin

インターフェースの回答は、2つの構造を組み合わせる上品な方法ですが、注釈の一部として型を組み合わせることが可能かどうかを知りたいと述べました。

インターフェースに関する注意

私はあなたの質問に関連するいくつかの機能のいくつかの説明を提供しましたが、最初に私はあなたがあなたのようにICoordsインターフェースを作成する必要があると思うのであなたがインターフェースソリューションから延期されたら質問はクラスのように見えます)-簡単に休める-インターフェースもクラスを拡張できるため

// Interface extending an interface and a class
interface IClientRequestAndCoords extends IClientRequest, Coords {} 

同じ名前とタイプである限り、インターフェースはプロパティをマージします。 (たとえば、両方がプロパティx: stringを宣言した場合。

ここに、他の注釈機能についてのメモがあります。

ユニオンタイプ

あなたが読んだかもしれない仕様は、次のようなunionタイプです:

var x: IClientRequest | Coords;

しかし、これはxがどちらか一方であることを保証するだけであり、2つの組み合わせではありません。マージされた型IClientRequest & Coordsの構文は、私が知る限り、ロードマップにはありません。

function go(data: IClientRequest | Coords) {
    var a = data[0]; // IClientRequest
    var b = data[1]; // Coords
}

// Allowed (even though it doesn't supply Coords data
go(myClientRequest);

// Allowed (even though it doesn't supply IClientRequest data
go (myCoords);

これも現在のリリースには含まれていませんが、後でリリースされます。

タプルのタイプ

あなたが見たかもしれない仕様のもう一つの可能​​な部分はタプル型です:

var x: [IClientRequest, Coords];

ただし、これにより、データの形状が構造体から配列のようなものに変わり、要素0IClientRequestで、要素1Coordsになります。

function go(data: [IClientRequest, Coords]) {
    var a = data[0]; // ClientRequest
    var b = data[1]; // Coords
}

go([myClientRequest, myCoords]);

Uber-Annotation

最後に、本当にマージされたインターフェースを作成したくない場合は、uber-annotationを使用できます。

function go(data: { userId:number; sessionKey: string; x: number; y: number; } ) {

}
3
Fenton

「型のメンバーの結合」の下にある spec preview で参照されているものを見つけましたが、これはまだ組み込まれていないようです。

intersectionタイプ(unionではない)にもっと興味があると思います。違いは、渡されたオブジェクトがプロパティのallをサポートする必要があり、one ofをサポートしない必要があることです。

Githubの問題: https://github.com/Microsoft/TypeScript/issues/1256#issuecomment-64533287

2
basarat

ES6Object.assign

interface ClientRequest {
    userId:     number
    sessionKey: string
}

interface Coords {
    lat:  number
    long: number
}

type Combined = ClientRequest & Coords;

次に、次のようにデータを定義できます。

let myData = Object.assign({},
    <ClientRequest> {
        userId: 10,
        sessionKey: "gjk23h872ty3h82g2ghfp928ge"
    },
    <Coords> {
        lat: -23,
        long: 52
    }
);

最後に、関数を呼び出します。

function myFunc(data: Combined) { ... }
myFunc(myData);

これを達成するさらに多くの方法については、この他の質問を参照してください:

2つのJavaScriptオブジェクトのプロパティを動的にマージするにはどうすればよいですか?

2
smac89

私はこれを行う必要があり、次の解決策が私のために働きました:

type MyFunction = () => void

interface MyFunctionWithProps extends MyFunction {
  prop1: string,
  prop2: number
}

// compiles fine
const MyMashup: MyFunctionWithProps = Object.assign(
  () => {},
  {
    prop1: 'hello',
    prop2: 1234
  }
)
0
James Trickey