Typescript 解析具有正确类型的元组中的多个回调和承诺

Typescript 解析具有正确类型的元组中的多个回调和承诺,typescript,Typescript,这是一个有很多人的操场 问题的第一步是如何将多个回调解析为一个函数,并将结果作为正确类型的元组 interface JQueryDeferred<T> { value: T } // just for the example to remove the error function resolve<Callbacks extends any[]>(...functions: Callbacks) { let results = []; for(c

这是一个有很多人的操场

问题的第一步是如何将多个回调解析为一个函数,并将结果作为正确类型的元组

interface JQueryDeferred<T> {
    value: T
} // just for the example to remove the error

function resolve<Callbacks extends any[]>(...functions: Callbacks) {
    let results = [];
    for(const f of functions) {
        results.push(f());
    }
    return results;
}

const f1 = () => 1;
const f2 = () => "str";

let r = resolve(f1, f2); // r is of type any[], I'd like it to be of type [number, string]
console.log(r);
接口JQueryDeferred{
值:T
}//仅用于示例以删除错误
函数解析(…函数:回调){
让结果=[];
for(函数常数f){
结果:push(f());
}
返回结果;
}
常数f1=()=>1;
常数f2=()=>“str”;
设r=resolve(f1,f2);//r是any[]类型,我希望它是[number,string]类型
控制台日志(r);
另外,如果resolve直接使用数组而不是varargs,您将如何执行此操作

第二部分是承诺。出于遗留原因,我使用了旧版本的JQuery,因此我使用jQueryFerred的方式可能已经过时

function resolveMany<T, R>(args: JQueryDeferred<T>[]): R[] { // not all T and R are the same but I don't know how to express that
    let results: any[] = [];
    // here we compute the results, I lefet that out of the example
    return results;
}

let defString!: JQueryDeferred<string>; // this defered will return a string, let's say "def"
let defNumber!: JQueryDeferred<number>; // this defered will return a number, let's say 42

let rr = resolveMany([defString, defNumber]); // will return ["def", 42]
// Here I got 2 problems, TSC complains about defNumber being of type JQueryDeferred<number>, I understand why but it's still blocking for me.
// And rr is of type unknown[], I would like rr to be types as [string, number]

let rrr = resolveMany([defString, defNumber, defNumber]); // this should also work and rrr should be of type [string, number, number]
函数resolveMany(args:jQueryFerred[]):R[]{//不是所有的T和R都是相同的,但我不知道如何表达它
let结果:任意[]=[];
//这里我们计算结果,我把它从例子中去掉
返回结果;
}
让我们把绳子解开!:jQueryFerred;//此延迟将返回一个字符串,比如“def”
让我们看看数字!:jQueryFerred;//这个延迟将返回一个数字,比如说42
设rr=resolveMany([defString,defNumber]);//将返回[“def”,42]
//这里我有两个问题,TSC抱怨defNumber是JQueryDerred类型,我理解为什么,但它仍然为我阻塞。
//而rr的类型为unknown[],我希望rr的类型为[string,number]
设rrr=resolveMany([defString,defNumber,defNumber]);//这也应该起作用,rrr应该是[string,number,number]类型

有没有办法在typescript中完成所有这些工作?

对于所有这些,编译器不会自动推断输入和输出之间元组类型的相关性。这超出了编译器的能力范围;您可能会自动获得一些处理长度的信息,至少如果您使用-
push
将循环更改为数组
map()
方法(请参阅),但是,如果没有类似于中所请求的更高种类的排序,就无法理解每个元素将针对不同的
X
JQueryDeferred
转换为
X
。这看起来不会很快实施

因此,让我们放弃让编译器自动推断此类类型,而专注于告诉编译器预期的类型。这将涉及类型操作,如,和描述类型。它还将涉及或类似于告诉编译器,实现确实符合我们描述的类型,因为它本身无法验证这一点


下面是如何编写您的
resolve()
,我将调用
resolveCallbacks()
,以区别于后面的一些操作:

function resolveCallbacks<T extends readonly any[]>(
  ...functions: { [I in keyof T]: () => T[I] }): T {
  let results = [] as unknown as { -readonly [K in keyof T]: T[K] };
  for (const f of functions) {
    results.push(f());
  }
  return results;
}

从varargs更改为数组与删除rest参数修饰符一样简单:

