我有一个基本的方法:
function foo<T>(data:any, clazz:new(...args:any[])=>T):T{
//Example impl, just to demonstrate the issue
if(data instanceof Array){
return new clazz();
}
return [new clazz()];
}
所以,我希望它能同时使用对象和数组,如下所示:
let bar:Bar = foo<Bar>(Bar); //Works fine actually
let bars:Bar[] = foo<Bar[]>(Bar); //Should return a Bar[]
它不起作用,因为Bar
不是Bar[]
的构造函数。
我已经尝试过:
foo<Bar[]>(Bar[])
foo<Bar[]>(Array<Bar>)
foo<Array<Bar>>(Array<Bar>)
答案 0 :(得分:1)
你要求的是,
let bar:Bar = foo<Bar>(Bar); //Works fine actually
let bars:Bar[] = foo<Bar[]>(Bar); //Should return a Bar[]
永远不会工作,因为类型会在运行时被删除。两者的JavaScript将如下所示:
let bar = foo(Bar);
let bars = foo(Bar);
所以没有办法分辨出来。
正如@AlekseyL所暗示的,最直接的解决方案是有两个函数来处理数组/非数组的情况。如果真的想要一个函数,我们需要有一种方法让它在运行时知道该怎么做。
首先,让我们创建帮助器Constructor
类型,因为我讨厌一直写出new(...
内容:
type Constructor<T> = {
new(...args: any[]): T;
}
现在让我们创建一个ArrayOf
类型,它只是一个包含相关类构造函数的对象。我们还需要一个类型保护来检测某些东西在运行时是否为ArrayOf
,还有一个函数来生成开发人员可以使用的ArrayOf
:
type ArrayOf<T> = {
clazz: Constructor<T>;
}
function isArrayOf<T>(x: Constructor<T> | ArrayOf<T>): x is ArrayOf<T> {
return 'clazz' in x;
}
function ArrayOf<T>(clazz: Constructor<T>): ArrayOf<T> {
return { clazz };
}
最后,我们可以实施foo()
:
function foo<T>(clazz: Constructor<T>): T;
function foo<T>(arrayOfClazz: ArrayOf<T>): T[];
function foo<T>(x: Constructor<T> | ArrayOf<T>): T | T[] {
if (isArrayOf(x)) {
return [new x.clazz()];
} else {
return new x();
}
}
这是一个重载函数,它接受构造函数或ArrayOf
对象,然后确定在运行时要做什么。让我们确保它有效:
class Bar {
// ...
}
const bar: Bar = foo(Bar);
const bars: Bar[] = foo(ArrayOf(Bar));
你走了;它有效!
但与仅拥有两个功能相比,这相当复杂。对于开发人员来说,所有这些都是大致相同的努力:
// what you wanted
let bar = foo<Bar>(Bar);
let bars = foo<Bar[]>(Bar); // will not work, as above
// what I gave you
let bar = foo(Bar);
let bars = foo(ArrayOf(Bar));
// two functions
let bar = foo(Bar);
let bars = fooArray(Bar);
我认为双功能解决方案可能是最开发的,但这只是我的观点。无论如何,希望有所帮助。祝你好运!
嗯,我看到你编辑了你的代码,为data
添加了一个新的foo
参数,这个参数是一个数组与否,你想要根据它返回一个数组。在这种情况下,解决方案非常简单:
function foo<T>(data: any[], clazz: Constructor<T>): T[];
function foo<T>(data: any, clazz: Constructor<T>): T;
function foo<T>(data: any, clazz: Constructor<T>): T | T[] {
if (Array.isArray(data)) {
return [new clazz()];
} else {
return new clazz();
}
}
const bar: Bar = foo('bar',Bar);
const bars: Bar[] = foo(['bars'], Bar);
祝你好运。
答案 1 :(得分:1)
您可以使用签名重载并根据传递的参数决定返回数组或单个实例:
type Constructor<T> = new () => T;
function foo<T>(clazz: [Constructor<T>]): T[]
function foo<T>(clazz: Constructor<T>): T
function foo<T>(clazz: Constructor<T> | [Constructor<T>]) {
if(clazz instanceof Array){
return [new clazz[0]];
}
return new clazz();
}
let arrayResult = foo([Bar]);
let result = foo(Bar);