mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Optimize union type creation (#53771)
This commit is contained in:
parent
3445e58815
commit
b798e6bfa5
@ -1881,6 +1881,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
var tupleTypes = new Map<string, GenericType>();
|
||||
var unionTypes = new Map<string, UnionType>();
|
||||
var unionOfUnionTypes = new Map<string, Type>();
|
||||
var intersectionTypes = new Map<string, Type>();
|
||||
var stringLiteralTypes = new Map<string, StringLiteralType>();
|
||||
var numberLiteralTypes = new Map<number, NumberLiteralType>();
|
||||
@ -16228,9 +16229,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
function addTypeToUnion(typeSet: Type[], includes: TypeFlags, type: Type) {
|
||||
const flags = type.flags;
|
||||
if (flags & TypeFlags.Union) {
|
||||
return addTypesToUnion(typeSet, includes | (isNamedUnionType(type) ? TypeFlags.Union : 0), (type as UnionType).types);
|
||||
}
|
||||
// We ignore 'never' types in unions
|
||||
if (!(flags & TypeFlags.Never)) {
|
||||
includes |= flags & TypeFlags.IncludesMask;
|
||||
@ -16253,8 +16251,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// Add the given types to the given type set. Order is preserved, duplicates are removed,
|
||||
// and nested types of the given kind are flattened into the set.
|
||||
function addTypesToUnion(typeSet: Type[], includes: TypeFlags, types: readonly Type[]): TypeFlags {
|
||||
let lastType: Type | undefined;
|
||||
for (const type of types) {
|
||||
includes = addTypeToUnion(typeSet, includes, type);
|
||||
// We skip the type if it is the same as the last type we processed. This simple test particularly
|
||||
// saves a lot of work for large lists of the same union type, such as when resolving `Record<A, B>[A]`,
|
||||
// where A and B are large union types.
|
||||
if (type !== lastType) {
|
||||
includes = type.flags & TypeFlags.Union ?
|
||||
addTypesToUnion(typeSet, includes | (isNamedUnionType(type) ? TypeFlags.Union : 0), (type as UnionType).types) :
|
||||
addTypeToUnion(typeSet, includes, type);
|
||||
lastType = type;
|
||||
}
|
||||
}
|
||||
return includes;
|
||||
}
|
||||
@ -16406,6 +16413,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (types.length === 1) {
|
||||
return types[0];
|
||||
}
|
||||
// We optimize for the common case of unioning a union type with some other type (such as `undefined`).
|
||||
if (types.length === 2 && !origin && (types[0].flags & TypeFlags.Union || types[1].flags & TypeFlags.Union)) {
|
||||
const infix = unionReduction === UnionReduction.None ? "N" : unionReduction === UnionReduction.Subtype ? "S" : "L";
|
||||
const index = types[0].id < types[1].id ? 0 : 1;
|
||||
const id = types[index].id + infix + types[1 - index].id + getAliasId(aliasSymbol, aliasTypeArguments);
|
||||
let type = unionOfUnionTypes.get(id);
|
||||
if (!type) {
|
||||
type = getUnionTypeWorker(types, unionReduction, aliasSymbol, aliasTypeArguments, /*origin*/ undefined);
|
||||
unionOfUnionTypes.set(id, type);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
return getUnionTypeWorker(types, unionReduction, aliasSymbol, aliasTypeArguments, origin);
|
||||
}
|
||||
|
||||
function getUnionTypeWorker(types: readonly Type[], unionReduction: UnionReduction, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined, origin: Type | undefined): Type {
|
||||
let typeSet: Type[] | undefined = [];
|
||||
const includes = addTypesToUnion(typeSet, 0 as TypeFlags, types);
|
||||
if (unionReduction !== UnionReduction.None) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user