Scenario:我正在try 创建一个基本方法,我可以对需要进行的几个不同调用重复使用(works/doesNotWork).基本方法应该进行一些设置,因为我不想重复几次.问题是,我传递给Setup调用的泛型告诉我它需要一个不同的类型.我需要的所有属性都存在于基本泛型类型上,但我遇到了打字问题.

Error:Argument of type '{ SyncCount: number; }' is not assignable to parameter of type 'DeepPartial<T>'.

Goal:我想要一个使用泛型的解决方案,它将允许我有一个基本方法,我可以调用设置.理想情况下,doesNotWork应该经过修改才能正常工作.AOS,请参见下面示例和小提琴中的所需代码(目标).

这是我issue美元中的一把小提琴

type DeepPartial<T> = T extends object ? {
    [P in keyof T]?: DeepPartial<T[P]>;
} : T;

interface IDbRecord {
    readonly _id: string;
    readonly _rev: string;
    readonly DocumentType: string;
}

interface IBuilder<TEntity extends IDbRecord> {
    defaults(value: DeepPartial<TEntity>): Builder<TEntity>
}

class Builder<TEntity extends IDbRecord> implements IBuilder<TEntity> {

    defaults(value: DeepPartial<TEntity>): IBuilder<TEntity> {
        return this;
    }

}

interface IBaseEntity extends IDbRecord {
    SyncCount: number;
    SyncStatus: string
}

interface ICar extends IBaseEntity {
    Model: string;
}

interface IPerson extends IBaseEntity {
    Name: string
}

class Test {

    protected builder<TEntity extends IDbRecord>() {
        return new Builder<TEntity>();
    }

    private works<T extends IBaseEntity>() {
        // not using the generic type works
        return this.builder<IBaseEntity>().defaults({ SyncCount: 0 })
    }

    private doesNotWork<T extends IBaseEntity>() {
        // using the generic type does not work here
        return this.builder<T>().defaults({ SyncCount: 0 }) // ERROR
    }

    private someWorkingImplmentation<T extends IBaseEntity>() {
        return this.builder<T>().defaults({ SyncCount: 0 });
    }

    // I want to avoid duplicate code below from defaults.
    // A base setup method would be best
    people = this.builder<IPerson>().defaults({ SyncCount: 0 });
    cars = this.builder<ICar>().defaults({ SyncCount: 0 });

    // GOAL
    _people = this.someWorkingImplmentation<IPerson>();
    _cars = this.someWorkingImplmentation<ICar>();
}

推荐答案

doesNotWork<T extends IBaseEntity>中的类型限制似乎没有向下传播到方法defaults.这个Typescript 认为泛型T可以是任何东西,尽管它被限制为IBaseEntity.有关更多详细信息,请参阅此SO question.

现在,约束就是这样流动的

doesNotWork<ICar> // return type inferred from builder<T>
  builder<T> - this is where the constraints of IBaseEntity fall off
    defaults<T>()

一个简单的解决方案是通过固定函数的返回类型来反转约束:

private doesNotWork<T extends IBaseEntity>(): IBuilder<T> {
    return this.builder<IBaseEntity>().defaults({ SyncCount: 0 })
}

通过添加返回类型IBuilder<T>,我们消除了流经构建器以确定返回类型的泛型T的要求.


这样,下面的代码现在可以正确识别接口的字段:

_people = this.works<IPerson>().defaults({ Name: 'Foo' });
_cars = this.works<ICar>().defaults({ Model: 'jetta' });

Typescript相关问答推荐

类型是工作.但它失go 了正确变体的亮点..为什么?或者如何增强?

如何用不同的键值初始化角react 形式

接口的额外属性作为同一接口的方法的参数类型'

使某些(嵌套)属性成为可选属性

我可以为情态车使用棱角形的路由守卫吗?

通过按键数组拾取对象的关键点

为什么我的一个合成函数不能推断类型?

嵌套对象的类型

如何在react组件中使用doctype和html标签?

AngularJS服务不会解析传入的Json响应到管道中的模型

使用TypeScrip的类型继承

有没有可能创建一种类型,强制在TypeScrip中返回`tyPeof`语句?

如何从一个泛型类型推断多个类型

S,为什么我的T扩展未定义的条件在属性的上下文中不起作用?

有没有办法在Reaction组件中动态导入打字脚本`type`?

有没有更干净的方法来更新**key of T**的值?

如何以类型安全的方式指定键的常量列表,并从该列表派生所挑选的接口?

如何处理可能为空的变量...我知道这不是Null?

仅当定义了值时才按值筛选数组

如何强制对象数组中的对象属性具有非空字符串值?