2017-04-11 143 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; 
} 

的問題是,我應該到指定的函數結果類型,但我不知道如何做到這一點 - 我嘗試了不同的選項,並沒有奏效。

補充:

這個小例子可能不完全清楚,所以我加入與發生問題的原代碼:

原代碼,我試圖把成包:https://gist.github.com/Avol-V/1af4748f4b0774a999311c92b6dc1631

small-redux代碼,你可以發現有:https://github.com/m18ru/small-redux/blob/master/src/createStore.ts

preact你可以找到有碼:https://github.com/developit/preact/blob/master/src/preact.d.ts

問題是我不想爲創建的類的每個用法指定TState類型 - 它不能在創建的類上更改,因此它不正確。

補充:

所以,我沒有找到任何解決方案在通用創建類的未指定T明確(附加到T2 - class Internal<TInternal, T2>)。我的結果代碼如下所示: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 '接口。它需要是一個具有抽象'方法(arg:T):void'函數的抽象類來強制類'A'來實現此方法。 – Diullei

+0

謝謝!但是它不會訪問函數的作用域'data'參數。 – baryo

+0

是的,它會的。看看https://gist.github.com/Diullei/21ad4fe56cd51e9330c998995d17a23e – Diullei