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()
函数采用与之前相同的参数