2017-04-21 23 views
0

私の目標は、名前が別のインターフェイスで定義されているプロパティを持つタイプインターフェイスを作成することです。異なるTypeの構造​​体を参照する型インタフェース?

私は、typescriptのモデルスキーマオブジェクトに対して次の定義をしています。

export interface ModelSchema { 
    idAttribute: string; 
    name: string; 
    attributes: { 
    [attrName: string]: 
     { type: 'number', default?: number, readOnly?: boolean} | 
     { type: 'string', default?: string, readOnly?: boolean} | 
     { type: 'boolean', default?: boolean, readOnly?: boolean} | 
     { type: 'date', default?: Date, readOnly?: boolean} | 
     { type: 'array', default?: string[] | number[], readOnly?: boolean } | 
     { type: 'object', default?: object, readOnly?: boolean} 
    }; 
    relationships: { 
    [relName: string]: { 
     type: RelationshipSchema, 
     readOnly?: boolean, 
    }, 
    }; 
}; 

ここでの説明の鍵となるのは、relationshipsプロパティです。文字列名( 'children'、 'replies'など)を持つ任意の数のプロパティを持つことができ、それぞれはデータモデル内に多対多の関係を表します。

承認者のための別のコンテナを定義したいと思います。サーバーが「このユーザーはC/R/U/Dにアイテム/リレーションシップを許可していますか?それぞれの関係には異なる規則があるため、構造は並列です。各関係には独自の承認者メソッドがあります。

だから、理想的に、私は

export interface ApproverDefinition<S extends ModelSchema> { 
    typeName: string, 
    attributes: AttributesAuthorize, 
    relationships: { 
    [name: string]: RelationshipAuthorize, 
    } 
} 

ような何かを言うだろうが、それは基本的に言うところが別々のガードを持っている:「ApproverDefinition.relationshipsの文字列インデックス付きプロパティと同じ名前を持っている必要がありますこれは、一般的に関係しているとSの関係プロパティのものと、ModelSchema(ここでは擬似コード)のような

何か:。

export interface ApproverDefinition<S extends ModelSchema> { 
    typeName: string, 
    attributes: AttributesAuthorize, 
    relationships: { 
    [name in keyof S.relationships]: RelationshipAuthorize, 
    } 
} 

上記はほぼ完璧です(但し、完全な範囲は必要ありませんが、私はそれと一緒に暮らします) - 私は何をしたいのかを説明しているように感じますが、私はTSから2つのエラーを受け取ります。最初に、私はSの名前をインターフェイスにエクスポートしています。そして、2番目はSを名前空間のように扱っています。

承認者コードとスキーマコードを区別しておく必要がある理由はたくさんあるため、ModelSchemaを拡張するだけでは実際には実現できません。

Object.keys(approver.relationships)とObject.keys(model.relationships)が同じエントリを持っていることを基本的にチェックすると、実行時の型チェックができますが、これをキャプチャしたいのですがタイプスクリプト言語で書かれています。

このようなことはすべて可能ですか?

編集:ここでは例のモデルスキーマです:

const ProfileSchema = { 
    idAttribute: 'id', 
    name: 'profiles', 
    attributes: { 
    id: { type: 'number', readOnly: true }, 
    short_text: { type: 'string', readOnly: false }, 
    long_text: { type: 'string', readOnly: true }, 
    // SNIP ... 
    }, 
    relationships: { 
    memberships: { type: Memberships, readOnly: false }, 
    conversations: { type: ProfilePermissions, readOnly: false }, 
    followingProfiles: { type: FollowingProfiles, readOnly: false}, 
    followingDocuments: { type: FollowingDocuments, readOnly: false}, 
    followingCommunities: { type: FollowingCommunities, readOnly: false}, 
    followers: { type: FollowingProfiles, readOnly: false}, 
    }, 
}; 

と私はProfileApprover.relationshipsがProfileSchema.relationshipsと同じ性質を持っていることを

const ProfileApprover: ApproverDefinition<ProfileSchema> = { 
    typeName: 'profiles' 
    attributes: /* attribute approver */ 
    relationships: { 
    memberships: /* approver function */, 
    conversations: /* approver function */, 
    followingProfiles: /* approver function */, 
    followingDocuments: /* approver function */, 
    followingCommunities: /* approver function */, 
    followers: /* approver function */, 
    } 
} 

