例如,我有以下类型:
class User extends Entity {}
class Post extends Entity {}
type Entities = {
user: User,
post: Post,
// potentially hundreds more
};
type EntityType = 'user' | 'post' | ...;
当我在泛型中使用Entities
和EntityType
时,它明显减慢了Typescript的速度。仅在VS代码中显示类型信息就需要几分钟的时间。我有一些通用功能,比如:
function getEntityFromCache<T extends EntityType>(type: T, id: number): Entities[T] | null | undefined;
function getEntity<T extends EntityType>(type: T, id: number): Entities[T] | null {
const cachedEntity = getEntityFromCache(type, id);
if (cachedEntity !== undefined) {
return cachedEntity;
}
...
}
我之所以理解这是缓慢的,是因为Entities[T]
是Entities
的所有值的并集,即User | Post | ...
。TS不能很好地处理工会。为了检查cached
的返回类型是否正确,TS必须遍历T
的每个可能值。即如果是T = 'user'
,则验证cachedEntity
是Entities['user']
;如果是T = 'post'
,则验证cachedEntity
为Entities['post']
;等等。这很慢,因为每次我有泛型时,TS都必须检查并集的每个值。
此外,TS不只是比较泛型值('user' === 'user'
、'post' === 'post'
),而是比较整个实体(User === User
、Post === Post
)。这使情况变得更糟,因为实体很复杂。
有什么方法可以加快速度?以下是我的一些想法:
从中间函数中删除泛型,使它们返回基本实体类型,然后进行类型转换。例如
function getEntityFromCache(type: T, id: number): Entity | null | undefined;
以某种方式使TS比较实体类型字符串,而不是比较整个实体。
根据TypeScript wiki页面"偏好基类型而非并集"值得使用子类型,而不是联合。
然而,它们也有成本。每次将参数传递给printSchedule时,都必须将其与并集的每个元素进行比较。对于两个元素的并集来说,这是琐碎而廉价的。但是,如果您的并集有十几个元素,则可能会在编译速度方面造成实际问题。例如,为了从并集中消除冗余成员,必须成对比较元素,这是二次的。这种检查可能发生在与大型并集相交时,其中与每个并集成员相交可能会导致需要减少的大量类型。避免这种情况的一种方法是使用子类型,而不是联合。
文档中的简化示例:
interface A {
char: 'a' | 'b' | 'c' | 'd' | 'e';
}
interface B extends A {
char: 'a' | 'b';
}
interface C extends A {
char: 'd' | 'e';
}
declare function char(schedule: A): void;