我正在尝试键入嵌套的嵌套序列化程序层次结构。下面的这段代码是我们现有内容的简化版本:
'use strict';
abstract class TypedSerializer<In, Out> {
record: In;
constructor(record: In) {
this.record = record;
}
serializeObject<PIn, POut, S extends ObjectSerializerConstructor<PIn, POut>>(ctor: S, data: PIn): POut {
const serializerInstance = new ctor(data);
return serializerInstance.toObject();
}
serializeArray<PIn, POut, S extends ObjectSerializerConstructor<PIn, POut>>(ctor: S, arr: PIn[]): POut[] {
const fn: ((PIn) => POut) = data => this.serializeObject(ctor, data);
return arr.map(fn);
}
}
type ObjectSerializerConstructor<In, Out> = {
new(record: In): ObjectSerializer<In, Out>;
};
abstract class ObjectSerializer<In, Out> extends TypedSerializer<In, Out> {
toObject(): Out {
return null as Out;
}
}
abstract class TypedListSerializer<In, Out> extends TypedSerializer<In, Out> {
toList(): Out[] {
return [] as Out[];
}
}
interface A {
prop1: string;
}
interface B {
prop2: string;
}
class RecordSerializer extends ObjectSerializer<A, B> implements B {
get prop2() {
return '';
}
}
interface ListOut {
arr: B[]
}
class TestListSerializer extends TypedListSerializer<A, ListOut> implements ListOut {
produceInputs(): A[] {
return [] as A[];
}
get arr() { // <-- fails here, line 63
return this.serializeArray(RecordSerializer, this.produceInputs());
}
}
我期待它编译得很好,但它产生了一个错误:
tsc --moduleResolution node --target es6 --lib es6 --noEmit true test.ts
test.ts(63,7): error TS2416: Property 'arr' in type 'TestListSerializer' is not assignable to the same property in base type 'ListOut'.
Type '{}[]' is not assignable to type 'B[]'.
Type '{}' is not assignable to type 'B'.
Property 'prop2' is missing in type '{}'.
这里是 link typescript Playground
在我看来,TSC 似乎无法正确推断出 RecordSerializer
的实际通用参数,因此它以 {}
数组而不是 数组结尾B
.
添加像 this.serializeArray(...) as B[]
这样的显式转换可以解决这个问题。
但必须有更好的方法来告诉 Typescript 我想要什么。我错过了什么?
我正在使用 v2.8.1
最佳答案
让 typescript 根据一个通用参数推断另一个通用参数通常效果不佳。最简单的解决方案是使用条件类型根据 S
type GetInFrom<T> = T extends ObjectSerializerConstructor<infer In, any>? In : never;
type GetOutFrom<T> = T extends ObjectSerializerConstructor<any, infer Out>? Out : never;
serializeObject<S extends ObjectSerializerConstructor<any, any>>(ctor: S, data: GetInFrom<S>): GetOutFrom<S> {
const serializerInstance = new ctor(data);
return serializerInstance.toObject();
}
serializeArray<S extends ObjectSerializerConstructor<any, any>>(ctor: S, arr: GetInFrom<S>[]): GetOutFrom<S>[] {
const fn: ((pIn: GetInFrom<S>) => GetOutFrom<S>) = (data => this.serializeObject(ctor, data));
return arr.map(fn);
}
playground 上的完整代码
关于 typescript 构造函数泛型参数推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50282206/