Typescript 如何实现泛型函数实例化TypeDarray

Typescript 如何实现泛型函数实例化TypeDarray,typescript,generics,Typescript,Generics,我试图写一个这样的函数: export function createTypedArray<T extends TypedArray>( arg : { source : T, arraySize : number } ) : T { if( arg.source instanceof Int32Array ) { return new Int32Array( arg.arraySize ); } if( arg.source instanceof Float32

我试图写一个这样的函数:

export function createTypedArray<T extends TypedArray>( arg : { source : T, arraySize : number } ) : T {
  if( arg.source instanceof Int32Array ) {
    return new Int32Array( arg.arraySize );
  }
  if( arg.source instanceof Float32Array ) {
    return new Float32Array( arg.arraySize );
  }
  if( arg.source instanceof Float64Array ) {
    return new Float64Array( arg.arraySize );
  }
  throw 'Unsupported typed array type!';
}
return <T> new Int32Array( arg.arraySize );
export function createTypedArray<T extends TypedArray>( arg : { source : T, arraySize : number } ) : T {
  if( arg.source instanceof Int32Array ||
      arg.source instanceof Float32Array ||
      arg.source instanceof Float64Array
  ) {
    return new <T>( arg.arraySize );
  }
  throw 'Unsupported typed array type!';
}
导出函数createTypedArray(arg:{source:T,arraySize:number}):T{
if(arg.source instanceof Int32Array){
返回新的Int32Array(arg.arraySize);
}
if(arg.source instanceof Float32Array){
返回新的Float32Array(arg.arraySize);
}
if(arg.source instanceof Float64Array){
返回新的Float64Array(arg.arraySize);
}
抛出“不支持的类型化数组类型!”;
}
问题是typescript编译器给了我如下错误:

类型“Int32Array”不可分配给类型“T”。 “Int32Array”可分配给“T”类型的约束,但“T”可以用约束“TypedArray”的不同子类型实例化。ts(2322)

我注意到,如果我像这样添加,我可以消除错误:

export function createTypedArray<T extends TypedArray>( arg : { source : T, arraySize : number } ) : T {
  if( arg.source instanceof Int32Array ) {
    return new Int32Array( arg.arraySize );
  }
  if( arg.source instanceof Float32Array ) {
    return new Float32Array( arg.arraySize );
  }
  if( arg.source instanceof Float64Array ) {
    return new Float64Array( arg.arraySize );
  }
  throw 'Unsupported typed array type!';
}
return <T> new Int32Array( arg.arraySize );
export function createTypedArray<T extends TypedArray>( arg : { source : T, arraySize : number } ) : T {
  if( arg.source instanceof Int32Array ||
      arg.source instanceof Float32Array ||
      arg.source instanceof Float64Array
  ) {
    return new <T>( arg.arraySize );
  }
  throw 'Unsupported typed array type!';
}
返回新的Int32Array(arg.arraySize);
有没有更好的方法来编写这个函数

有没有一种方法可以这样写:

export function createTypedArray<T extends TypedArray>( arg : { source : T, arraySize : number } ) : T {
  if( arg.source instanceof Int32Array ) {
    return new Int32Array( arg.arraySize );
  }
  if( arg.source instanceof Float32Array ) {
    return new Float32Array( arg.arraySize );
  }
  if( arg.source instanceof Float64Array ) {
    return new Float64Array( arg.arraySize );
  }
  throw 'Unsupported typed array type!';
}
return <T> new Int32Array( arg.arraySize );
export function createTypedArray<T extends TypedArray>( arg : { source : T, arraySize : number } ) : T {
  if( arg.source instanceof Int32Array ||
      arg.source instanceof Float32Array ||
      arg.source instanceof Float64Array
  ) {
    return new <T>( arg.arraySize );
  }
  throw 'Unsupported typed array type!';
}
导出函数createTypedArray(arg:{source:T,arraySize:number}):T{
如果(arg.source instanceof Int32Array||
arg.source Float32Array的实例||
arg.source浮点数组的实例
) {
返回新的(arg.arraySize);
}
抛出“不支持的类型化数组类型!”;
}

您的代码不起作用的原因是您误解了。它们缩小了左侧变量的类型,在您的示例中是
arg.source
。类型防护装置不会缩小类型变量
T
的类型*

因此,在任何情况下,如果Typescript不够聪明,无法从逻辑上推断出某种类型,但您可以,这正是您应该使用类型断言的时候。所以

return new Int32Array( arg.arraySize ) as T
这正是你应该做的



*可以说应该是这样的,因为
T
必须是
arg.source
的类型——也许您可以将其提交给Typescript团队。

您的代码不起作用的原因是您对。它们缩小了左侧变量的类型,在您的示例中是
arg.source
。类型防护装置不会缩小类型变量
T
的类型*

因此,在任何情况下,如果Typescript不够聪明,无法从逻辑上推断出某种类型,但您可以,这正是您应该使用类型断言的时候。所以

return new Int32Array( arg.arraySize ) as T
这正是你应该做的



*可以说应该是这样的,因为
T
必须是
arg.source
的类型——也许您可以将其提交给Typescript团队。

这是实现泛型函数的一个难点,其中泛型类型参数是联合类型。有关更多信息,请参阅。基本问题是,虽然编译器可能会将
arg.source
的类型缩小到,例如,
Int32Array
,但编译器无法将泛型类型参数从
T extensed TypedArray
缩小到类似
T extensed Int32Array
的范围。通常,当您缩小类型为
T
的值时,缩小
T
是不安全的,但在许多情况下,像您这样的情况下,这样做会非常方便。但目前还没有发生

要使用现有的实现并使其编译,可以使用以前的方法


如果这就是我要说的,我会让另一个答案成立,但我想表明,如果您愿意将实现扭曲成椒盐卷饼,以指导编译器完成逻辑,那么您可以得到一些至少是模糊类型安全的东西,而无需断言:

const typedArrayMaker = (size: number) => ({
    get Int32Array() { return new Int32Array(size); },
    get Float32Array() { return new Float32Array(size); },
    get Float64Array() { return new Float64Array(size); }
});    
export function createTypedArray<K extends keyof ReturnType<typeof typedArrayMaker>>(
    arg: { source: { [Symbol.toStringTag]: K }, arraySize: number }) {
    return typedArrayMaker(arg.arraySize)[arg.source[Symbol.toStringTag]];
}
然后,
createTypedArray()
函数采用与前面相同的参数,但泛型参数是
K
,即
arg.source
的属性值。已知所有类型化数组都具有此属性的值。这就是我们用来索引
typedArrayMaker
的内容

所有这些都将返回类型转换为通用索引操作,它实际上可以对此进行推理。最终得到的返回类型取决于
K
,没有错误。让我们测试一下:

function test(i32: Int32Array, f32: Float32Array, f64: Float64Array, i8: Int8Array) {
    const i32New = createTypedArray({ source: i32, arraySize: 128 }); // Int32Array
    const f32New = createTypedArray({ source: f32, arraySize: 128 }); // Float32Array
    const f64New = createTypedArray({ source: f64, arraySize: 128 }); // Float64Array
    const i8New = createTypedArray({ source: i8, arraySize: 128 }); // error!
    // ----------------------------> ~~~~~~
    // Type '"Int8Array"' is not assignable to type 
    // '"Int32Array" | "Float32Array" | "Float64Array"'
}
您可以看到,编译器识别出
i32New
f32New
f64New
属于预期类型,而
i8
在传递到
createTypedArray()
时会导致错误,因为该类型的数组类型尚未包含在我们的函数中

我只是觉得以编译器理解的方式展示一种方法会很有趣。实际上,我绝对建议使用类型断言,因为具有getter和symbol属性的高阶函数太疯狂了


好吧,希望这会有帮助;祝你好运


这是实现泛型函数的难点,其中泛型类型参数是联合类型。有关更多信息,请参阅。基本问题是,虽然编译器可能会将
arg.source
的类型缩小到,例如,
Int32Array
,但编译器无法将泛型类型参数从
T extensed TypedArray
缩小到类似
T extensed Int32Array
的范围。通常,当您缩小类型为
T
的值时,缩小
T
是不安全的,但在许多情况下,像您这样的情况下,这样做会非常方便。但目前还没有发生

要使用现有的实现并使其编译,可以使用以前的方法


如果这就是我要说的,我会让另一个答案成立,但我想表明,如果您愿意将实现扭曲成椒盐卷饼,以指导编译器完成逻辑,那么您可以得到一些至少是模糊类型安全的东西,而无需断言:

const typedArrayMaker = (size: number) => ({
    get Int32Array() { return new Int32Array(size); },
    get Float32Array() { return new Float32Array(size); },
    get Float64Array() { return new Float64Array(size); }
});    
export function createTypedArray<K extends keyof ReturnType<typeof typedArrayMaker>>(
    arg: { source: { [Symbol.toStringTag]: K }, arraySize: number }) {
    return typedArrayMaker(arg.arraySize)[arg.source[Symbol.toStringTag]];
}
然后,
createTypedArray()
函数采用与之前相同的参数