2017-04-11 138 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