【问题标题】:Typescript constructor generic argument inferenceTypescript 构造函数泛型参数推断
【发布时间】:2018-05-11 14:13:42
【问题描述】:

我正在尝试键入嵌套的嵌套序列化程序层次结构。下面的这个 sn-p 是我们所拥有的简化版本:

'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 打字稿游乐场

在我看来,TSC 似乎无法正确推断出RecordSerializer 的实际泛型参数,因此它以{} 数组结束,而不是B 数组。

添加像this.serializeArray(...) as B[] 这样的显式转换可以解决问题。 但必须有更好的方法来告诉 Typescript 我想要什么。我错过了什么?

我正在使用 v2.8.1

【问题讨论】:

    标签: typescript type-inference


    【解决方案1】:

    让打字稿根据另一个通用参数推断一个通用参数通常效果不佳。最简单的解决方案是使用条件类型来提取基于S的in和out参数

    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上的完整代码

    【讨论】:

    • 游乐场链接已损坏 - 它打开到一个空白页面。我将在我的 IDE 中使用代码。
    • @ilj Strange... 我会在上班时尝试修复它。代码似乎在那里,但操场忽略了它
    • @ilj 修复了操场链接
    • 有点奇怪,使用 比使用 效果更好,但它确实按我的意图工作。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2016-12-05
    • 2022-01-26
    • 2019-02-07
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 2020-01-23
    • 1970-01-01
    相关资源
    最近更新 更多