Support deferred resolution of type arguments in type references

This commit is contained in:
Anders Hejlsberg 2019-08-23 09:54:55 -04:00
parent 5ae286329f
commit 643351ca2d
3 changed files with 100 additions and 58 deletions

View file

@ -508,6 +508,7 @@ namespace ts {
getIndexTypeOfStructuredType, getIndexTypeOfStructuredType,
getConstraintOfTypeParameter, getConstraintOfTypeParameter,
getFirstIdentifier, getFirstIdentifier,
getTypeArguments,
), ),
getAmbientModules, getAmbientModules,
getJsxIntrinsicTagNamesAt, getJsxIntrinsicTagNamesAt,
@ -3539,6 +3540,7 @@ namespace ts {
} }
function createNodeBuilder() { function createNodeBuilder() {
let depth = 0;
return { return {
typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) =>
withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)), withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)),
@ -3700,6 +3702,12 @@ namespace ts {
return createThis(); return createThis();
} }
if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) {
const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context);
if (isReservedMemberName(type.aliasSymbol.escapedName) && !(type.aliasSymbol.flags & SymbolFlags.Class)) return createTypeReferenceNode(createIdentifier(""), typeArgumentNodes);
return symbolToTypeNode(type.aliasSymbol, context, SymbolFlags.Type, typeArgumentNodes);
}
const objectFlags = getObjectFlags(type); const objectFlags = getObjectFlags(type);
if (objectFlags & ObjectFlags.Reference) { if (objectFlags & ObjectFlags.Reference) {
@ -3722,11 +3730,6 @@ namespace ts {
? symbolToTypeNode(type.symbol, context, SymbolFlags.Type) ? symbolToTypeNode(type.symbol, context, SymbolFlags.Type)
: createTypeReferenceNode(createIdentifier("?"), /*typeArguments*/ undefined); : createTypeReferenceNode(createIdentifier("?"), /*typeArguments*/ undefined);
} }
if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) {
const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context);
if (isReservedMemberName(type.aliasSymbol.escapedName) && !(type.aliasSymbol.flags & SymbolFlags.Class)) return createTypeReferenceNode(createIdentifier(""), typeArgumentNodes);
return symbolToTypeNode(type.aliasSymbol, context, SymbolFlags.Type, typeArgumentNodes);
}
if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) {
const types = type.flags & TypeFlags.Union ? formatUnionTypes((<UnionType>type).types) : (<IntersectionType>type).types; const types = type.flags & TypeFlags.Union ? formatUnionTypes((<UnionType>type).types) : (<IntersectionType>type).types;
if (length(types) === 1) { if (length(types) === 1) {
@ -3904,14 +3907,18 @@ namespace ts {
} }
function typeReferenceToTypeNode(type: TypeReference) { function typeReferenceToTypeNode(type: TypeReference) {
const typeArguments: ReadonlyArray<Type> = type.typeArguments || emptyArray; const typeArguments: ReadonlyArray<Type> = getTypeArguments(type);
if (type.target === globalArrayType || type.target === globalReadonlyArrayType) { if (type.target === globalArrayType || type.target === globalReadonlyArrayType) {
if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) {
const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); depth++;
return createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]); const typeArgumentNode = typeToTypeNodeHelper(depth >= 5 ? anyType : typeArguments[0], context);
depth--;
createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]);
} }
const elementType = typeToTypeNodeHelper(typeArguments[0], context); depth++;
const elementType = typeToTypeNodeHelper(depth >= 5 ? anyType : typeArguments[0], context);
depth--;
const arrayType = createArrayTypeNode(elementType); const arrayType = createArrayTypeNode(elementType);
return type.target === globalArrayType ? arrayType : createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); return type.target === globalArrayType ? arrayType : createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType);
} }
@ -6231,7 +6238,7 @@ namespace ts {
const signatures = getSignaturesOfType(type, SignatureKind.Construct); const signatures = getSignaturesOfType(type, SignatureKind.Construct);
if (signatures.length === 1) { if (signatures.length === 1) {
const s = signatures[0]; const s = signatures[0];
return !s.typeParameters && s.parameters.length === 1 && s.hasRestParameter && getTypeOfParameter(s.parameters[0]) === anyArrayType; return !s.typeParameters && s.parameters.length === 1 && s.hasRestParameter && getElementTypeOfArrayType(getTypeOfParameter(s.parameters[0])) === anyType;
} }
return false; return false;
} }
@ -6402,7 +6409,7 @@ namespace ts {
const outerTypeParameters = (<InterfaceType>type).outerTypeParameters; const outerTypeParameters = (<InterfaceType>type).outerTypeParameters;
if (outerTypeParameters) { if (outerTypeParameters) {
const last = outerTypeParameters.length - 1; const last = outerTypeParameters.length - 1;
const typeArguments = (<TypeReference>type).typeArguments!; const typeArguments = getTypeArguments(<TypeReference>type);
return outerTypeParameters[last].symbol !== typeArguments[last].symbol; return outerTypeParameters[last].symbol !== typeArguments[last].symbol;
} }
return true; return true;
@ -6493,7 +6500,7 @@ namespace ts {
(<GenericType>type).instantiations = createMap<TypeReference>(); (<GenericType>type).instantiations = createMap<TypeReference>();
(<GenericType>type).instantiations.set(getTypeListId(type.typeParameters), <GenericType>type); (<GenericType>type).instantiations.set(getTypeListId(type.typeParameters), <GenericType>type);
(<GenericType>type).target = <GenericType>type; (<GenericType>type).target = <GenericType>type;
(<GenericType>type).typeArguments = type.typeParameters; (<GenericType>type).resolvedTypeArguments = type.typeParameters;
type.thisType = createTypeParameter(symbol); type.thisType = createTypeParameter(symbol);
type.thisType.isThisType = true; type.thisType.isThisType = true;
type.thisType.constraint = type; type.thisType.constraint = type;
@ -7017,7 +7024,7 @@ namespace ts {
function getTypeWithThisArgument(type: Type, thisArgument?: Type, needApparentType?: boolean): Type { function getTypeWithThisArgument(type: Type, thisArgument?: Type, needApparentType?: boolean): Type {
if (getObjectFlags(type) & ObjectFlags.Reference) { if (getObjectFlags(type) & ObjectFlags.Reference) {
const target = (<TypeReference>type).target; const target = (<TypeReference>type).target;
const typeArguments = (<TypeReference>type).typeArguments; const typeArguments = getTypeArguments(<TypeReference>type);
if (length(target.typeParameters) === length(typeArguments)) { if (length(target.typeParameters) === length(typeArguments)) {
const ref = createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])); const ref = createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!]));
return needApparentType ? getApparentType(ref) : ref; return needApparentType ? getApparentType(ref) : ref;
@ -7082,9 +7089,9 @@ namespace ts {
function resolveTypeReferenceMembers(type: TypeReference): void { function resolveTypeReferenceMembers(type: TypeReference): void {
const source = resolveDeclaredMembers(type.target); const source = resolveDeclaredMembers(type.target);
const typeParameters = concatenate(source.typeParameters!, [source.thisType!]); const typeParameters = concatenate(source.typeParameters!, [source.thisType!]);
const typeArguments = type.typeArguments && type.typeArguments.length === typeParameters.length ? const typeArguments = getTypeArguments(type);
type.typeArguments : concatenate(type.typeArguments, [type]); const paddedTypeArguments = typeArguments.length === typeParameters.length ? typeArguments : concatenate(typeArguments, [type]);
resolveObjectTypeMembers(type, source, typeParameters, typeArguments); resolveObjectTypeMembers(type, source, typeParameters, paddedTypeArguments);
} }
function createSignature( function createSignature(
@ -7135,7 +7142,7 @@ namespace ts {
const restParameter = sig.parameters[restIndex]; const restParameter = sig.parameters[restIndex];
const restType = getTypeOfSymbol(restParameter); const restType = getTypeOfSymbol(restParameter);
if (isTupleType(restType)) { if (isTupleType(restType)) {
const elementTypes = restType.typeArguments || emptyArray; const elementTypes = getTypeArguments(restType);
const minLength = restType.target.minLength; const minLength = restType.target.minLength;
const tupleRestIndex = restType.target.hasRestElement ? elementTypes.length - 1 : -1; const tupleRestIndex = restType.target.hasRestElement ? elementTypes.length - 1 : -1;
const restParams = map(elementTypes, (t, i) => { const restParams = map(elementTypes, (t, i) => {
@ -9056,7 +9063,7 @@ namespace ts {
target.instantiations.set(id, type); target.instantiations.set(id, type);
type.objectFlags |= typeArguments ? getPropagatingFlagsOfTypes(typeArguments, /*excludeKinds*/ 0) : 0; type.objectFlags |= typeArguments ? getPropagatingFlagsOfTypes(typeArguments, /*excludeKinds*/ 0) : 0;
type.target = target; type.target = target;
type.typeArguments = typeArguments; type.resolvedTypeArguments = typeArguments;
} }
return type; return type;
} }
@ -9066,10 +9073,28 @@ namespace ts {
type.symbol = source.symbol; type.symbol = source.symbol;
type.objectFlags = source.objectFlags; type.objectFlags = source.objectFlags;
type.target = source.target; type.target = source.target;
type.typeArguments = source.typeArguments; type.resolvedTypeArguments = source.resolvedTypeArguments;
return type; return type;
} }
function createDeferredTypeReference(target: GenericType, typeArgumentNodes: ReadonlyArray<TypeNode>, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray<Type>): TypeReference {
const type = <TypeReference>createObjectType(ObjectFlags.Reference, target.symbol);
type.target = target;
type.typeArgumentNodes = typeArgumentNodes;
type.mapper = mapper;
type.aliasSymbol = aliasSymbol;
type.aliasTypeArguments = aliasTypeArguments;
return type;
}
function getTypeArguments(type: TypeReference): ReadonlyArray<Type> {
if (!type.resolvedTypeArguments) {
const typeArguments = type.typeArgumentNodes ? map(type.typeArgumentNodes, getTypeFromTypeNode) : emptyArray;
type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments;
}
return type.resolvedTypeArguments;
}
function getTypeReferenceArity(type: TypeReference): number { function getTypeReferenceArity(type: TypeReference): number {
return length(type.target.typeParameters); return length(type.target.typeParameters);
} }
@ -9559,7 +9584,10 @@ namespace ts {
function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type { function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type {
const links = getNodeLinks(node); const links = getNodeLinks(node);
if (!links.resolvedType) { if (!links.resolvedType) {
links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType), isReadonlyTypeOperator(node.parent)); const target = isReadonlyTypeOperator(node.parent) ? globalReadonlyArrayType : globalArrayType;
const aliasSymbol = getAliasSymbolForTypeNode(node);
const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol);
links.resolvedType = createDeferredTypeReference(target, [node.elementType], /*mapper*/ undefined, aliasSymbol, aliasTypeArguments);
} }
return links.resolvedType; return links.resolvedType;
} }
@ -9603,7 +9631,7 @@ namespace ts {
type.instantiations = createMap<TypeReference>(); type.instantiations = createMap<TypeReference>();
type.instantiations.set(getTypeListId(type.typeParameters), <GenericType>type); type.instantiations.set(getTypeListId(type.typeParameters), <GenericType>type);
type.target = <GenericType>type; type.target = <GenericType>type;
type.typeArguments = type.typeParameters; type.resolvedTypeArguments = type.typeParameters;
type.thisType = createTypeParameter(); type.thisType = createTypeParameter();
type.thisType.isThisType = true; type.thisType.isThisType = true;
type.thisType.constraint = type; type.thisType.constraint = type;
@ -9659,7 +9687,7 @@ namespace ts {
index = Math.min(index, getTypeReferenceArity(type) - 1); index = Math.min(index, getTypeReferenceArity(type) - 1);
} }
return createTupleType( return createTupleType(
(type.typeArguments || emptyArray).slice(index), getTypeArguments(type).slice(index),
Math.max(0, tuple.minLength - index), Math.max(0, tuple.minLength - index),
tuple.hasRestElement, tuple.hasRestElement,
tuple.readonly, tuple.readonly,
@ -11507,7 +11535,7 @@ namespace ts {
function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) { function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) {
const minLength = tupleType.target.minLength; const minLength = tupleType.target.minLength;
const elementTypes = map(tupleType.typeArguments || emptyArray, (_, i) => const elementTypes = map(getTypeArguments(tupleType), (_, i) =>
instantiateMappedTypeTemplate(mappedType, getLiteralType("" + i), i >= minLength, mapper)); instantiateMappedTypeTemplate(mappedType, getLiteralType("" + i), i >= minLength, mapper));
const modifiers = getMappedTypeModifiers(mappedType); const modifiers = getMappedTypeModifiers(mappedType);
const newMinLength = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : const newMinLength = modifiers & MappedTypeModifiers.IncludeOptional ? 0 :
@ -11616,9 +11644,19 @@ namespace ts {
return getAnonymousTypeInstantiation(<AnonymousType>type, mapper); return getAnonymousTypeInstantiation(<AnonymousType>type, mapper);
} }
if (objectFlags & ObjectFlags.Reference) { if (objectFlags & ObjectFlags.Reference) {
const typeArguments = (<TypeReference>type).typeArguments; const resolvedTypeArguments = (<TypeReference>type).resolvedTypeArguments;
const newTypeArguments = instantiateTypes(typeArguments, mapper); if (resolvedTypeArguments) {
return newTypeArguments !== typeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type; const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper);
return newTypeArguments !== resolvedTypeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type;
}
else {
const typeArgumentNodes = (<TypeReference>type).typeArgumentNodes;
if (typeArgumentNodes) {
const combinedMapper = combineTypeMappers((<TypeReference>type).mapper, mapper);
return createDeferredTypeReference((<TypeReference>type).target, typeArgumentNodes, combinedMapper,
(<TypeReference>type).aliasSymbol, instantiateTypes((<TypeReference>type).aliasTypeArguments, combinedMapper));
}
}
} }
return type; return type;
} }
@ -13284,8 +13322,8 @@ namespace ts {
source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) { source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) {
propagateSidebandVarianceFlags(source.aliasTypeArguments, getAliasVariances(source.aliasSymbol)); propagateSidebandVarianceFlags(source.aliasTypeArguments, getAliasVariances(source.aliasSymbol));
} }
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target && length((<TypeReference>source).typeArguments)) { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target && length(getTypeArguments(<TypeReference>source))) {
propagateSidebandVarianceFlags((<TypeReference>source).typeArguments!, getVariances((<TypeReference>source).target)); propagateSidebandVarianceFlags(getTypeArguments(<TypeReference>source), getVariances((<TypeReference>source).target));
} }
} }
return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False; return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
@ -13569,7 +13607,7 @@ namespace ts {
// type references (which are intended by be compared structurally). Obtain the variance // type references (which are intended by be compared structurally). Obtain the variance
// information for the type parameters and relate the type arguments accordingly. // information for the type parameters and relate the type arguments accordingly.
const variances = getVariances((<TypeReference>source).target); const variances = getVariances((<TypeReference>source).target);
const varianceResult = relateVariances((<TypeReference>source).typeArguments, (<TypeReference>target).typeArguments, variances, isIntersectionConstituent); const varianceResult = relateVariances(getTypeArguments(<TypeReference>source), getTypeArguments(<TypeReference>target), variances, isIntersectionConstituent);
if (varianceResult !== undefined) { if (varianceResult !== undefined) {
return varianceResult; return varianceResult;
} }
@ -13995,8 +14033,9 @@ namespace ts {
} }
const targetCount = getTypeReferenceArity(target) - 1; const targetCount = getTypeReferenceArity(target) - 1;
const sourceCount = getTypeReferenceArity(source) - (sourceRestType ? 1 : 0); const sourceCount = getTypeReferenceArity(source) - (sourceRestType ? 1 : 0);
const sourceTypeArguments = getTypeArguments(<TypeReference>source);
for (let i = targetCount; i < sourceCount; i++) { for (let i = targetCount; i < sourceCount; i++) {
const related = isRelatedTo((<TypeReference>source).typeArguments![i], targetRestType, reportErrors); const related = isRelatedTo(sourceTypeArguments[i], targetRestType, reportErrors);
if (!related) { if (!related) {
if (reportErrors) { if (reportErrors) {
reportError(Diagnostics.Property_0_is_incompatible_with_rest_element_type, "" + i); reportError(Diagnostics.Property_0_is_incompatible_with_rest_element_type, "" + i);
@ -14408,7 +14447,7 @@ namespace ts {
} }
function isTypeReferenceWithGenericArguments(type: Type): boolean { function isTypeReferenceWithGenericArguments(type: Type): boolean {
return !!(getObjectFlags(type) & ObjectFlags.Reference) && some((<TypeReference>type).typeArguments, t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t)); return !!(getObjectFlags(type) & ObjectFlags.Reference) && some(getTypeArguments(<TypeReference>type), t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t));
} }
/** /**
@ -14417,7 +14456,7 @@ namespace ts {
*/ */
function getTypeReferenceId(type: TypeReference, typeParameters: Type[], depth = 0) { function getTypeReferenceId(type: TypeReference, typeParameters: Type[], depth = 0) {
let result = "" + type.target.id; let result = "" + type.target.id;
for (const t of type.typeArguments!) { for (const t of getTypeArguments(type)) {
if (isUnconstrainedTypeParameter(t)) { if (isUnconstrainedTypeParameter(t)) {
let index = typeParameters.indexOf(t); let index = typeParameters.indexOf(t);
if (index < 0) { if (index < 0) {
@ -14688,7 +14727,7 @@ namespace ts {
} }
function getElementTypeOfArrayType(type: Type): Type | undefined { function getElementTypeOfArrayType(type: Type): Type | undefined {
return isArrayType(type) && (type as TypeReference).typeArguments ? (type as TypeReference).typeArguments![0] : undefined; return isArrayType(type) ? getTypeArguments(type as TypeReference)[0] : undefined;
} }
function isArrayLikeType(type: Type): boolean { function isArrayLikeType(type: Type): boolean {
@ -14698,7 +14737,7 @@ namespace ts {
} }
function isEmptyArrayLiteralType(type: Type): boolean { function isEmptyArrayLiteralType(type: Type): boolean {
const elementType = isArrayType(type) ? (<TypeReference>type).typeArguments![0] : undefined; const elementType = isArrayType(type) ? getTypeArguments(<TypeReference>type)[0] : undefined;
return elementType === undefinedWideningType || elementType === implicitNeverType; return elementType === undefinedWideningType || elementType === implicitNeverType;
} }
@ -14796,7 +14835,7 @@ namespace ts {
} }
function getRestTypeOfTupleType(type: TupleTypeReference) { function getRestTypeOfTupleType(type: TupleTypeReference) {
return type.target.hasRestElement ? type.typeArguments![type.target.typeParameters!.length - 1] : undefined; return type.target.hasRestElement ? getTypeArguments(type)[type.target.typeParameters!.length - 1] : undefined;
} }
function getRestArrayTypeOfTupleType(type: TupleTypeReference) { function getRestArrayTypeOfTupleType(type: TupleTypeReference) {
@ -15085,7 +15124,7 @@ namespace ts {
result = getIntersectionType(sameMap((<IntersectionType>type).types, getWidenedType)); result = getIntersectionType(sameMap((<IntersectionType>type).types, getWidenedType));
} }
else if (isArrayType(type) || isTupleType(type)) { else if (isArrayType(type) || isTupleType(type)) {
result = createTypeReference((<TypeReference>type).target, sameMap((<TypeReference>type).typeArguments, getWidenedType)); result = createTypeReference((<TypeReference>type).target, sameMap(getTypeArguments(<TypeReference>type), getWidenedType));
} }
if (result && context === undefined) { if (result && context === undefined) {
type.widened = result; type.widened = result;
@ -15122,7 +15161,7 @@ namespace ts {
} }
} }
if (isArrayType(type) || isTupleType(type)) { if (isArrayType(type) || isTupleType(type)) {
for (const t of (<TypeReference>type).typeArguments!) { for (const t of getTypeArguments(<TypeReference>type)) {
if (reportWideningErrorsInType(t)) { if (reportWideningErrorsInType(t)) {
errorReported = true; errorReported = true;
} }
@ -15332,7 +15371,7 @@ namespace ts {
function couldContainTypeVariables(type: Type): boolean { function couldContainTypeVariables(type: Type): boolean {
const objectFlags = getObjectFlags(type); const objectFlags = getObjectFlags(type);
return !!(type.flags & TypeFlags.Instantiable || return !!(type.flags & TypeFlags.Instantiable ||
objectFlags & ObjectFlags.Reference && forEach((<TypeReference>type).typeArguments, couldContainTypeVariables) || objectFlags & ObjectFlags.Reference && forEach(getTypeArguments(<TypeReference>type), couldContainTypeVariables) ||
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ||
objectFlags & ObjectFlags.Mapped || objectFlags & ObjectFlags.Mapped ||
type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && couldUnionOrIntersectionContainTypeVariables(<UnionOrIntersectionType>type)); type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && couldUnionOrIntersectionContainTypeVariables(<UnionOrIntersectionType>type));
@ -15408,10 +15447,10 @@ namespace ts {
// For arrays and tuples we infer new arrays and tuples where the reverse mapping has been // For arrays and tuples we infer new arrays and tuples where the reverse mapping has been
// applied to the element type(s). // applied to the element type(s).
if (isArrayType(source)) { if (isArrayType(source)) {
return createArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target, constraint), isReadonlyArrayType(source)); return createArrayType(inferReverseMappedType(getTypeArguments(<TypeReference>source)[0], target, constraint), isReadonlyArrayType(source));
} }
if (isTupleType(source)) { if (isTupleType(source)) {
const elementTypes = map(source.typeArguments || emptyArray, t => inferReverseMappedType(t, target, constraint)); const elementTypes = map(getTypeArguments(source), t => inferReverseMappedType(t, target, constraint));
const minLength = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ? const minLength = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ?
getTypeReferenceArity(source) - (source.target.hasRestElement ? 1 : 0) : source.target.minLength; getTypeReferenceArity(source) - (source.target.hasRestElement ? 1 : 0) : source.target.minLength;
return createTupleType(elementTypes, minLength, source.target.hasRestElement, source.target.readonly, source.target.associatedNames); return createTupleType(elementTypes, minLength, source.target.hasRestElement, source.target.readonly, source.target.associatedNames);
@ -15625,7 +15664,7 @@ namespace ts {
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (
(<TypeReference>source).target === (<TypeReference>target).target || isArrayType(source) && isArrayType(target))) { (<TypeReference>source).target === (<TypeReference>target).target || isArrayType(source) && isArrayType(target))) {
// If source and target are references to the same generic type, infer from type arguments // If source and target are references to the same generic type, infer from type arguments
inferFromTypeArguments((<TypeReference>source).typeArguments || emptyArray, (<TypeReference>target).typeArguments || emptyArray, getVariances((<TypeReference>source).target)); inferFromTypeArguments(getTypeArguments(<TypeReference>source), getTypeArguments(<TypeReference>target), getVariances((<TypeReference>source).target));
} }
else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) {
contravariant = !contravariant; contravariant = !contravariant;
@ -15945,10 +15984,10 @@ namespace ts {
const targetRestType = getRestTypeOfTupleType(target); const targetRestType = getRestTypeOfTupleType(target);
const fixedLength = targetLength < sourceLength || sourceRestType ? targetLength : sourceLength; const fixedLength = targetLength < sourceLength || sourceRestType ? targetLength : sourceLength;
for (let i = 0; i < fixedLength; i++) { for (let i = 0; i < fixedLength; i++) {
inferFromTypes(i < sourceLength ? (<TypeReference>source).typeArguments![i] : sourceRestType!, target.typeArguments![i]); inferFromTypes(i < sourceLength ? getTypeArguments(<TypeReference>source)[i] : sourceRestType!, getTypeArguments(target)[i]);
} }
if (targetRestType) { if (targetRestType) {
const types = fixedLength < sourceLength ? (<TypeReference>source).typeArguments!.slice(fixedLength, sourceLength) : []; const types = fixedLength < sourceLength ? getTypeArguments(<TypeReference>source).slice(fixedLength, sourceLength) : [];
if (sourceRestType) { if (sourceRestType) {
types.push(sourceRestType); types.push(sourceRestType);
} }
@ -18598,7 +18637,7 @@ namespace ts {
} }
function getThisTypeArgument(type: Type): Type | undefined { function getThisTypeArgument(type: Type): Type | undefined {
return getObjectFlags(type) & ObjectFlags.Reference && (<TypeReference>type).target === globalThisType ? (<TypeReference>type).typeArguments![0] : undefined; return getObjectFlags(type) & ObjectFlags.Reference && (<TypeReference>type).target === globalThisType ? getTypeArguments(<TypeReference>type)[0] : undefined;
} }
function getThisTypeFromContextualType(type: Type): Type | undefined { function getThisTypeFromContextualType(type: Type): Type | undefined {
@ -21651,7 +21690,7 @@ namespace ts {
const spreadArgument = <SpreadElement>args[length - 1]; const spreadArgument = <SpreadElement>args[length - 1];
const type = flowLoopCount ? checkExpression(spreadArgument.expression) : checkExpressionCached(spreadArgument.expression); const type = flowLoopCount ? checkExpression(spreadArgument.expression) : checkExpressionCached(spreadArgument.expression);
if (isTupleType(type)) { if (isTupleType(type)) {
const typeArguments = (<TypeReference>type).typeArguments || emptyArray; const typeArguments = getTypeArguments(<TypeReference>type);
const restIndex = type.target.hasRestElement ? typeArguments.length - 1 : -1; const restIndex = type.target.hasRestElement ? typeArguments.length - 1 : -1;
const syntheticArgs = map(typeArguments, (t, i) => createSyntheticExpression(spreadArgument, t, /*isSpread*/ i === restIndex)); const syntheticArgs = map(typeArguments, (t, i) => createSyntheticExpression(spreadArgument, t, /*isSpread*/ i === restIndex));
return concatenate(args.slice(0, length - 1), syntheticArgs); return concatenate(args.slice(0, length - 1), syntheticArgs);
@ -23199,7 +23238,7 @@ namespace ts {
// otherwise would return the type 'undefined'). // otherwise would return the type 'undefined').
const restType = getTypeOfSymbol(signature.parameters[paramCount]); const restType = getTypeOfSymbol(signature.parameters[paramCount]);
const index = pos - paramCount; const index = pos - paramCount;
if (!isTupleType(restType) || restType.target.hasRestElement || index < (restType.typeArguments || emptyArray).length) { if (!isTupleType(restType) || restType.target.hasRestElement || index < getTypeArguments(restType).length) {
return getIndexedAccessType(restType, getLiteralType(index)); return getIndexedAccessType(restType, getLiteralType(index));
} }
} }
@ -23233,7 +23272,7 @@ namespace ts {
if (signature.hasRestParameter) { if (signature.hasRestParameter) {
const restType = getTypeOfSymbol(signature.parameters[length - 1]); const restType = getTypeOfSymbol(signature.parameters[length - 1]);
if (isTupleType(restType)) { if (isTupleType(restType)) {
return length + (restType.typeArguments || emptyArray).length - 1; return length + getTypeArguments(restType).length - 1;
} }
} }
return length; return length;
@ -24975,7 +25014,7 @@ namespace ts {
function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) { function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) {
const patternElements = pattern.elements; const patternElements = pattern.elements;
const arity = getTypeReferenceArity(type); const arity = getTypeReferenceArity(type);
const elementTypes = arity ? type.typeArguments!.slice() : []; const elementTypes = arity ? getTypeArguments(type).slice() : [];
for (let i = arity; i < patternElements.length; i++) { for (let i = arity; i < patternElements.length; i++) {
const e = patternElements[i]; const e = patternElements[i];
if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && e.dotDotDotToken)) { if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && e.dotDotDotToken)) {
@ -26542,7 +26581,7 @@ namespace ts {
} }
if (isReferenceToType(promise, getGlobalPromiseType(/*reportErrors*/ false))) { if (isReferenceToType(promise, getGlobalPromiseType(/*reportErrors*/ false))) {
return typeAsPromise.promisedTypeOfPromise = (<GenericType>promise).typeArguments![0]; return typeAsPromise.promisedTypeOfPromise = getTypeArguments(<GenericType>promise)[0];
} }
const thenFunction = getTypeOfPropertyOfType(promise, "then" as __String)!; // TODO: GH#18217 const thenFunction = getTypeOfPropertyOfType(promise, "then" as __String)!; // TODO: GH#18217
@ -28435,7 +28474,7 @@ namespace ts {
let globalType: Type; let globalType: Type;
if (isReferenceToType(type, globalType = resolver.getGlobalIterableType(/*reportErrors*/ false)) || if (isReferenceToType(type, globalType = resolver.getGlobalIterableType(/*reportErrors*/ false)) ||
isReferenceToType(type, globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false))) { isReferenceToType(type, globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false))) {
const [yieldType] = (type as GenericType).typeArguments!; const [yieldType] = getTypeArguments(type as GenericType);
// The "return" and "next" types of `Iterable` and `IterableIterator` are defined by the // The "return" and "next" types of `Iterable` and `IterableIterator` are defined by the
// iteration types of their `[Symbol.iterator]()` method. The same is true for their async cousins. // iteration types of their `[Symbol.iterator]()` method. The same is true for their async cousins.
// While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use // While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use
@ -28448,7 +28487,7 @@ namespace ts {
// just grab its related type arguments: // just grab its related type arguments:
// - `Generator<T, TReturn, TNext>` or `AsyncGenerator<T, TReturn, TNext>` // - `Generator<T, TReturn, TNext>` or `AsyncGenerator<T, TReturn, TNext>`
if (isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) { if (isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) {
const [yieldType, returnType, nextType] = (type as GenericType).typeArguments!; const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType);
return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = createIterationTypes(yieldType, returnType, nextType); return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = createIterationTypes(yieldType, returnType, nextType);
} }
} }
@ -28536,7 +28575,7 @@ namespace ts {
// - `Generator<T, TReturn, TNext>` or `AsyncGenerator<T, TReturn, TNext>` // - `Generator<T, TReturn, TNext>` or `AsyncGenerator<T, TReturn, TNext>`
const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false); const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false);
if (isReferenceToType(type, globalType)) { if (isReferenceToType(type, globalType)) {
const [yieldType] = (type as GenericType).typeArguments!; const [yieldType] = getTypeArguments(type as GenericType);
// The "return" and "next" types of `IterableIterator` and `AsyncIterableIterator` are defined by the // The "return" and "next" types of `IterableIterator` and `AsyncIterableIterator` are defined by the
// iteration types of their `next`, `return`, and `throw` methods. While we define these as `any` // iteration types of their `next`, `return`, and `throw` methods. While we define these as `any`
// and `undefined` in our libs by default, a custom lib *could* use different definitions. // and `undefined` in our libs by default, a custom lib *could* use different definitions.
@ -28548,7 +28587,7 @@ namespace ts {
} }
if (isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) || if (isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) ||
isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) { isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) {
const [yieldType, returnType, nextType] = (type as GenericType).typeArguments!; const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType);
return (type as IterableOrIteratorType)[resolver.iteratorCacheKey] = createIterationTypes(yieldType, returnType, nextType); return (type as IterableOrIteratorType)[resolver.iteratorCacheKey] = createIterationTypes(yieldType, returnType, nextType);
} }
} }
@ -28590,11 +28629,11 @@ namespace ts {
// As an optimization, if the type is an instantiation of one of the global `IteratorYieldResult<T>` // As an optimization, if the type is an instantiation of one of the global `IteratorYieldResult<T>`
// or `IteratorReturnResult<TReturn>` types, then just grab its type argument. // or `IteratorReturnResult<TReturn>` types, then just grab its type argument.
if (isReferenceToType(type, getGlobalIteratorYieldResultType(/*reportErrors*/ false))) { if (isReferenceToType(type, getGlobalIteratorYieldResultType(/*reportErrors*/ false))) {
const yieldType = (type as GenericType).typeArguments![0]; const yieldType = getTypeArguments(type as GenericType)[0];
return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined); return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined);
} }
if (isReferenceToType(type, getGlobalIteratorReturnResultType(/*reportErrors*/ false))) { if (isReferenceToType(type, getGlobalIteratorReturnResultType(/*reportErrors*/ false))) {
const returnType = (type as GenericType).typeArguments![0]; const returnType = getTypeArguments(type as GenericType)[0];
return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined); return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined);
} }

View file

@ -10,7 +10,8 @@ namespace ts {
getResolvedSymbol: (node: Node) => Symbol, getResolvedSymbol: (node: Node) => Symbol,
getIndexTypeOfStructuredType: (type: Type, kind: IndexKind) => Type | undefined, getIndexTypeOfStructuredType: (type: Type, kind: IndexKind) => Type | undefined,
getConstraintOfTypeParameter: (typeParameter: TypeParameter) => Type | undefined, getConstraintOfTypeParameter: (typeParameter: TypeParameter) => Type | undefined,
getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier) { getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier,
getTypeArguments: (type: TypeReference) => ReadonlyArray<Type>) {
return getSymbolWalker; return getSymbolWalker;
@ -89,7 +90,7 @@ namespace ts {
function visitTypeReference(type: TypeReference): void { function visitTypeReference(type: TypeReference): void {
visitType(type.target); visitType(type.target);
forEach(type.typeArguments, visitType); forEach(getTypeArguments(type), visitType);
} }
function visitTypeParameter(type: TypeParameter): void { function visitTypeParameter(type: TypeParameter): void {

View file

@ -4200,7 +4200,9 @@ namespace ts {
*/ */
export interface TypeReference extends ObjectType { export interface TypeReference extends ObjectType {
target: GenericType; // Type reference target target: GenericType; // Type reference target
typeArguments?: ReadonlyArray<Type>; // Type reference type arguments (undefined if none) resolvedTypeArguments?: ReadonlyArray<Type>; // Type reference type arguments (undefined if none)
typeArgumentNodes?: ReadonlyArray<TypeNode>;
mapper?: TypeMapper;
/* @internal */ /* @internal */
literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set
} }