2017-04-11 8 views
0

通常の使用法で動作するコードを宣言生成(または宣言を手動で記述)で使用しようとしました。ジェネリックのクラスを.d.tsに返すジェネリックでの関数

function createClass<T>(data: T) 
{ 
    abstract class Internal<T2> 
    { 
     public constructor(arg: T2) 
     { 
      console.log(data, arg); 
     } 

     protected abstract method(arg: T): void; 
    } 

    return Internal; 
} 

問題は、私は関数の結果の型を指定する必要があることですが、私はこれを行う方法を知らない - 私は別のオプションを試してみましたが、どれも働いていない:コードは次のようです。

を追加しました:

この小さな例では、完全には明らかではないかもしれないので、私は、問題が発生して、元のコードを追加します。

オリジナルコード、私はパッケージに変身しようとしていることあなたがそこに見つけることができるpreacthttps://github.com/m18ru/small-redux/blob/master/src/createStore.ts

コード::あなたがそこに見つけることができるsmall-reduxhttps://gist.github.com/Avol-V/1af4748f4b0774a999311c92b6dc1631

コード:https://github.com/developit/preact/blob/master/src/preact.d.ts

問題は、作成したクラスを使用するたびにTStateタイプを指定したくないという問題です。作成されたクラスでは変更できないため、間違っています。

を追加しました:だから

、私は( - class Internal<TInternal, T2>さらにT2に)作成したクラスのジェネリックで明示的にTを指定しないように任意の解決策を見つけることができませんでした。私の結果コードは次のようになります。https://github.com/m18ru/preact-small-redux/blob/85c143e851b92c44861dc976ce6ef89bcda2c884/src/index.ts

あなただけのジェネリックを持つクラスを返す関数を書きたい場合は@baryoが示唆するように、あなたは(いくつかのクリーンアップで)これを行うことができます。

declare abstract class AbstractInternal<T> 
{ 
    public abstract method(arg: T): void; 
} 

function createClass(): typeof AbstractInternal 
{ 
    abstract class Internal<T> implements AbstractInternal<T> 
    { 
     public abstract method(arg: T): void; 
    } 

    return Internal; 
} 

const A = createClass(); 

class B extends A<string> 
{ 
    public method(arg: string): string 
    { 
     return 'Hello ' + arg; 
    } 
} 

答えて

2

あなたが内部の作成すべてその関数は、型を含めてその範囲にスコープされています。だから少なくともそれから型を定義する必要があります。たぶん、次はあなたを助ける:

interface IInternal<T> { 
    method(arg: T): void; 
} 

type InternalCtor<T> = new (param: T) => IInternal<T>; 

function createClass<T>(data: T): InternalCtor<T> 
{ 
    abstract class Internal<T> implements IInternal<T> 
    { 
     public constructor(arg: T) 
     { 
      console.log(data, arg); 
     } 

     public abstract method(arg: T): void; 
    } 

    return Internal as InternalCtor<T>; 
} 

class A extends createClass<number>(1) { 
    public method() { 
     console.log('hello'); 
    } 
} 

const z = new A(2); // 1 2 

編集: あなたは一般的な方法は、一般的なクラスを返すことを興味言及 - それはタイピングと少しトリッキーになりますが、私たちはただ活字体自体は、すべて私たちを推測させることができます必要。

function createClass<T>(data: T) 
{ 
    // directly return a new class with a different generic type. 
    // notice that you can't return an abstract class. 
    return class Internal<U> 
    { 
     public constructor(arg: U) 
     { 
      console.log(data, arg); 
     } 

     public method(arg: T): void { console.log(arg); } 
    } 
} 



// first generic type (number) is for the function, then the second generic type (string) is for the returned class. 
class A extends createClass<number>(1)<string> { 

} 

const z = new A('zzz'); // 1 zzz 
z.method(2); // 2 

編集2: それはあなたが探しているものとは少し違うのですが、私はより良い練習が(@Diulleiが提案するものに類似)は、次のことになると思う。

abstract class AbstractInternal<T> { 
    public abstract method(arg: T): void; 
} 

type InternalCtor<T> = new (param: T) => AbstractInternal<T>; 

function createClass<T, U>(data: T): InternalCtor<U> { 
    abstract class Internal<U> implements AbstractInternal<U> 
    { 
     public constructor(arg: T) { 
      console.log(data, arg); 
     } 

     public abstract method(arg: U): void; 
    } 

    return Internal as any as InternalCtor<U>; 
} 

class A extends createClass<number, string>(1) { 
    public method(arg: string) { // now I need to implement this to avoid a compilation error 
     console.log(`hello ${arg}`); 
    } 
} 

const z = new A('arg'); // 1 "arg"" 
z.method('arg2'); // "hello arg2"" 
+1

良い仕事!私があなたが変更する必要があると思うユニークなものは、 'IInternal 'インターフェースです。このメソッドを実装するために 'A'クラスを強制する抽象クラス' method(arg:T):void'を持つ抽象クラスである必要があります。 – Diullei

+0

ありがとう!関数のスコープ付き 'data'パラメータにアクセスすることはできません。 – baryo

+0

はい、そうです。それを見てhttps://gist.github.com/Diullei/21ad4fe56cd51e9330c998995d17a23e – Diullei

関連する問題