function resolveCallbackArray<T extends readonly any[]>(
  functions: { [I in keyof T]: () => T[I] }): T {
  let results = [] as unknown as { -readonly [K in keyof T]: T[K] };
  for (const f of functions) {
    results.push(f());
  }
  return results;
}
这也行


在剩下的部分中,我不能100%确定您在使用
JQueryDeferred
做什么,因为您提供了自己的示例类型,它与异步行为无关。假设
JQueryDeferred
只有一个
value
属性,那么我们可以以一种简单的方式将
resolveCallbacks
转换为
ResolveDeferereds

function resolveDeferreds<T extends readonly any[]>(
  ...deferreds: { [I in keyof T]: JQueryDeferred<T[I]> }): T {
  let results = [] as unknown as { -readonly [K in keyof T]: T[K] };
  for (const d of deferreds) {
    results.push(d.value)
  }
  return results;
}

let defString: JQueryDeferred<string> = { value: "abc" }
let defNumber: JQueryDeferred<number> = { value: 123 }    
let rD = resolveDeferreds(defString, defNumber);
//let rD: [string, number]
console.log(rD); // ["abc", 123]
至于实现,我只是在这里使用了现有的函数,因为我不打算重新发明轮子。如果必须的话,你可以做。我们仍然需要这种类型断言,因为
Promise.all()
不会强式地键入任意元组(无论如何,到现在为止,请参见)。我们可以看到它是有效的:

const f1 = () => 1;
const f2 = () => "str";

let r = resolveCallbacks(f1, f2);
// let r: [number, string]
console.log(r); // [1, "str"]
let promString = new Promise<string>((r) => r("hello"));
let promNumber = new Promise<number>((r) => r(456));

const rP = resolvePromises(promString, promNumber);
// const rP: Promise<[string, number]>
rP.then(sn => console.log(sn)); // ["hello, 456"]
let promString=新承诺((r)=>r(“你好”);
让promNumber=newpromise((r)=>r(456));
const rP=resolvePromises(promString,promNumber);
//警察:承诺
rP.then(sn=>console.log(sn));//[“你好,456”]


对于所有这些,编译器不会自动推断输入和输出之间元组类型的相关性。这超出了编译器的能力范围;您可能会自动获得一些处理长度的信息,至少如果您使用-
push
将循环更改为数组
map()
方法(请参阅),但是,如果没有类似于中所请求的更高种类的排序,就无法理解每个元素将针对不同的
X
JQueryDeferred
转换为
X
。这看起来不会很快实施

因此,让我们放弃让编译器自动推断此类类型,而专注于告诉编译器预期的类型。这将涉及类型操作,如,和描述类型。它还将涉及或类似于告诉编译器,实现确实符合我们描述的类型,因为它本身无法验证这一点


下面是如何编写您的
resolve()
,我将调用
resolveCallbacks()
,以区别于后面的一些操作:

function resolveCallbacks<T extends readonly any[]>(
  ...functions: { [I in keyof T]: () => T[I] }): T {
  let results = [] as unknown as { -readonly [K in keyof T]: T[K] };
  for (const f of functions) {
    results.push(f());
  }
  return results;
}

从varargs更改为数组与删除rest参数修饰符一样简单:

function resolveCallbackArray<T extends readonly any[]>(
  functions: { [I in keyof T]: () => T[I] }): T {
  let results = [] as unknown as { -readonly [K in keyof T]: T[K] };
  for (const f of functions) {
    results.push(f());
  }
  return results;
}
这也行


在剩下的部分中,我不能100%确定您在使用
JQueryDeferred
做什么,因为您提供了自己的示例类型,它与异步行为无关。假设
JQueryDeferred
只有一个
value
属性,那么我们可以以一种简单的方式将
resolveCallbacks
转换为
ResolveDeferereds

function resolveDeferreds<T extends readonly any[]>(
  ...deferreds: { [I in keyof T]: JQueryDeferred<T[I]> }): T {
  let results = [] as unknown as { -readonly [K in keyof T]: T[K] };
  for (const d of deferreds) {
    results.push(d.value)
  }
  return results;
}

let defString: JQueryDeferred<string> = { value: "abc" }
let defNumber: JQueryDeferred<number> = { value: 123 }    
let rD = resolveDeferreds(defString, defNumber);
//let rD: [string, number]
console.log(rD); // ["abc", 123]
至于实现,我只是在这里使用了现有的函数,因为我不打算重新发明轮子。如果必须的话,你可以做。我们仍然需要那个类型断言,因为