2017-01-25 7 views
0

私は、抽象親クラスがそのサブクラスを通じて提供されるジェネリック型のすべてのプロパティを継承する必要があるパターンを作成しています。TypeScriptの汎用パラメータからどのように拡張できますか?

ここでは基本的なアイデアを提供し、基本クラスのコンストラクタを見てだ、ともviewed on githubことができます。

public constructor(data: T) { 

    _.assign(this, _.omit(data, [ 
     "table", 
     "id", 
     "PartitionKey", 
     "RowKey", 
    ])); 
} 

私が探している何をして効果的にthisを表現するいくつかの方法であります:

export abstract class Base<T extends EntityData> implements Storage.AbstractEntity & T { 
... 

残念ながら、これはサポートされていないようあなたは

export class AuthorFact extends Base<Author> { 

    public get RowKey() { return (this as any).id } 
} 

見ることができるように、私は:現在ので、私は私が私の基本クラスは、このようなことからalso receives the properties of the generic type it's encapsulating継承する任意のクラスがあること、その一般的なパラメータを拡張することができますどのように途方に暮れてよ私の基本型から& Tを削除し、(this as any)を使用してエラーをスローするコンパイラを抑制してください。

.idの型チェックと、作成するインスタンスでAuthorという他のプロパティが利用できるようにすることが究極の目的です。

答えて

1

はしても、最新のallows classes and interfaces to derive from object types and intersections of object typesは、ジェネリック型パラメータからクラスを拡張することはまだ許可されていないことをコミットして:それ は一貫存在であることを確認することはできませんので

をインターフェイスまたはクラス裸の型パラメータを拡張することはできません型のインスタンス化でメンバー名 が競合しません。

しかし、今や許されていることは狂っています。実行時にクラスを作成し、型チェックを行うことができます。 (これは現在2.2ですnpm i [email protected]が必要です):

import * as Azure from "azure"; 
import * as _ from "lodash"; 


export class Author { 
    public id: string; 
    public firstName: string; 
    public lastName: string; 
    public nativeIds: {[key: string]: string} = {}; 
    public posts: Post[]; 
    public created: Date; 
} 

export class Post { 
    public constructor(
     public id: string, 
     public author: Author, 
     public title: string, 
     public content: string, 
     public authored: Date 
    ) { 
    } 
} 

type Constructor<T> = new() => T; 
type DataConstructor<T, Data> = new (data: Data) => T; 

function Base<T>(dataClass: Constructor<T>) { 
    class Class extends (dataClass as Constructor<{}>) { 
     public constructor(data: T) { 
      super(); 
      _.assign(this, _.omit(data, [ 
       "table", 
       "id", 
       "PartitionKey", 
       "RowKey", 
      ])); 
     } 
     [property: string]: string | number | boolean | Date; 
    } 
    return Class as Constructor<T & Class>; 
} 

function Fact<T, Data>(superClass: DataConstructor<T, Data>) { 
    class Class extends (superClass as DataConstructor<{}, Data>) { 
     public get PartitionKey() { return "fact" } 
    } 
    return Class as DataConstructor<T & Class, Data> 
} 

function Identifiable<T, Data>(superClass: DataConstructor<T, Data>) { 
    class Class extends (superClass as DataConstructor<{}, Data>) { 
     public id: string; 
     public get RowKey() { return this.id } 
    } 
    return Class as DataConstructor<T & Class, Data> 
} 

function IdentifiableDataFact<Data>(dataClass: Constructor<Data>) { 
    return Identifiable(Fact(Base(dataClass))); 
} 


class AuthorFact extends IdentifiableDataFact(Author) { 
} 

// let's init some data 
let author = new Author(); 
author.id = 'a'; 
author.firstName = 'z'; 
author.lastName = 'q'; 


// let's see what we've got  
let authorFact = new AuthorFact(author); // it has a constructor that takes Author 

let e: Azure.Entity = authorFact; // it's structurally compatible with Azure.Entity 

// it has PartitionKey 
console.log(authorFact.PartitionKey);   // prints fact 

// it has some properties that were copied over by Base constructor (except id) 
console.log(authorFact.firstName);  // prints z 

// it has index signature (check with --noImplicitAny) 
const ps = ['lastName', 'nativeIds']; 
ps.forEach(p => console.log(authorFact[p])); // prints q {} 

// and it has RowKey but it's undefined here (this might not be what you want) 
// because id is explicitly omitted from being copied in Base constructor 
console.log(authorFact.RowKey); // undefined 

それはあなたが抽象クラスでそれを行うことができないことが判明したが、私は構造タイプは、まだあなたがここに欲しいものを行うことができだと思います。

+0

マッピングされた型を使用できる可能性はありますか?また、なぜクラスの代わりに関数を使っていくつかのものをラップするのはなぜですか? –

+1

マップされたタイプについての考え方はありません。 'extends 'のためにTも型と同様に値でなければならないので、' T = A & B; class C extends T {} 'を実行することができないので、関数が必要です。'エラーTS2693:' T 'タイプを参照していますが、ここの値として使用されています。クラス型を返す関数がそれを行う唯一の方法です。 – artem

+0

私はあなたの答えを念頭に置くつもりですが、それは1つの実行可能なアプローチのようです。私はちょうどより新しい言語の特徴がより少なく...回路的な解決をもたらすかもしれない着陸していないことを確認したい;) –

関連する問題