我有一个工厂,该工厂基于扩展BaseEntity的实体返回配置值。但是,我收到一个类型错误,指出无法从函数返回具有与通用参数相同签名的类型,特别是类型Collection<A> is not assignable to type Collection<T>
和那个Type A is not assignable to type T
。但是,在此示例中,A
和T
的定义不相同吗?
type BaseTypes = 'a';
interface Base {
type: BaseTypes;
id: number;
}
interface A extends Base {
type: 'a';
name: string;
}
interface Collection<T extends Base> {
items: T[];
}
function getCollection<T extends Base>(obj: T): Collection<T> | null {
switch (obj.type) {
case 'a':
return getACollection(); // Type Collection<A> is not assignable to type Collection<T>
default:
return null;
}
}
function getACollection(): Collection<A> {
return { items: [] };
}
答案 0 :(得分:1)
Typescript需要一个联合类型才能使用类型防护,Base
是派生接口的基本类型,但不是联合,因此编译器不会缩小联合。
第二个问题是,即使扩展了联合,Typescript也不会缩小泛型类型(尽管我相信在将来的发行版中这会改变,如果找到它,我会发布github问题。编辑 This是问题所在,但显然没有实现它的计划。但是,即使要缩小参数的类型,也只会缩小参数的范围,类型保护不会影响函数的返回类型。类型防护在影响方面非常狭窄。
最简单的解决方案是为函数提供两个不同的签名:一个带有通用参数的公共签名,一个不带通用参数的私有签名,它们使用Base
并返回Collection<Base>
。这不是一个完全类型安全的解决方案,因为该实现可以接受Base
的一个派生并返回不同派生的collectionsl,但这是我们目前能做的最好的事情。
function getCollection<T extends Base>(obj: T): Collection<T> | null
function getCollection(obj: Base): Collection<Base> | null {
switch (obj.type) {
case 'a':
return getACollection();
default:
return null;
}
}