代码之家  ›  专栏  ›  技术社区  ›  radman

TypeScript中的可变泛型类型?

  •  0
  • radman  · 技术社区  · 6 年前

    我想在TypeScript中创建一个函数,它接受一个构造函数数组并返回一个相应的实例数组。参见下面的代码。

    getArray

    class T1 {}
    class T2 {}
    class T3 {}
    type AnyCon = new() => any;
    
    function getOne<T_Con extends AnyCon>(con: T_Con): InstanceType<T_Con> {
      return new con();
    }
    
    function getArray<T_Cons>(cons: T_Cons): InstanceType<T_Cons>[] {
      return cons.map( (c: con) => new con() );
    }
    
    let t1: T1 = getOne(T1);
    let [t2, t3]: [T2, T3] = getArray( [T2, T3] );
    
    0 回复  |  直到 6 年前
        1
  •  11
  •   jcalz    6 年前

    您可以在TS3.1及更高版本中使用 mapped array/tuple types . 更容易得到 tuples 推断的 rest parameters 而不是数组参数,因此我将显示:

    function getVariadic<T extends Array<AnyCon>>(...cons: T): {
      [K in keyof T]: T[K] extends AnyCon ? InstanceType<T[K]> : never
    };
    function getVariadic(...cons: AnyCon[]): any[] {
      return cons.map((c: AnyCon) => new c());
    }
    
    let [t2, t3]: [T2, T3] = getVariadic(T2, T3);
    

    我想这和你预期的一样。希望有帮助。祝你好运!


    function getArray<T extends Array<AnyCon>>(cons: T): {
      [K in keyof T]: T[K] extends AnyCon ? InstanceType<T[K]> : never
    };
    function getArray(cons: AnyCon[]): any[] {
      return cons.map((c: AnyCon) => new c());
    }
    
    // error, getArray([T2, T3]) returns (T2 | T3)[]!
    let [t2, t3]: [T2, T3] = getArray([T2, T3]); // 🙁
    

    哦,让我们再试一次

    // okay, but verbose and redundant
    let [t2, t3]: [T2, T3] = getArray([T2, T3] as [typeof T2, typeof T3]); // 😐
    

    也许我们可以用一个 helper function [T2, T3] 推断为元组类型:

    // put this in a library somewhere
    type Lit = string | number | boolean | undefined | null | void | {};
    const tuple = <T extends Lit[]>(...args: T) => args;
    
    // works! but now is very similar to getVariadic
    let [t2, t3]: [T2, T3] = getArray(tuple(T2, T3)); 🙂
    

    最后,一次 TypeScript 3.4 const contexts 这是一个有点容易,但需要一些更多的变化 getArray()

    // note the widening to ReadonlyArray
    function getArray<T extends ReadonlyArray<AnyCon>>(cons: T): {
      -readonly [K in keyof T]: T[K] extends AnyCon ? InstanceType<T[K]> : never
    };
    function getArray(cons: AnyCon[]): any[] {
      return cons.map((c: AnyCon) => new c());
    }
    
    // works and is the least repetitive
    let [t2, t3]: [T2, T3] = getArray([T2, T3] as const); 😀
    

    但正如我上面所说, getVariadic()