ノートを定義したいのですが、プロパティ異なる値を持つ。これは、すべての承認者インスタンスが対応するスキーマと一致するタイプルールで指定したいものです。

承認者が登録されていない場合は、ランタイムエラーが発生することがありますが、これは静的にtypescriptを定義できるようなものです。

+0

上記のスキーマのモックjsonデータを共有できますか? – Aravind

+0

確かにそこにあります。 – pfooti

答えて

1

私が正しくあなたを理解していれば、何がしたいことは、我々は独立して、それに

export interface Relationships { 
    [relName: string]: { 
    type: RelationshipSchema, 
    readOnly?: boolean, 
    }, 
} 

を参照できるように、我々はインターフェイスにModelShemaの関係プロパティの種類を抽出し、この

まずようなものですApproverDefinitionだけrelatを参照するので、私たちは前のオブジェクトリテラルのタイプ

export interface ModelSchema { 
    idAttribute: string; 
    name: string; 
    attributes: { 
    [attrName: string]: 
    {type: 'number', default?: number, readOnly?: boolean} | 
    {type: 'string', default?: string, readOnly?: boolean} | 
    {type: 'boolean', default?: boolean, readOnly?: boolean} | 
    {type: 'date', default?: Date, readOnly?: boolean} | 
    {type: 'array', default?: string[] | number[], readOnly?: boolean} | 
    {type: 'object', default?: object, readOnly?: boolean} 
    }; 
    retationships: Relationships; 
} 

の代わりにModelSchemaにこのインタフェースを使用しますModelSchemaのionhipsプロパティを使用する場合、現在使用できる型を制約として使用できます。これはProfileSchemaが値、およびないタイプであるため、私たちはその関係プロパティにtypeofを使用しての型引数として結果を使用する必要があり、

export interface ApproverDefinition<R extends Relationships> { 
    typeName: string; 
    attributes: AttributesAuthorize; 
    relationships: { 
    [name in keyof R]: RelationshipAuthorize 
    } 
} 

const ProfileSchema = { 
    idAttribute: 'id', 
    name: 'profiles', 
    attributes: { 
    id: {type: 'number', readOnly: true}, 
    short_text: {type: 'string', readOnly: false}, 
    long_text: {type: 'string', readOnly: true}, 
    // SNIP ... 
    }, 
    relationships: { 
    memberships: {type: Memberships, readOnly: false}, 
    conversations: {type: ProfilePermissions, readOnly: false}, 
    followingProfiles: {type: FollowingProfiles, readOnly: false}, 
    followingDocuments: {type: FollowingDocuments, readOnly: false}, 
    followingCommunities: {type: FollowingCommunities, readOnly: false}, 
    followers: {type: FollowingProfiles, readOnly: false}, 
    }, 
}; 

最後に、私たちにkeyofで使用するためのキーへのアクセスを提供しますApproverDefinition

const ProfileApprover: ApproverDefinition<typeof ProfileSchema.relationships> = { 
    typeName: 'profiles', 
    attributes: {}, /* attribute approver */ 
    relationships: { 
    // all of these are now required by the type 
    memberships: /* approver function */, 
    conversations: /* approver function */, 
    followingProfiles: /* approver function */, 
    followingDocuments: /* approver function */, 
    followingCommunities: /* approver function */, 
    followers: /* approver function */, 
    } 
}; 
+0

このようなことは、TypeScriptがかなり許容されていることを除いて、ネームスペースの問題を解決しています。実際にはタイプミスを防ぐことができません。ProfileApproverにrelationships.folllllowersフィールドを定義できます。それは単なる余分なデータなので、私はまた、「この関係ブロックはこれらのフィールドをすべて持たなければなりません」と言うこともできません(どちらかの間にサブセット関係が存在することを保証します)。当面は、コンパイル時ではなく実行時にこのテストを行うように変更しました。 – pfooti

+0

@pfootiしかしそうではありません。 'folllllowers'という名前のプロパティを追加するとエラーになります。私は遊び場のリンクを投稿することができません(長すぎると、サービスで切り捨てができなくなります)。しかし、あなたが記述したところでは、あなたの期待通りにタイプスクリプトエラーが発生します。 –

関連する問題