///
///
/* @internal */
namespace ts {
let nextSymbolId = 1;
let nextNodeId = 1;
let nextMergeId = 1;
let nextFlowId = 1;
const ambientModuleSymbolRegex = /^".+"$/;
export function getNodeId(node: Node): number {
if (!node.id) {
node.id = nextNodeId;
nextNodeId++;
}
return node.id;
}
export function getSymbolId(symbol: Symbol): number {
if (!symbol.id) {
symbol.id = nextSymbolId;
nextSymbolId++;
}
return symbol.id;
}
export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean) {
const moduleState = getModuleInstanceState(node);
return moduleState === ModuleInstanceState.Instantiated ||
(preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly);
}
export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker {
const impl = new TypeCheckerImpl(host, produceDiagnostics);
return impl.checker;
}
export const enum TypeFacts {
None = 0,
TypeofEQString = 1 << 0,
TypeofEQNumber = 1 << 1,
TypeofEQBoolean = 1 << 2,
TypeofEQSymbol = 1 << 3,
TypeofEQObject = 1 << 4,
TypeofEQFunction = 1 << 5,
TypeofEQHostObject = 1 << 6,
TypeofNEString = 1 << 7,
TypeofNENumber = 1 << 8,
TypeofNEBoolean = 1 << 9,
TypeofNESymbol = 1 << 10,
TypeofNEObject = 1 << 11,
TypeofNEFunction = 1 << 12,
TypeofNEHostObject = 1 << 13,
EQUndefined = 1 << 14,
EQNull = 1 << 15,
EQUndefinedOrNull = 1 << 16,
NEUndefined = 1 << 17,
NENull = 1 << 18,
NEUndefinedOrNull = 1 << 19,
Truthy = 1 << 20,
Falsy = 1 << 21,
Discriminatable = 1 << 22,
All = (1 << 23) - 1,
// The following members encode facts about particular kinds of types for use in the getTypeFacts function.
// The presence of a particular fact means that the given test is true for some (and possibly all) values
// of that kind of type.
BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull,
BaseStringFacts = BaseStringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
StringStrictFacts = BaseStringStrictFacts | Truthy | Falsy,
StringFacts = BaseStringFacts | Truthy,
EmptyStringStrictFacts = BaseStringStrictFacts | Falsy,
EmptyStringFacts = BaseStringFacts,
NonEmptyStringStrictFacts = BaseStringStrictFacts | Truthy,
NonEmptyStringFacts = BaseStringFacts | Truthy,
BaseNumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull,
BaseNumberFacts = BaseNumberStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
NumberStrictFacts = BaseNumberStrictFacts | Truthy | Falsy,
NumberFacts = BaseNumberFacts | Truthy,
ZeroStrictFacts = BaseNumberStrictFacts | Falsy,
ZeroFacts = BaseNumberFacts,
NonZeroStrictFacts = BaseNumberStrictFacts | Truthy,
NonZeroFacts = BaseNumberFacts | Truthy,
BaseBooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull,
BaseBooleanFacts = BaseBooleanStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
BooleanStrictFacts = BaseBooleanStrictFacts | Truthy | Falsy,
BooleanFacts = BaseBooleanFacts | Truthy,
FalseStrictFacts = BaseBooleanStrictFacts | Falsy,
FalseFacts = BaseBooleanFacts,
TrueStrictFacts = BaseBooleanStrictFacts | Truthy,
TrueFacts = BaseBooleanFacts | Truthy,
SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy,
SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Discriminatable,
ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Discriminatable,
FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy,
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy
}
export const enum TypeSystemPropertyName {
Type,
ResolvedBaseConstructorType,
DeclaredType,
ResolvedReturnType
}
export const enum CheckMode {
Normal = 0,
SkipContextSensitive = 1,
Inferential = 2
}
export type TypeSystemEntity = Symbol | Type | Signature;
export interface ExportCollisionTracker {
specifierText: string;
exportsWithDuplicate: ExportDeclaration[];
}
export type ExportCollisionTrackerTable = UnderscoreEscapedMap;
export interface TypeSet extends Array {
containsAny?: boolean;
containsUndefined?: boolean;
containsNull?: boolean;
containsNever?: boolean;
containsNonWideningType?: boolean;
containsString?: boolean;
containsNumber?: boolean;
containsStringOrNumberLiteral?: boolean;
containsObjectType?: boolean;
containsEmptyObject?: boolean;
unionIndex?: number;
}
export type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void;
export class TypeCheckerImpl {
constructor(host: TypeCheckerHost, produceDiagnostics: boolean) {
let anyThis: any = this;
for (let key in anyThis) {
let v = anyThis[key];
if (v instanceof Function) {
anyThis[key] = v.bind(this);
}
}
let __conv_self__ = this;
this.host = host;
this.produceDiagnostics = produceDiagnostics;
this.Symbol = objectAllocator.getSymbolConstructor();
this.Type = objectAllocator.getTypeConstructor();
this.Signature = objectAllocator.getSignatureConstructor();
this.typeCount = 0;
this.symbolCount = 0;
this.enumCount = 0;
this.symbolInstantiationDepth = 0;
this.emptySymbols = createSymbolTable();
this.compilerOptions = host.getCompilerOptions();
this.languageVersion = getEmitScriptTarget(__conv_self__.compilerOptions);
this.modulekind = getEmitModuleKind(__conv_self__.compilerOptions);
this.noUnusedIdentifiers = !!__conv_self__.compilerOptions.noUnusedLocals || !!__conv_self__.compilerOptions.noUnusedParameters;
this.allowSyntheticDefaultImports = typeof __conv_self__.compilerOptions.allowSyntheticDefaultImports !== "undefined" ? __conv_self__.compilerOptions.allowSyntheticDefaultImports : __conv_self__.modulekind === ModuleKind.System;
this.strictNullChecks = __conv_self__.compilerOptions.strictNullChecks === undefined ? __conv_self__.compilerOptions.strict : __conv_self__.compilerOptions.strictNullChecks;
this.noImplicitAny = __conv_self__.compilerOptions.noImplicitAny === undefined ? __conv_self__.compilerOptions.strict : __conv_self__.compilerOptions.noImplicitAny;
this.noImplicitThis = __conv_self__.compilerOptions.noImplicitThis === undefined ? __conv_self__.compilerOptions.strict : __conv_self__.compilerOptions.noImplicitThis;
this.emitResolver = __conv_self__.createResolver();
this.nodeBuilder = __conv_self__.createNodeBuilder();
this.undefinedSymbol = __conv_self__.createSymbol(SymbolFlags.Property, ("undefined" as __String));
this.undefinedSymbol.declarations = [];
this.argumentsSymbol = __conv_self__.createSymbol(SymbolFlags.Property, ("arguments" as __String));
this.tupleTypes = [];
this.unionTypes = createMap();
this.intersectionTypes = createMap();
this.literalTypes = createMap();
this.indexedAccessTypes = createMap();
this.evolvingArrayTypes = [];
this.unknownSymbol = __conv_self__.createSymbol(SymbolFlags.Property, ("unknown" as __String));
this.resolvingSymbol = __conv_self__.createSymbol(0, InternalSymbolName.Resolving);
this.checker = this.createTypeChecker(host);
this.anyType = __conv_self__.createIntrinsicType(TypeFlags.Any, "any");
this.autoType = __conv_self__.createIntrinsicType(TypeFlags.Any, "any");
this.unknownType = __conv_self__.createIntrinsicType(TypeFlags.Any, "unknown");
this.undefinedType = __conv_self__.createIntrinsicType(TypeFlags.Undefined, "undefined");
this.undefinedWideningType = __conv_self__.strictNullChecks ? __conv_self__.undefinedType : __conv_self__.createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined");
this.nullType = __conv_self__.createIntrinsicType(TypeFlags.Null, "null");
this.nullWideningType = __conv_self__.strictNullChecks ? __conv_self__.nullType : __conv_self__.createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsWideningType, "null");
this.stringType = __conv_self__.createIntrinsicType(TypeFlags.String, "string");
this.numberType = __conv_self__.createIntrinsicType(TypeFlags.Number, "number");
this.trueType = __conv_self__.createIntrinsicType(TypeFlags.BooleanLiteral, "true");
this.falseType = __conv_self__.createIntrinsicType(TypeFlags.BooleanLiteral, "false");
this.booleanType = __conv_self__.createBooleanType([__conv_self__.trueType, __conv_self__.falseType]);
this.esSymbolType = __conv_self__.createIntrinsicType(TypeFlags.ESSymbol, "symbol");
this.voidType = __conv_self__.createIntrinsicType(TypeFlags.Void, "void");
this.neverType = __conv_self__.createIntrinsicType(TypeFlags.Never, "never");
this.silentNeverType = __conv_self__.createIntrinsicType(TypeFlags.Never, "never");
this.nonPrimitiveType = __conv_self__.createIntrinsicType(TypeFlags.NonPrimitive, "object");
this.emptyObjectType = __conv_self__.createAnonymousType(undefined, __conv_self__.emptySymbols, emptyArray, emptyArray, undefined, undefined);
this.emptyTypeLiteralSymbol = __conv_self__.createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type);
this.emptyTypeLiteralSymbol.members = createSymbolTable();
this.emptyTypeLiteralType = __conv_self__.createAnonymousType(__conv_self__.emptyTypeLiteralSymbol, __conv_self__.emptySymbols, emptyArray, emptyArray, undefined, undefined);
this.emptyGenericType = (__conv_self__.createAnonymousType(undefined, __conv_self__.emptySymbols, emptyArray, emptyArray, undefined, undefined));
this.emptyGenericType.instantiations = createMap();
this.anyFunctionType = __conv_self__.createAnonymousType(undefined, __conv_self__.emptySymbols, emptyArray, emptyArray, undefined, undefined);
// The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated
// in getPropagatingFlagsOfTypes, and it is checked in inferFromTypes.
this.anyFunctionType.flags |= TypeFlags.ContainsAnyFunctionType;
this.noConstraintType = __conv_self__.createAnonymousType(undefined, __conv_self__.emptySymbols, emptyArray, emptyArray, undefined, undefined);
this.circularConstraintType = __conv_self__.createAnonymousType(undefined, __conv_self__.emptySymbols, emptyArray, emptyArray, undefined, undefined);
this.anySignature = __conv_self__.createSignature(undefined, undefined, undefined, emptyArray, __conv_self__.anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
this.unknownSignature = __conv_self__.createSignature(undefined, undefined, undefined, emptyArray, __conv_self__.unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
this.resolvingSignature = __conv_self__.createSignature(undefined, undefined, undefined, emptyArray, __conv_self__.anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
this.silentNeverSignature = __conv_self__.createSignature(undefined, undefined, undefined, emptyArray, __conv_self__.silentNeverType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
this.enumNumberIndexInfo = __conv_self__.createIndexInfo(__conv_self__.stringType, /*isReadonly*/ true);
this.jsObjectLiteralIndexInfo = __conv_self__.createIndexInfo(__conv_self__.anyType, /*isReadonly*/ false);
this.globals = createSymbolTable();
this.flowLoopStart = 0;
this.flowLoopCount = 0;
this.visitedFlowCount = 0;
this.emptyStringType = __conv_self__.getLiteralType("");
this.zeroType = __conv_self__.getLiteralType(0);
this.resolutionTargets = [];
this.resolutionResults = [];
this.resolutionPropertyNames = [];
this.suggestionCount = 0;
this.maximumSuggestionCount = 10;
this.mergedSymbols = [];
this.symbolLinks = [];
this.nodeLinks = [];
this.flowLoopCaches = [];
this.flowLoopNodes = [];
this.flowLoopKeys = [];
this.flowLoopTypes = [];
this.visitedFlowNodes = [];
this.visitedFlowTypes = [];
this.potentialThisCollisions = [];
this.potentialNewTargetCollisions = [];
this.awaitedTypeStack = [];
this.diagnostics = createDiagnosticCollection();
this.typeofEQFacts = createMapFromTemplate({
"string": TypeFacts.TypeofEQString,
"number": TypeFacts.TypeofEQNumber,
"boolean": TypeFacts.TypeofEQBoolean,
"symbol": TypeFacts.TypeofEQSymbol,
"undefined": TypeFacts.EQUndefined,
"object": TypeFacts.TypeofEQObject,
"function": TypeFacts.TypeofEQFunction
});
this.typeofNEFacts = createMapFromTemplate({
"string": TypeFacts.TypeofNEString,
"number": TypeFacts.TypeofNENumber,
"boolean": TypeFacts.TypeofNEBoolean,
"symbol": TypeFacts.TypeofNESymbol,
"undefined": TypeFacts.NEUndefined,
"object": TypeFacts.TypeofNEObject,
"function": TypeFacts.TypeofNEFunction
});
this.typeofTypesByName = createMapFromTemplate({
"string": __conv_self__.stringType,
"number": __conv_self__.numberType,
"boolean": __conv_self__.booleanType,
"symbol": __conv_self__.esSymbolType,
"undefined": __conv_self__.undefinedType
});
this.typeofType = __conv_self__.createTypeofType();
this._hasComputedJsxElementPropertiesName = false;
this._hasComputedJsxElementChildrenPropertyName = false;
this.jsxTypes = createUnderscoreEscapedMap();
this.JsxNames = {
JSX: "JSX" as __String,
IntrinsicElements: "IntrinsicElements" as __String,
ElementClass: "ElementClass" as __String,
ElementAttributesPropertyNameContainer: "ElementAttributesProperty" as __String,
ElementChildrenAttributeNameContainer: "ElementChildrenAttribute" as __String,
Element: "Element" as __String,
IntrinsicAttributes: "IntrinsicAttributes" as __String,
IntrinsicClassAttributes: "IntrinsicClassAttributes" as __String
};
this.subtypeRelation = createMap();
this.assignableRelation = createMap();
this.comparableRelation = createMap();
this.identityRelation = createMap();
this.enumRelation = createMap();
// This is for caching the result of getSymbolDisplayBuilder. Do not access directly.
this.builtinGlobals = createSymbolTable();
this.builtinGlobals.set(this.undefinedSymbol.escapedName, this.undefinedSymbol);
/** Things we lazy load from the JSX namespace */
this.jsxTypes = createUnderscoreEscapedMap();
this.checker = this.createTypeChecker(host);
this.initializeTypeChecker();
}
private createTypeChecker(host: TypeCheckerHost): TypeChecker {
const __conv_self__ = this;
const checkerObj: TypeChecker = {
getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + __conv_self__.symbolCount,
getTypeCount: () => __conv_self__.typeCount,
isUndefinedSymbol: symbol => symbol === __conv_self__.undefinedSymbol,
isArgumentsSymbol: symbol => symbol === __conv_self__.argumentsSymbol,
isUnknownSymbol: symbol => symbol === __conv_self__.unknownSymbol,
getMergedSymbol: this.getMergedSymbol,
getDiagnostics: this.getDiagnostics,
getGlobalDiagnostics: this.getGlobalDiagnostics,
getTypeOfSymbolAtLocation: (symbol, location) => {
location = getParseTreeNode(location);
return location ? __conv_self__.getTypeOfSymbolAtLocation(symbol, location) : __conv_self__.unknownType;
},
getSymbolsOfParameterPropertyDeclaration: (parameter, parameterName) => {
parameter = getParseTreeNode(parameter, isParameter);
Debug.assert(parameter !== undefined, "Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node.");
return __conv_self__.getSymbolsOfParameterPropertyDeclaration(parameter, escapeLeadingUnderscores(parameterName));
},
getDeclaredTypeOfSymbol: this.getDeclaredTypeOfSymbol,
getPropertiesOfType: this.getPropertiesOfType,
getPropertyOfType: (type, name) => __conv_self__.getPropertyOfType(type, escapeLeadingUnderscores(name)),
getIndexInfoOfType: this.getIndexInfoOfType,
getSignaturesOfType: this.getSignaturesOfType,
getIndexTypeOfType: this.getIndexTypeOfType,
getBaseTypes: this.getBaseTypes,
getBaseTypeOfLiteralType: this.getBaseTypeOfLiteralType,
getWidenedType: this.getWidenedType,
getTypeFromTypeNode: node => {
node = getParseTreeNode(node, isTypeNode);
return node ? __conv_self__.getTypeFromTypeNode(node) : __conv_self__.unknownType;
},
getParameterType: this.getTypeAtPosition,
getReturnTypeOfSignature: this.getReturnTypeOfSignature,
getNullableType: this.getNullableType,
getNonNullableType: this.getNonNullableType,
typeToTypeNode: this.nodeBuilder.typeToTypeNode,
indexInfoToIndexSignatureDeclaration: this.nodeBuilder.indexInfoToIndexSignatureDeclaration,
signatureToSignatureDeclaration: this.nodeBuilder.signatureToSignatureDeclaration,
getSymbolsInScope: (location, meaning) => {
location = getParseTreeNode(location);
return location ? __conv_self__.getSymbolsInScope(location, meaning) : [];
},
getSymbolAtLocation: node => {
node = getParseTreeNode(node);
return node ? __conv_self__.getSymbolAtLocation(node) : undefined;
},
getShorthandAssignmentValueSymbol: node => {
node = getParseTreeNode(node);
return node ? __conv_self__.getShorthandAssignmentValueSymbol(node) : undefined;
},
getExportSpecifierLocalTargetSymbol: node => {
node = getParseTreeNode(node, isExportSpecifier);
return node ? __conv_self__.getExportSpecifierLocalTargetSymbol(node) : undefined;
},
getTypeAtLocation: node => {
node = getParseTreeNode(node);
return node ? __conv_self__.getTypeOfNode(node) : __conv_self__.unknownType;
},
getPropertySymbolOfDestructuringAssignment: location => {
location = getParseTreeNode(location, isIdentifier);
return location ? __conv_self__.getPropertySymbolOfDestructuringAssignment(location) : undefined;
},
signatureToString: (signature, enclosingDeclaration?, flags?, kind?) => {
return __conv_self__.signatureToString(signature, getParseTreeNode(enclosingDeclaration), flags, kind);
},
typeToString: (type, enclosingDeclaration?, flags?) => {
return __conv_self__.typeToString(type, getParseTreeNode(enclosingDeclaration), flags);
},
getSymbolDisplayBuilder: this.getSymbolDisplayBuilder,
symbolToString: (symbol, enclosingDeclaration?, meaning?) => {
return __conv_self__.symbolToString(symbol, getParseTreeNode(enclosingDeclaration), meaning);
},
getAugmentedPropertiesOfType: this.getAugmentedPropertiesOfType,
getRootSymbols: this.getRootSymbols,
getContextualType: node => {
node = getParseTreeNode(node, isExpression);
return node ? __conv_self__.getContextualType(node) : undefined;
},
getFullyQualifiedName: this.getFullyQualifiedName,
getResolvedSignature: (node, candidatesOutArray, theArgumentCount) => {
node = getParseTreeNode(node, isCallLikeExpression);
__conv_self__.apparentArgumentCount = theArgumentCount;
const res = node ? __conv_self__.getResolvedSignature(node, candidatesOutArray) : undefined;
__conv_self__.apparentArgumentCount = undefined;
return res;
},
getConstantValue: node => {
node = getParseTreeNode(node, __conv_self__.canHaveConstantValue);
return node ? __conv_self__.getConstantValue(node) : undefined;
},
isValidPropertyAccess: (node, propertyName) => {
node = getParseTreeNode(node, isPropertyAccessOrQualifiedName);
return node ? __conv_self__.isValidPropertyAccess(node, escapeLeadingUnderscores(propertyName)) : false;
},
getSignatureFromDeclaration: declaration => {
declaration = getParseTreeNode(declaration, isFunctionLike);
return declaration ? __conv_self__.getSignatureFromDeclaration(declaration) : undefined;
},
isImplementationOfOverload: node => {
const parsed = getParseTreeNode(node, isFunctionLike);
return parsed ? __conv_self__.isImplementationOfOverload(parsed) : undefined;
},
getImmediateAliasedSymbol: symbol => {
Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here.");
const links = __conv_self__.getSymbolLinks(symbol);
if (!links.immediateTarget) {
const node = __conv_self__.getDeclarationOfAliasSymbol(symbol);
Debug.assert(!!node);
links.immediateTarget = __conv_self__.getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true);
}
return links.immediateTarget;
},
getAliasedSymbol: this.resolveAlias,
getEmitResolver: this.getEmitResolver,
getExportsOfModule: this.getExportsOfModuleAsArray,
getExportsAndPropertiesOfModule: this.getExportsAndPropertiesOfModule,
getAmbientModules: this.getAmbientModules,
getAllAttributesTypeFromJsxOpeningLikeElement: node => {
node = getParseTreeNode(node, isJsxOpeningLikeElement);
return node ? __conv_self__.getAllAttributesTypeFromJsxOpeningLikeElement(node) : undefined;
},
getJsxIntrinsicTagNames: this.getJsxIntrinsicTagNames,
isOptionalParameter: node => {
node = getParseTreeNode(node, isParameter);
return node ? __conv_self__.isOptionalParameter(node) : false;
},
tryGetMemberInModuleExports: (name, symbol) => __conv_self__.tryGetMemberInModuleExports(escapeLeadingUnderscores(name), symbol),
tryGetMemberInModuleExportsAndProperties: (name, symbol) => __conv_self__.tryGetMemberInModuleExportsAndProperties(escapeLeadingUnderscores(name), symbol),
tryFindAmbientModuleWithoutAugmentations: moduleName => {
// we deliberately exclude augmentations
// since we are only interested in declarations of the module itself
return __conv_self__.tryFindAmbientModule(moduleName, /*withAugmentations*/ false);
},
getApparentType: this.getApparentType,
getAllPossiblePropertiesOfType: this.getAllPossiblePropertiesOfType,
getSuggestionForNonexistentProperty: (node, type) => unescapeLeadingUnderscores(__conv_self__.getSuggestionForNonexistentProperty(node, type)),
getSuggestionForNonexistentSymbol: (location, name, meaning) => unescapeLeadingUnderscores(__conv_self__.getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning)),
getBaseConstraintOfType: this.getBaseConstraintOfType,
resolveName: (name, location, meaning) => {
return __conv_self__.resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
},
getJsxNamespace: () => unescapeLeadingUnderscores(__conv_self__.getJsxNamespace()),
//advancedChecker: this,
};
const chAny: any = checkerObj;
for (let key in chAny) {
const val: any = chAny[key];
if (val instanceof Function) {
chAny[key] = val.bind(this);
}
}
return checkerObj;
}
public checker: TypeChecker;
public host: TypeCheckerHost;
public produceDiagnostics: boolean;
// Cancellation that controls whether or not we can cancel in the middle of type checking.
// In general cancelling is *not* safe for the type checker. We might be in the middle of
// computing something, and we will leave our internals in an inconsistent state. Callers
// who set the cancellation token should catch if a cancellation exception occurs, and
// should throw away and create a new TypeChecker.
//
// Currently we only support setting the cancellation token when getting diagnostics. This
// is because diagnostics can be quite expensive, and we want to allow hosts to bail out if
// they no longer need the information (for example, if the user started editing again).
public cancellationToken: CancellationToken;
public requestedExternalEmitHelpers: ExternalEmitHelpers;
public externalHelpersModule: Symbol;
public Symbol: new (flags: SymbolFlags, name: __String) => Symbol;
public Type: new (checker: TypeChecker, flags: TypeFlags) => Type;
public Signature: new (checker: TypeChecker) => Signature;
public typeCount: number;
public symbolCount: number;
public enumCount: number;
public symbolInstantiationDepth: number;
public emptySymbols: SymbolTable;
public compilerOptions: CompilerOptions;
public languageVersion: ScriptTarget;
public modulekind: ModuleKind;
public noUnusedIdentifiers: boolean;
public allowSyntheticDefaultImports: boolean;
public strictNullChecks: boolean;
public noImplicitAny: boolean;
public noImplicitThis: boolean;
public emitResolver: EmitResolver;
public nodeBuilder = (false as true) && this.createNodeBuilder();
public undefinedSymbol = (false as true) && this.createSymbol(SymbolFlags.Property, ("undefined" as __String));
public argumentsSymbol = (false as true) && this.createSymbol(SymbolFlags.Property, ("arguments" as __String));
/** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */
public apparentArgumentCount: number | undefined;
// for public members that accept a Node or one of its subtypes, we must guard against
// synthetic nodes created during transformations by calling `getParseTreeNode`.
// for most of these, we perform the guard only on `checker` to avoid any possible
// extra cost of calling `getParseTreeNode` when calling these functions from inside the
// checker.
public tupleTypes: GenericType[] = (false as true) && [];
public unionTypes = (false as true) && createMap();
public intersectionTypes = (false as true) && createMap();
public literalTypes = (false as true) && createMap();
public indexedAccessTypes = (false as true) && createMap();
public evolvingArrayTypes: EvolvingArrayType[] = (false as true) && [];
public unknownSymbol = (false as true) && this.createSymbol(SymbolFlags.Property, ("unknown" as __String));
public resolvingSymbol = (false as true) && this.createSymbol(0, InternalSymbolName.Resolving);
public anyType = (false as true) && this.createIntrinsicType(TypeFlags.Any, "any");
public autoType = (false as true) && this.createIntrinsicType(TypeFlags.Any, "any");
public unknownType = (false as true) && this.createIntrinsicType(TypeFlags.Any, "unknown");
public undefinedType = (false as true) && this.createIntrinsicType(TypeFlags.Undefined, "undefined");
public undefinedWideningType = (false as true) && (this.strictNullChecks ? this.undefinedType : this.createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined"));
public nullType = (false as true) && this.createIntrinsicType(TypeFlags.Null, "null");
public nullWideningType = (false as true) && (this.strictNullChecks ? this.nullType : this.createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsWideningType, "null"));
public stringType = (false as true) && this.createIntrinsicType(TypeFlags.String, "string");
public numberType = (false as true) && this.createIntrinsicType(TypeFlags.Number, "number");
public trueType = (false as true) && this.createIntrinsicType(TypeFlags.BooleanLiteral, "true");
public falseType = (false as true) && this.createIntrinsicType(TypeFlags.BooleanLiteral, "false");
public booleanType = (false as true) && this.createBooleanType([this.trueType, this.falseType]);
public esSymbolType = (false as true) && this.createIntrinsicType(TypeFlags.ESSymbol, "symbol");
public voidType = (false as true) && this.createIntrinsicType(TypeFlags.Void, "void");
public neverType = (false as true) && this.createIntrinsicType(TypeFlags.Never, "never");
public silentNeverType = (false as true) && this.createIntrinsicType(TypeFlags.Never, "never");
public nonPrimitiveType = (false as true) && this.createIntrinsicType(TypeFlags.NonPrimitive, "object");
public emptyObjectType = (false as true) && this.createAnonymousType(undefined, this.emptySymbols, emptyArray, emptyArray, undefined, undefined);
public emptyTypeLiteralSymbol = (false as true) && this.createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type);
public emptyTypeLiteralType = (false as true) && this.createAnonymousType(this.emptyTypeLiteralSymbol, this.emptySymbols, emptyArray, emptyArray, undefined, undefined);
public emptyGenericType = (false as true) && (this.createAnonymousType(undefined, this.emptySymbols, emptyArray, emptyArray, undefined, undefined));
public anyFunctionType = (false as true) && this.createAnonymousType(undefined, this.emptySymbols, emptyArray, emptyArray, undefined, undefined);
// The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated
// in getPropagatingFlagsOfTypes, and it is checked in inferFromTypes.
public noConstraintType = (false as true) && this.createAnonymousType(undefined, this.emptySymbols, emptyArray, emptyArray, undefined, undefined);
public circularConstraintType = (false as true) && this.createAnonymousType(undefined, this.emptySymbols, emptyArray, emptyArray, undefined, undefined);
public anySignature = (false as true) && this.createSignature(undefined, undefined, undefined, emptyArray, this.anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
public unknownSignature = (false as true) && this.createSignature(undefined, undefined, undefined, emptyArray, this.unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
public resolvingSignature = (false as true) && this.createSignature(undefined, undefined, undefined, emptyArray, this.anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
public silentNeverSignature = (false as true) && this.createSignature(undefined, undefined, undefined, emptyArray, this.silentNeverType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
public enumNumberIndexInfo = (false as true) && this.createIndexInfo(this.stringType, /*isReadonly*/ true);
public jsObjectLiteralIndexInfo = (false as true) && this.createIndexInfo(this.anyType, /*isReadonly*/ false);
public globals = (false as true) && createSymbolTable();
/**
* List of every ambient module with a "*" wildcard.
* Unlike other ambient modules, these can't be stored in `globals` because symbol tables only deal with exact matches.
* This is only used if there is no exact match.
*/
public patternAmbientModules: PatternAmbientModule[];
public globalObjectType: ObjectType;
public globalFunctionType: ObjectType;
public globalArrayType: GenericType;
public globalReadonlyArrayType: GenericType;
public globalStringType: ObjectType;
public globalNumberType: ObjectType;
public globalBooleanType: ObjectType;
public globalRegExpType: ObjectType;
public globalThisType: GenericType;
public anyArrayType: Type;
public autoArrayType: Type;
public anyReadonlyArrayType: Type;
// The library files are only loaded when the feature is used.
// This allows users to just specify library files they want to used through --lib
// and they will not get an error from not having unrelated library files
public deferredGlobalESSymbolConstructorSymbol: Symbol;
public deferredGlobalESSymbolType: ObjectType;
public deferredGlobalTypedPropertyDescriptorType: GenericType;
public deferredGlobalPromiseType: GenericType;
public deferredGlobalPromiseConstructorSymbol: Symbol;
public deferredGlobalPromiseConstructorLikeType: ObjectType;
public deferredGlobalIterableType: GenericType;
public deferredGlobalIteratorType: GenericType;
public deferredGlobalIterableIteratorType: GenericType;
public deferredGlobalAsyncIterableType: GenericType;
public deferredGlobalAsyncIteratorType: GenericType;
public deferredGlobalAsyncIterableIteratorType: GenericType;
public deferredGlobalTemplateStringsArrayType: ObjectType;
public deferredJsxElementClassType: Type;
public deferredJsxElementType: Type;
public deferredJsxStatelessElementType: Type;
public deferredNodes: Node[];
public deferredUnusedIdentifierNodes: Node[];
public flowLoopStart = (false as true) && 0;
public flowLoopCount = (false as true) && 0;
public visitedFlowCount = (false as true) && 0;
public emptyStringType = (false as true) && this.getLiteralType("");
public zeroType = (false as true) && this.getLiteralType(0);
public resolutionTargets: TypeSystemEntity[] = (false as true) && [];
public resolutionResults: boolean[] = (false as true) && [];
public resolutionPropertyNames: TypeSystemPropertyName[] = (false as true) && [];
public suggestionCount = (false as true) && 0;
public maximumSuggestionCount = (false as true) && 10;
public mergedSymbols: Symbol[] = (false as true) && [];
public symbolLinks: SymbolLinks[] = (false as true) && [];
public nodeLinks: NodeLinks[] = (false as true) && [];
public flowLoopCaches: Map[] = (false as true) && [];
public flowLoopNodes: FlowNode[] = (false as true) && [];
public flowLoopKeys: string[] = (false as true) && [];
public flowLoopTypes: Type[][] = (false as true) && [];
public visitedFlowNodes: FlowNode[] = (false as true) && [];
public visitedFlowTypes: FlowType[] = (false as true) && [];
public potentialThisCollisions: Node[] = (false as true) && [];
public potentialNewTargetCollisions: Node[] = (false as true) && [];
public awaitedTypeStack: number[] = (false as true) && [];
public diagnostics = (false as true) && createDiagnosticCollection();
public typeofEQFacts = (false as true) && createMapFromTemplate({
"string": TypeFacts.TypeofEQString,
"number": TypeFacts.TypeofEQNumber,
"boolean": TypeFacts.TypeofEQBoolean,
"symbol": TypeFacts.TypeofEQSymbol,
"undefined": TypeFacts.EQUndefined,
"object": TypeFacts.TypeofEQObject,
"function": TypeFacts.TypeofEQFunction
});
public typeofNEFacts = (false as true) && createMapFromTemplate({
"string": TypeFacts.TypeofNEString,
"number": TypeFacts.TypeofNENumber,
"boolean": TypeFacts.TypeofNEBoolean,
"symbol": TypeFacts.TypeofNESymbol,
"undefined": TypeFacts.NEUndefined,
"object": TypeFacts.TypeofNEObject,
"function": TypeFacts.TypeofNEFunction
});
public typeofTypesByName = (false as true) && createMapFromTemplate({
"string": this.stringType,
"number": this.numberType,
"boolean": this.booleanType,
"symbol": this.esSymbolType,
"undefined": this.undefinedType
});
public typeofType = (false as true) && this.createTypeofType();
public _jsxNamespace: __String;
public _jsxFactoryEntity: EntityName;
public _jsxElementPropertiesName: __String;
public _hasComputedJsxElementPropertiesName: boolean;
public _jsxElementChildrenPropertyName: __String;
public _hasComputedJsxElementChildrenPropertyName: boolean;
/** Things we lazy load from the JSX namespace */
public jsxTypes = (false as true) && createUnderscoreEscapedMap();
public JsxNames = (false as true) && {
JSX: "JSX" as __String,
IntrinsicElements: "IntrinsicElements" as __String,
ElementClass: "ElementClass" as __String,
ElementAttributesPropertyNameContainer: "ElementAttributesProperty" as __String,
ElementChildrenAttributeNameContainer: "ElementChildrenAttribute" as __String,
Element: "Element" as __String,
IntrinsicAttributes: "IntrinsicAttributes" as __String,
IntrinsicClassAttributes: "IntrinsicClassAttributes" as __String
};
public subtypeRelation = (false as true) && createMap();
public assignableRelation = (false as true) && createMap();
public comparableRelation = (false as true) && createMap();
public identityRelation = (false as true) && createMap();
public enumRelation = (false as true) && createMap();
// This is for caching the result of getSymbolDisplayBuilder. Do not access directly.
public _displayBuilder: SymbolDisplayBuilder;
public builtinGlobals = (false as true) && createSymbolTable();
public getJsxNamespace(): __String {
if (!this._jsxNamespace) {
this._jsxNamespace = ("React" as __String);
if (this.compilerOptions.jsxFactory) {
this._jsxFactoryEntity = parseIsolatedEntityName(this.compilerOptions.jsxFactory, this.languageVersion);
if (this._jsxFactoryEntity) {
this._jsxNamespace = this.getFirstIdentifier(this._jsxFactoryEntity).escapedText;
}
}
else if (this.compilerOptions.reactNamespace) {
this._jsxNamespace = escapeLeadingUnderscores(this.compilerOptions.reactNamespace);
}
}
return this._jsxNamespace;
}
public getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) {
// Ensure we have all the type information in place for this file so that all the
// emitter questions of this resolver will return the right information.
this.getDiagnostics(sourceFile, cancellationToken);
return this.emitResolver;
}
public error(location: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): void {
const diagnostic = location
? createDiagnosticForNode(location, message, arg0, arg1, arg2)
: createCompilerDiagnostic(message, arg0, arg1, arg2);
this.diagnostics.add(diagnostic);
}
public createSymbol(flags: SymbolFlags, name: __String) {
this.symbolCount++;
const symbol = (new this.Symbol(flags | SymbolFlags.Transient, name));
symbol.checkFlags = 0;
return symbol;
}
public isTransientSymbol(symbol: Symbol): symbol is TransientSymbol {
return (symbol.flags & SymbolFlags.Transient) !== 0;
}
public getExcludedSymbolFlags(flags: SymbolFlags): SymbolFlags {
let result: SymbolFlags = 0;
if (flags & SymbolFlags.BlockScopedVariable)
result |= SymbolFlags.BlockScopedVariableExcludes;
if (flags & SymbolFlags.FunctionScopedVariable)
result |= SymbolFlags.FunctionScopedVariableExcludes;
if (flags & SymbolFlags.Property)
result |= SymbolFlags.PropertyExcludes;
if (flags & SymbolFlags.EnumMember)
result |= SymbolFlags.EnumMemberExcludes;
if (flags & SymbolFlags.Function)
result |= SymbolFlags.FunctionExcludes;
if (flags & SymbolFlags.Class)
result |= SymbolFlags.ClassExcludes;
if (flags & SymbolFlags.Interface)
result |= SymbolFlags.InterfaceExcludes;
if (flags & SymbolFlags.RegularEnum)
result |= SymbolFlags.RegularEnumExcludes;
if (flags & SymbolFlags.ConstEnum)
result |= SymbolFlags.ConstEnumExcludes;
if (flags & SymbolFlags.ValueModule)
result |= SymbolFlags.ValueModuleExcludes;
if (flags & SymbolFlags.Method)
result |= SymbolFlags.MethodExcludes;
if (flags & SymbolFlags.GetAccessor)
result |= SymbolFlags.GetAccessorExcludes;
if (flags & SymbolFlags.SetAccessor)
result |= SymbolFlags.SetAccessorExcludes;
if (flags & SymbolFlags.TypeParameter)
result |= SymbolFlags.TypeParameterExcludes;
if (flags & SymbolFlags.TypeAlias)
result |= SymbolFlags.TypeAliasExcludes;
if (flags & SymbolFlags.Alias)
result |= SymbolFlags.AliasExcludes;
return result;
}
public recordMergedSymbol(target: Symbol, source: Symbol) {
if (!source.mergeId) {
source.mergeId = nextMergeId;
nextMergeId++;
}
this.mergedSymbols[source.mergeId] = target;
}
public cloneSymbol(symbol: Symbol): Symbol {
const result = this.createSymbol(symbol.flags, symbol.escapedName);
result.declarations = symbol.declarations.slice(0);
result.parent = symbol.parent;
if (symbol.valueDeclaration)
result.valueDeclaration = symbol.valueDeclaration;
if (symbol.constEnumOnlyModule)
result.constEnumOnlyModule = true;
if (symbol.members)
result.members = cloneMap(symbol.members);
if (symbol.exports)
result.exports = cloneMap(symbol.exports);
this.recordMergedSymbol(result, symbol);
return result;
}
public mergeSymbol(target: Symbol, source: Symbol) {
const __conv_self__ = this;
if (!(target.flags & this.getExcludedSymbolFlags(source.flags))) {
if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) {
// reset flag when merging instantiated module into value module that has only const enums
target.constEnumOnlyModule = false;
}
target.flags |= source.flags;
if (source.valueDeclaration &&
(!target.valueDeclaration ||
(target.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && source.valueDeclaration.kind !== SyntaxKind.ModuleDeclaration))) {
// other kinds of value declarations take precedence over modules
target.valueDeclaration = source.valueDeclaration;
}
addRange(target.declarations, source.declarations);
if (source.members) {
if (!target.members)
target.members = createSymbolTable();
this.mergeSymbolTable(target.members, source.members);
}
if (source.exports) {
if (!target.exports)
target.exports = createSymbolTable();
this.mergeSymbolTable(target.exports, source.exports);
}
this.recordMergedSymbol(target, source);
}
else if (target.flags & SymbolFlags.NamespaceModule) {
this.error(getNameOfDeclaration(source.declarations[0]), Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, this.symbolToString(target));
}
else {
const message = target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable
? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0;
forEach(source.declarations, node => {
__conv_self__.error(getNameOfDeclaration(node) || node, message, __conv_self__.symbolToString(source));
});
forEach(target.declarations, node => {
__conv_self__.error(getNameOfDeclaration(node) || node, message, __conv_self__.symbolToString(source));
});
}
}
public mergeSymbolTable(target: SymbolTable, source: SymbolTable) {
const __conv_self__ = this;
source.forEach((sourceSymbol, id) => {
let targetSymbol = target.get(id);
if (!targetSymbol) {
target.set(id, sourceSymbol);
}
else {
if (!(targetSymbol.flags & SymbolFlags.Transient)) {
targetSymbol = __conv_self__.cloneSymbol(targetSymbol);
target.set(id, targetSymbol);
}
__conv_self__.mergeSymbol(targetSymbol, sourceSymbol);
}
});
}
public mergeModuleAugmentation(moduleName: LiteralExpression): void {
const moduleAugmentation = moduleName.parent;
if (moduleAugmentation.symbol.declarations[0] !== moduleAugmentation) {
// this is a combined symbol for multiple augmentations within the same file.
// its symbol already has accumulated information for all declarations
// so we need to add it just once - do the work only for first declaration
Debug.assert(moduleAugmentation.symbol.declarations.length > 1);
return;
}
if (isGlobalScopeAugmentation(moduleAugmentation)) {
this.mergeSymbolTable(this.globals, moduleAugmentation.symbol.exports);
}
else {
// find a module that about to be augmented
// do not validate names of augmentations that are defined in ambient context
const moduleNotFoundError = !isInAmbientContext(moduleName.parent.parent)
? Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found
: undefined;
let mainModule = this.resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError, /*isForAugmentation*/ true);
if (!mainModule) {
return;
}
// obtain item referenced by 'export='
mainModule = this.resolveExternalModuleSymbol(mainModule);
if (mainModule.flags & SymbolFlags.Namespace) {
// if module symbol has already been merged - it is safe to use it.
// otherwise clone it
mainModule = mainModule.flags & SymbolFlags.Transient ? mainModule : this.cloneSymbol(mainModule);
this.mergeSymbol(mainModule, moduleAugmentation.symbol);
}
else {
this.error(moduleName, Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, moduleName.text);
}
}
}
public addToSymbolTable(target: SymbolTable, source: SymbolTable, message: DiagnosticMessage) {
const __conv_self__ = this;
source.forEach((sourceSymbol, id) => {
const targetSymbol = target.get(id);
if (targetSymbol) {
// Error on redeclarations
forEach(targetSymbol.declarations, addDeclarationDiagnostic(unescapeLeadingUnderscores(id), message));
}
else {
target.set(id, sourceSymbol);
}
});
function addDeclarationDiagnostic(id: string, message: DiagnosticMessage) {
return (declaration: Declaration) => __conv_self__.diagnostics.add(createDiagnosticForNode(declaration, message, id));
}
}
public getSymbolLinks(symbol: Symbol): SymbolLinks {
if (symbol.flags & SymbolFlags.Transient)
return symbol;
const id = getSymbolId(symbol);
return this.symbolLinks[id] || (this.symbolLinks[id] = {});
}
public getNodeLinks(node: Node): NodeLinks {
const nodeId = getNodeId(node);
return this.nodeLinks[nodeId] || (this.nodeLinks[nodeId] = { flags: 0 });
}
public getObjectFlags(type: Type): ObjectFlags {
return type.flags & TypeFlags.Object ? (type).objectFlags : 0;
}
public isGlobalSourceFile(node: Node) {
return node.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(node);
}
public getSymbol(symbols: SymbolTable, name: __String, meaning: SymbolFlags): Symbol {
if (meaning) {
const symbol = symbols.get(name);
if (symbol) {
Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
if (symbol.flags & meaning) {
return symbol;
}
if (symbol.flags & SymbolFlags.Alias) {
const target = this.resolveAlias(symbol);
// Unknown symbol means an error occurred in alias resolution, treat it as positive answer to avoid cascading errors
if (target === this.unknownSymbol || target.flags & meaning) {
return symbol;
}
}
}
}
// return undefined if we can't find a symbol.
}
/**
* Get symbols that represent parameter-property-declaration as parameter and as property declaration
* @param parameter a parameterDeclaration node
* @param parameterName a name of the parameter to get the symbols for.
* @return a tuple of two symbols
*/
public getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: __String): [Symbol, Symbol] {
const constructorDeclaration = parameter.parent;
const classDeclaration = parameter.parent.parent;
const parameterSymbol = this.getSymbol(constructorDeclaration.locals, parameterName, SymbolFlags.Value);
const propertySymbol = this.getSymbol(classDeclaration.symbol.members, parameterName, SymbolFlags.Value);
if (parameterSymbol && propertySymbol) {
return [parameterSymbol, propertySymbol];
}
Debug.fail("There should exist two symbols, one as property declaration and one as parameter declaration");
}
public isBlockScopedNameDeclaredBeforeUse(declaration: Declaration, usage: Node): boolean {
const __conv_self__ = this;
const declarationFile = getSourceFileOfNode(declaration);
const useFile = getSourceFileOfNode(usage);
if (declarationFile !== useFile) {
if ((this.modulekind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) ||
(!this.compilerOptions.outFile && !this.compilerOptions.out) ||
this.isInTypeQuery(usage) ||
isInAmbientContext(declaration)) {
// nodes are in different files and order cannot be determined
return true;
}
// declaration is after usage
// can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
if (isUsedInFunctionOrInstanceProperty(usage, declaration)) {
return true;
}
const sourceFiles = this.host.getSourceFiles();
return indexOf(sourceFiles, declarationFile) <= indexOf(sourceFiles, useFile);
}
if (declaration.pos <= usage.pos) {
// declaration is before usage
if (declaration.kind === SyntaxKind.BindingElement) {
// still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2])
const errorBindingElement = getAncestor(usage, SyntaxKind.BindingElement) as BindingElement;
if (errorBindingElement) {
return findAncestor(errorBindingElement, isBindingElement) !== findAncestor(declaration, isBindingElement) ||
declaration.pos < errorBindingElement.pos;
}
// or it might be illegal if usage happens before parent variable is declared (eg var [a] = a)
return this.isBlockScopedNameDeclaredBeforeUse((getAncestor(declaration, SyntaxKind.VariableDeclaration) as Declaration), usage);
}
else if (declaration.kind === SyntaxKind.VariableDeclaration) {
// still might be illegal if usage is in the initializer of the variable declaration (eg var a = a)
return !isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration as VariableDeclaration, usage);
}
return true;
}
// declaration is after usage, but it can still be legal if usage is deferred:
// 1. inside an export specifier
// 2. inside a function
// 3. inside an instance property initializer, a reference to a non-instance property
// 4. inside a static property initializer, a reference to a static method in the same class
// or if usage is in a type context:
// 1. inside a type query (typeof in type position)
if (usage.parent.kind === SyntaxKind.ExportSpecifier) {
// export specifiers do not use the variable, they only make it available for use
return true;
}
const container = getEnclosingBlockScopeContainer(declaration);
return this.isInTypeQuery(usage) || isUsedInFunctionOrInstanceProperty(usage, declaration, container);
function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
const container = getEnclosingBlockScopeContainer(declaration);
switch (declaration.parent.parent.kind) {
case SyntaxKind.VariableStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.ForOfStatement:
// variable statement/for/for-of statement case,
// use site should not be inside variable declaration (initializer of declaration or binding element)
if (__conv_self__.isSameScopeDescendentOf(usage, declaration, container)) {
return true;
}
break;
}
// ForIn/ForOf case - use site should not be used in expression part
return isForInOrOfStatement(declaration.parent.parent) && __conv_self__.isSameScopeDescendentOf(usage, declaration.parent.parent.expression, container);
}
function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node, container?: Node): boolean {
return !!findAncestor(usage, current => {
if (current === container) {
return "quit";
}
if (isFunctionLike(current)) {
return true;
}
const initializerOfProperty = current.parent &&
current.parent.kind === SyntaxKind.PropertyDeclaration &&
(current.parent).initializer === current;
if (initializerOfProperty) {
if (hasModifier(current.parent, ModifierFlags.Static)) {
if (declaration.kind === SyntaxKind.MethodDeclaration) {
return true;
}
}
else {
const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !hasModifier(declaration, ModifierFlags.Static);
if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) {
return true;
}
}
}
});
}
}
// Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and
// the nameNotFoundMessage argument is not undefined. Returns the resolved symbol, or undefined if no symbol with
// the given name can be found.
public resolveName(location: Node | undefined, name: __String, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage | undefined, nameArg: __String | Identifier, suggestedNameNotFoundMessage?: DiagnosticMessage): Symbol {
return this.resolveNameHelper(location, name, meaning, nameNotFoundMessage, nameArg, this.getSymbol, suggestedNameNotFoundMessage);
}
public resolveNameHelper(location: Node | undefined, name: __String, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage, nameArg: __String | Identifier, lookup: (symbols: SymbolTable, name: __String, meaning: SymbolFlags) => Symbol, suggestedNameNotFoundMessage?: DiagnosticMessage): Symbol {
const originalLocation = location; // needed for did-you-mean error reporting, which gathers candidates starting from the original location
let result: Symbol;
let lastLocation: Node;
let propertyWithInvalidInitializer: Node;
const errorLocation = location;
let grandparent: Node;
let isInExternalModule = false;
loop: while (location) {
// Locals of a source file are not in scope (because they get merged into the global symbol table)
if (location.locals && !this.isGlobalSourceFile(location)) {
if (result = lookup(location.locals, name, meaning)) {
let useResult = true;
if (isFunctionLike(location) && lastLocation && lastLocation !== (location).body) {
// symbol lookup restrictions for function-like declarations
// - Type parameters of a function are in scope in the entire function declaration, including the parameter
// list and return type. However, local types are only in scope in the function body.
// - parameters are only in the scope of function body
// This restriction does not apply to JSDoc comment types because they are parented
// at a higher level than type parameters would normally be
if (meaning & result.flags & SymbolFlags.Type && lastLocation.kind !== SyntaxKind.JSDocComment) {
useResult = result.flags & SymbolFlags.TypeParameter
? lastLocation === (location).type ||
lastLocation.kind === SyntaxKind.Parameter ||
lastLocation.kind === SyntaxKind.TypeParameter
: false;
}
if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.FunctionScopedVariable) {
// parameters are visible only inside function body, parameter list and return type
// technically for parameter list case here we might mix parameters and variables declared in function,
// however it is detected separately when checking initializers of parameters
// to make sure that they reference no variables declared after them.
useResult =
lastLocation.kind === SyntaxKind.Parameter ||
(lastLocation === (location).type &&
result.valueDeclaration.kind === SyntaxKind.Parameter);
}
}
if (useResult) {
break loop;
}
else {
result = undefined;
}
}
}
switch (location.kind) {
case SyntaxKind.SourceFile:
if (!isExternalOrCommonJsModule(location))
break;
isInExternalModule = true;
// falls through
case SyntaxKind.ModuleDeclaration:
const moduleExports = this.getSymbolOfNode(location).exports;
if (location.kind === SyntaxKind.SourceFile || isAmbientModule(location)) {
// It's an external module. First see if the module has an export default and if the local
// name of that export default matches.
if (result = moduleExports.get("default" as __String)) {
const localSymbol = getLocalSymbolForExportDefault(result);
if (localSymbol && (result.flags & meaning) && localSymbol.escapedName === name) {
break loop;
}
result = undefined;
}
// Because of module/namespace merging, a module's exports are in scope,
// yet we never want to treat an export specifier as putting a member in scope.
// Therefore, if the name we find is purely an export specifier, it is not actually considered in scope.
// Two things to note about this:
// 1. We have to check this without calling getSymbol. The problem with calling getSymbol
// on an export specifier is that it might find the export specifier itself, and try to
// resolve it as an alias. This will cause the checker to consider the export specifier
// a circular alias reference when it might not be.
// 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely*
// an alias. If we used &, we'd be throwing out symbols that have non alias aspects,
// which is not the desired behavior.
const moduleExport = moduleExports.get(name);
if (moduleExport &&
moduleExport.flags === SymbolFlags.Alias &&
getDeclarationOfKind(moduleExport, SyntaxKind.ExportSpecifier)) {
break;
}
}
if (result = lookup(moduleExports, name, meaning & SymbolFlags.ModuleMember)) {
break loop;
}
break;
case SyntaxKind.EnumDeclaration:
if (result = lookup(this.getSymbolOfNode(location).exports, name, meaning & SymbolFlags.EnumMember)) {
break loop;
}
break;
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
// TypeScript 1.0 spec (April 2014): 8.4.1
// Initializer expressions for instance member variables are evaluated in the scope
// of the class constructor body but are not permitted to reference parameters or
// local variables of the constructor. This effectively means that entities from outer scopes
// by the same name as a constructor parameter or local variable are inaccessible
// in initializer expressions for instance member variables.
if (isClassLike(location.parent) && !hasModifier(location, ModifierFlags.Static)) {
const ctor = this.findConstructorDeclaration((location.parent));
if (ctor && ctor.locals) {
if (lookup(ctor.locals, name, meaning & SymbolFlags.Value)) {
// Remember the property node, it will be used later to report appropriate error
propertyWithInvalidInitializer = location;
}
}
}
break;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
if (result = lookup(this.getSymbolOfNode(location).members, name, meaning & SymbolFlags.Type)) {
if (!this.isTypeParameterSymbolDeclaredInContainer(result, location)) {
// ignore type parameters not declared in this container
result = undefined;
break;
}
if (lastLocation && hasModifier(lastLocation, ModifierFlags.Static)) {
// TypeScript 1.0 spec (April 2014): 3.4.1
// The scope of a type parameter extends over the entire declaration with which the type
// parameter list is associated, with the exception of static member declarations in classes.
this.error(errorLocation, Diagnostics.Static_members_cannot_reference_class_type_parameters);
return undefined;
}
break loop;
}
if (location.kind === SyntaxKind.ClassExpression && meaning & SymbolFlags.Class) {
const className = (location).name;
if (className && name === className.escapedText) {
result = location.symbol;
break loop;
}
}
break;
// It is not legal to reference a class's own type parameters from a computed property name that
// belongs to the class. For example:
//
// function foo() { return '' }
// class C { // <-- Class's own type parameter T
// [foo()]() { } // <-- Reference to T from class's own computed property
// }
//
case SyntaxKind.ComputedPropertyName:
grandparent = location.parent.parent;
if (isClassLike(grandparent) || grandparent.kind === SyntaxKind.InterfaceDeclaration) {
// A reference to this grandparent's type parameters would be an error
if (result = lookup(this.getSymbolOfNode(grandparent).members, name, meaning & SymbolFlags.Type)) {
this.error(errorLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type);
return undefined;
}
}
break;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ArrowFunction:
if (meaning & SymbolFlags.Variable && name === "arguments") {
result = this.argumentsSymbol;
break loop;
}
break;
case SyntaxKind.FunctionExpression:
if (meaning & SymbolFlags.Variable && name === "arguments") {
result = this.argumentsSymbol;
break loop;
}
if (meaning & SymbolFlags.Function) {
const functionName = (location).name;
if (functionName && name === functionName.escapedText) {
result = location.symbol;
break loop;
}
}
break;
case SyntaxKind.Decorator:
// Decorators are resolved at the class declaration. Resolving at the parameter
// or member would result in looking up locals in the method.
//
// function y() {}
// class C {
// method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter.
// }
//
if (location.parent && location.parent.kind === SyntaxKind.Parameter) {
location = location.parent;
}
//
// function y() {}
// class C {
// @y method(x, y) {} // <-- decorator y should be resolved at the class declaration, not the method.
// }
//
if (location.parent && isClassElement(location.parent)) {
location = location.parent;
}
break;
}
lastLocation = location;
location = location.parent;
}
// We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`.
// If `result === lastLocation.symbol`, that means that we are somewhere inside `lastLocation` looking up a name, and resolving to `lastLocation` itself.
// That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used.
if (result && nameNotFoundMessage && this.noUnusedIdentifiers && result !== lastLocation.symbol) {
result.isReferenced = true;
}
if (!result) {
result = lookup(this.globals, name, meaning);
}
if (!result) {
if (nameNotFoundMessage) {
if (!errorLocation ||
!this.checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg) &&
!this.checkAndReportErrorForExtendingInterface(errorLocation) &&
!this.checkAndReportErrorForUsingTypeAsNamespace(errorLocation, name, meaning) &&
!this.checkAndReportErrorForUsingTypeAsValue(errorLocation, name, meaning) &&
!this.checkAndReportErrorForUsingNamespaceModuleAsValue(errorLocation, name, meaning)) {
let suggestion: __String | undefined;
if (suggestedNameNotFoundMessage && this.suggestionCount < this.maximumSuggestionCount) {
suggestion = this.getSuggestionForNonexistentSymbol(originalLocation, name, meaning);
if (suggestion) {
this.error(errorLocation, suggestedNameNotFoundMessage, this.diagnosticName(nameArg), unescapeLeadingUnderscores(suggestion));
}
}
if (!suggestion) {
this.error(errorLocation, nameNotFoundMessage, this.diagnosticName(nameArg));
}
this.suggestionCount++;
}
}
return undefined;
}
// Perform extra checks only if error reporting was requested
if (nameNotFoundMessage) {
if (propertyWithInvalidInitializer) {
// We have a match, but the reference occurred within a property initializer and the identifier also binds
// to a local variable in the constructor where the code will be emitted.
const propertyName = (propertyWithInvalidInitializer).name;
this.error(errorLocation, Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, declarationNameToString(propertyName), this.diagnosticName(nameArg));
return undefined;
}
// Only check for block-scoped variable if we have an error location and are looking for the
// name with variable meaning
// For example,
// declare module foo {
// interface bar {}
// }
// const foo/*1*/: foo/*2*/.bar;
// The foo at /*1*/ and /*2*/ will share same symbol with two meanings:
// block-scoped variable and namespace module. However, only when we
// try to resolve name in /*1*/ which is used in variable position,
// we want to check for block-scoped
if (errorLocation &&
(meaning & SymbolFlags.BlockScopedVariable ||
((meaning & SymbolFlags.Class || meaning & SymbolFlags.Enum) && (meaning & SymbolFlags.Value) === SymbolFlags.Value))) {
const exportOrLocalSymbol = this.getExportSymbolOfValueSymbolIfExported(result);
if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable || exportOrLocalSymbol.flags & SymbolFlags.Class || exportOrLocalSymbol.flags & SymbolFlags.Enum) {
this.checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation);
}
}
// If we're in an external module, we can't reference value symbols created from UMD export declarations
if (result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value) {
const decls = result.declarations;
if (decls && decls.length === 1 && decls[0].kind === SyntaxKind.NamespaceExportDeclaration) {
this.error(errorLocation, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, unescapeLeadingUnderscores(name));
}
}
}
return result;
}
public diagnosticName(nameArg: __String | Identifier) {
return typeof nameArg === "string" ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier);
}
public isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
for (const decl of symbol.declarations) {
if (decl.kind === SyntaxKind.TypeParameter && decl.parent === container) {
return true;
}
}
return false;
}
public checkAndReportErrorForMissingPrefix(errorLocation: Node, name: __String, nameArg: __String | Identifier): boolean {
if ((errorLocation.kind === SyntaxKind.Identifier && (this.isTypeReferenceIdentifier((errorLocation))) || this.isInTypeQuery(errorLocation))) {
return false;
}
const container = getThisContainer(errorLocation, /*includeArrowFunctions*/ true);
let location = container;
while (location) {
if (isClassLike(location.parent)) {
const classSymbol = this.getSymbolOfNode(location.parent);
if (!classSymbol) {
break;
}
// Check to see if a static member exists.
const constructorType = this.getTypeOfSymbol(classSymbol);
if (this.getPropertyOfType(constructorType, name)) {
this.error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, this.diagnosticName(nameArg), this.symbolToString(classSymbol));
return true;
}
// No static member is present.
// Check if we're in an instance method and look for a relevant instance member.
if (location === container && !hasModifier(location, ModifierFlags.Static)) {
const instanceType = (this.getDeclaredTypeOfSymbol(classSymbol)).thisType;
if (this.getPropertyOfType(instanceType, name)) {
this.error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, this.diagnosticName(nameArg));
return true;
}
}
}
location = location.parent;
}
return false;
}
public checkAndReportErrorForExtendingInterface(errorLocation: Node): boolean {
const expression = this.getEntityNameForExtendingInterface(errorLocation);
const isError = !!(expression && this.resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true));
if (isError) {
this.error(errorLocation, Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, getTextOfNode(expression));
}
return isError;
}
/**
* Climbs up parents to an ExpressionWithTypeArguments, and returns its expression,
* but returns undefined if that expression is not an EntityNameExpression.
*/
public getEntityNameForExtendingInterface(node: Node): EntityNameExpression | undefined {
switch (node.kind) {
case SyntaxKind.Identifier:
case SyntaxKind.PropertyAccessExpression:
return node.parent ? this.getEntityNameForExtendingInterface(node.parent) : undefined;
case SyntaxKind.ExpressionWithTypeArguments:
Debug.assert(isEntityNameExpression((node).expression));
return (node).expression;
default:
return undefined;
}
}
public checkAndReportErrorForUsingTypeAsNamespace(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean {
if (meaning === SymbolFlags.Namespace) {
const symbol = this.resolveSymbol(this.resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined));
const parent = errorLocation.parent;
if (symbol) {
if (isQualifiedName(parent)) {
Debug.assert(parent.left === errorLocation, "Should only be resolving left side of qualified name as a namespace");
const propName = parent.right.escapedText;
const propType = this.getPropertyOfType(this.getDeclaredTypeOfSymbol(symbol), propName);
if (propType) {
this.error(parent, Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, unescapeLeadingUnderscores(name), unescapeLeadingUnderscores(propName));
return true;
}
}
this.error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_namespace_here, unescapeLeadingUnderscores(name));
return true;
}
}
return false;
}
public checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean {
if (meaning & (SymbolFlags.Value & ~SymbolFlags.NamespaceModule)) {
if (name === "any" || name === "string" || name === "number" || name === "boolean" || name === "never") {
this.error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name));
return true;
}
const symbol = this.resolveSymbol(this.resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined));
if (symbol && !(symbol.flags & SymbolFlags.NamespaceModule)) {
this.error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name));
return true;
}
}
return false;
}
public checkAndReportErrorForUsingNamespaceModuleAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean {
if (meaning & (SymbolFlags.Value & ~SymbolFlags.NamespaceModule & ~SymbolFlags.Type)) {
const symbol = this.resolveSymbol(this.resolveName(errorLocation, name, SymbolFlags.NamespaceModule & ~SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined));
if (symbol) {
this.error(errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_value, unescapeLeadingUnderscores(name));
return true;
}
}
else if (meaning & (SymbolFlags.Type & ~SymbolFlags.NamespaceModule & ~SymbolFlags.Value)) {
const symbol = this.resolveSymbol(this.resolveName(errorLocation, name, SymbolFlags.NamespaceModule & ~SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined));
if (symbol) {
this.error(errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_type, unescapeLeadingUnderscores(name));
return true;
}
}
return false;
}
public checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void {
Debug.assert(!!(result.flags & SymbolFlags.BlockScopedVariable || result.flags & SymbolFlags.Class || result.flags & SymbolFlags.Enum));
// Block-scoped variables cannot be used before their definition
const declaration = forEach(result.declarations, d => isBlockOrCatchScoped(d) || isClassLike(d) || (d.kind === SyntaxKind.EnumDeclaration) ? d : undefined);
Debug.assert(declaration !== undefined, "Declaration to checkResolvedBlockScopedVariable is undefined");
if (!isInAmbientContext(declaration) && !this.isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) {
if (result.flags & SymbolFlags.BlockScopedVariable) {
this.error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(getNameOfDeclaration(declaration)));
}
else if (result.flags & SymbolFlags.Class) {
this.error(errorLocation, Diagnostics.Class_0_used_before_its_declaration, declarationNameToString(getNameOfDeclaration(declaration)));
}
else if (result.flags & SymbolFlags.RegularEnum) {
this.error(errorLocation, Diagnostics.Enum_0_used_before_its_declaration, declarationNameToString(getNameOfDeclaration(declaration)));
}
}
}
/* Starting from 'initial' node walk up the parent chain until 'stopAt' node is reached.
* If at any point current node is equal to 'parent' node - return true.
* Return false if 'stopAt' node is reached or isFunctionLike(current) === true.
*/
public isSameScopeDescendentOf(initial: Node, parent: Node, stopAt: Node): boolean {
return parent && !!findAncestor(initial, n => n === stopAt || isFunctionLike(n) ? "quit" : n === parent);
}
public getAnyImportSyntax(node: Node): AnyImportSyntax {
if (isAliasSymbolDeclaration(node)) {
if (node.kind === SyntaxKind.ImportEqualsDeclaration) {
return node;
}
return findAncestor(node, isImportDeclaration);
}
}
public getDeclarationOfAliasSymbol(symbol: Symbol): Declaration | undefined {
return find(symbol.declarations, isAliasSymbolDeclaration);
}
public getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration, dontResolveAlias: boolean): Symbol {
if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) {
return this.resolveExternalModuleSymbol(this.resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)));
}
return this.getSymbolOfPartOfRightHandSideOfImportEquals((node.moduleReference), dontResolveAlias);
}
public getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol {
const moduleSymbol = this.resolveExternalModuleName(node, (node.parent).moduleSpecifier);
if (moduleSymbol) {
let exportDefaultSymbol: Symbol;
if (isShorthandAmbientModuleSymbol(moduleSymbol)) {
exportDefaultSymbol = moduleSymbol;
}
else {
const exportValue = moduleSymbol.exports.get("export=" as __String);
exportDefaultSymbol = exportValue
? this.getPropertyOfType(this.getTypeOfSymbol(exportValue), ("default" as __String))
: this.resolveSymbol(moduleSymbol.exports.get("default" as __String), dontResolveAlias);
}
if (!exportDefaultSymbol && !this.allowSyntheticDefaultImports) {
this.error(node.name, Diagnostics.Module_0_has_no_default_export, this.symbolToString(moduleSymbol));
}
else if (!exportDefaultSymbol && this.allowSyntheticDefaultImports) {
return this.resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || this.resolveSymbol(moduleSymbol, dontResolveAlias);
}
return exportDefaultSymbol;
}
}
public getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol {
const moduleSpecifier = (node.parent.parent).moduleSpecifier;
return this.resolveESModuleSymbol(this.resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier, dontResolveAlias);
}
// This function creates a synthetic symbol that combines the value side of one symbol with the
// type/namespace side of another symbol. Consider this example:
//
// declare module graphics {
// interface Point {
// x: number;
// y: number;
// }
// }
// declare var graphics: {
// Point: new (x: number, y: number) => graphics.Point;
// }
// declare module "graphics" {
// export = graphics;
// }
//
// An 'import { Point } from "graphics"' needs to create a symbol that combines the value side 'Point'
// property with the type/namespace side interface 'Point'.
public combineValueAndTypeSymbols(valueSymbol: Symbol, typeSymbol: Symbol): Symbol {
if (valueSymbol === this.unknownSymbol && typeSymbol === this.unknownSymbol) {
return this.unknownSymbol;
}
if (valueSymbol.flags & (SymbolFlags.Type | SymbolFlags.Namespace)) {
return valueSymbol;
}
const result = this.createSymbol(valueSymbol.flags | typeSymbol.flags, valueSymbol.escapedName);
result.declarations = concatenate(valueSymbol.declarations, typeSymbol.declarations);
result.parent = valueSymbol.parent || typeSymbol.parent;
if (valueSymbol.valueDeclaration)
result.valueDeclaration = valueSymbol.valueDeclaration;
if (typeSymbol.members)
result.members = typeSymbol.members;
if (valueSymbol.exports)
result.exports = valueSymbol.exports;
return result;
}
public getExportOfModule(symbol: Symbol, name: __String, dontResolveAlias: boolean): Symbol {
if (symbol.flags & SymbolFlags.Module) {
return this.resolveSymbol(this.getExportsOfSymbol(symbol).get(name), dontResolveAlias);
}
}
public getPropertyOfVariable(symbol: Symbol, name: __String): Symbol {
if (symbol.flags & SymbolFlags.Variable) {
const typeAnnotation = (symbol.valueDeclaration).type;
if (typeAnnotation) {
return this.resolveSymbol(this.getPropertyOfType(this.getTypeFromTypeNode(typeAnnotation), name));
}
}
}
public getExternalModuleMember(node: ImportDeclaration | ExportDeclaration, specifier: ImportOrExportSpecifier, dontResolveAlias?: boolean): Symbol {
const moduleSymbol = this.resolveExternalModuleName(node, node.moduleSpecifier);
const targetSymbol = this.resolveESModuleSymbol(moduleSymbol, node.moduleSpecifier, dontResolveAlias);
if (targetSymbol) {
const name = specifier.propertyName || specifier.name;
if (name.escapedText) {
if (isShorthandAmbientModuleSymbol(moduleSymbol)) {
return moduleSymbol;
}
let symbolFromVariable: Symbol;
// First check if module was specified with "export=". If so, get the member from the resolved type
if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports.get("export=" as __String)) {
symbolFromVariable = this.getPropertyOfType(this.getTypeOfSymbol(targetSymbol), name.escapedText);
}
else {
symbolFromVariable = this.getPropertyOfVariable(targetSymbol, name.escapedText);
}
// if symbolFromVariable is export - get its final target
symbolFromVariable = this.resolveSymbol(symbolFromVariable, dontResolveAlias);
let symbolFromModule = this.getExportOfModule(targetSymbol, name.escapedText, dontResolveAlias);
// If the export member we're looking for is default, and there is no real default but allowSyntheticDefaultImports is on, return the entire module as the default
if (!symbolFromModule && this.allowSyntheticDefaultImports && name.escapedText === "default") {
symbolFromModule = this.resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || this.resolveSymbol(moduleSymbol, dontResolveAlias);
}
const symbol = symbolFromModule && symbolFromVariable ?
this.combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) :
symbolFromModule || symbolFromVariable;
if (!symbol) {
this.error(name, Diagnostics.Module_0_has_no_exported_member_1, this.getFullyQualifiedName(moduleSymbol), declarationNameToString(name));
}
return symbol;
}
}
}
public getTargetOfImportSpecifier(node: ImportSpecifier, dontResolveAlias: boolean): Symbol {
return this.getExternalModuleMember((node.parent.parent.parent), node, dontResolveAlias);
}
public getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol {
return this.resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias);
}
public getTargetOfExportSpecifier(node: ExportSpecifier, meaning: SymbolFlags, dontResolveAlias?: boolean) {
return node.parent.parent.moduleSpecifier ?
this.getExternalModuleMember(node.parent.parent, node, dontResolveAlias) :
this.resolveEntityName(node.propertyName || node.name, meaning, /*ignoreErrors*/ false, dontResolveAlias);
}
public getTargetOfExportAssignment(node: ExportAssignment, dontResolveAlias: boolean): Symbol {
return this.resolveEntityName((node.expression), SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias);
}
public getTargetOfAliasDeclaration(node: Declaration, dontRecursivelyResolve?: boolean): Symbol {
switch (node.kind) {
case SyntaxKind.ImportEqualsDeclaration:
return this.getTargetOfImportEqualsDeclaration((node), dontRecursivelyResolve);
case SyntaxKind.ImportClause:
return this.getTargetOfImportClause((node), dontRecursivelyResolve);
case SyntaxKind.NamespaceImport:
return this.getTargetOfNamespaceImport((node), dontRecursivelyResolve);
case SyntaxKind.ImportSpecifier:
return this.getTargetOfImportSpecifier((node), dontRecursivelyResolve);
case SyntaxKind.ExportSpecifier:
return this.getTargetOfExportSpecifier((node), SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, dontRecursivelyResolve);
case SyntaxKind.ExportAssignment:
return this.getTargetOfExportAssignment((node), dontRecursivelyResolve);
case SyntaxKind.NamespaceExportDeclaration:
return this.getTargetOfNamespaceExportDeclaration((node), dontRecursivelyResolve);
}
}
/**
* Indicates that a symbol is an alias that does not merge with a local declaration.
*/
public isNonLocalAlias(symbol: Symbol, excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace) {
return symbol && (symbol.flags & (SymbolFlags.Alias | excludes)) === SymbolFlags.Alias;
}
public resolveSymbol(symbol: Symbol, dontResolveAlias?: boolean): Symbol {
const shouldResolve = !dontResolveAlias && this.isNonLocalAlias(symbol);
return shouldResolve ? this.resolveAlias(symbol) : symbol;
}
public resolveAlias(symbol: Symbol): Symbol {
Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here.");
const links = this.getSymbolLinks(symbol);
if (!links.target) {
links.target = this.resolvingSymbol;
const node = this.getDeclarationOfAliasSymbol(symbol);
Debug.assert(!!node);
const target = this.getTargetOfAliasDeclaration(node);
if (links.target === this.resolvingSymbol) {
links.target = target || this.unknownSymbol;
}
else {
this.error(node, Diagnostics.Circular_definition_of_import_alias_0, this.symbolToString(symbol));
}
}
else if (links.target === this.resolvingSymbol) {
links.target = this.unknownSymbol;
}
return links.target;
}
public markExportAsReferenced(node: ImportEqualsDeclaration | ExportAssignment | ExportSpecifier) {
const symbol = this.getSymbolOfNode(node);
const target = this.resolveAlias(symbol);
if (target) {
const markAlias = target === this.unknownSymbol ||
((target.flags & SymbolFlags.Value) && !this.isConstEnumOrConstEnumOnlyModule(target));
if (markAlias) {
this.markAliasSymbolAsReferenced(symbol);
}
}
}
// When an alias symbol is referenced, we need to mark the entity it references as referenced and in turn repeat that until
// we reach a non-alias or an exported entity (which is always considered referenced). We do this by checking the target of
// the alias as an expression (which recursively takes us back here if the target references another alias).
public markAliasSymbolAsReferenced(symbol: Symbol) {
const links = this.getSymbolLinks(symbol);
if (!links.referenced) {
links.referenced = true;
const node = this.getDeclarationOfAliasSymbol(symbol);
Debug.assert(!!node);
if (node.kind === SyntaxKind.ExportAssignment) {
// export default
this.checkExpressionCached((node).expression);
}
else if (node.kind === SyntaxKind.ExportSpecifier) {
// export { } or export { as foo }
this.checkExpressionCached((node).propertyName || (node).name);
}
else if (isInternalModuleImportEqualsDeclaration(node)) {
// import foo =
this.checkExpressionCached(((node).moduleReference));
}
}
}
// This function is only for imports with entity names
public getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, dontResolveAlias?: boolean): Symbol {
// There are three things we might try to look for. In the following examples,
// the search term is enclosed in |...|:
//
// import a = |b|; // Namespace
// import a = |b.c|; // Value, type, namespace
// import a = |b.c|.d; // Namespace
if (entityName.kind === SyntaxKind.Identifier && isRightSideOfQualifiedNameOrPropertyAccess(entityName)) {
entityName = entityName.parent;
}
// Check for case 1 and 3 in the above example
if (entityName.kind === SyntaxKind.Identifier || entityName.parent.kind === SyntaxKind.QualifiedName) {
return this.resolveEntityName(entityName, SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias);
}
else {
// Case 2 in above example
// entityName.kind could be a QualifiedName or a Missing identifier
Debug.assert(entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration);
return this.resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias);
}
}
public getFullyQualifiedName(symbol: Symbol): string {
return symbol.parent ? this.getFullyQualifiedName(symbol.parent) + "." + this.symbolToString(symbol) : this.symbolToString(symbol);
}
/**
* Resolves a qualified name and any involved aliases.
*/
public resolveEntityName(name: EntityNameOrEntityNameExpression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean, location?: Node): Symbol | undefined {
if (nodeIsMissing(name)) {
return undefined;
}
let symbol: Symbol;
if (name.kind === SyntaxKind.Identifier) {
const message = meaning === SymbolFlags.Namespace ? Diagnostics.Cannot_find_namespace_0 : Diagnostics.Cannot_find_name_0;
symbol = this.resolveName(location || name, name.escapedText, meaning, ignoreErrors ? undefined : message, name);
if (!symbol) {
return undefined;
}
}
else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) {
let left: EntityNameOrEntityNameExpression;
if (name.kind === SyntaxKind.QualifiedName) {
left = (name).left;
}
else if (name.kind === SyntaxKind.PropertyAccessExpression &&
(name.expression.kind === SyntaxKind.ParenthesizedExpression || isEntityNameExpression(name.expression))) {
left = name.expression;
}
else {
// If the expression in property-access expression is not entity-name or parenthsizedExpression (e.g. it is a call expression), it won't be able to successfully resolve the name.
// This is the case when we are trying to do any language service operation in heritage clauses. By return undefined, the getSymbolOfEntityNameOrPropertyAccessExpression
// will attempt to checkPropertyAccessExpression to resolve symbol.
// i.e class C extends foo()./*do language service operation here*/B {}
return undefined;
}
const right = name.kind === SyntaxKind.QualifiedName ? name.right : name.name;
const namespace = this.resolveEntityName(left, SymbolFlags.Namespace, ignoreErrors, /*dontResolveAlias*/ false, location);
if (!namespace || nodeIsMissing(right)) {
return undefined;
}
else if (namespace === this.unknownSymbol) {
return namespace;
}
symbol = this.getSymbol(this.getExportsOfSymbol(namespace), right.escapedText, meaning);
if (!symbol) {
if (!ignoreErrors) {
this.error(right, Diagnostics.Namespace_0_has_no_exported_member_1, this.getFullyQualifiedName(namespace), declarationNameToString(right));
}
return undefined;
}
}
else if (name.kind === SyntaxKind.ParenthesizedExpression) {
// If the expression in parenthesizedExpression is not an entity-name (e.g. it is a call expression), it won't be able to successfully resolve the name.
// This is the case when we are trying to do any language service operation in heritage clauses.
// By return undefined, the getSymbolOfEntityNameOrPropertyAccessExpression will attempt to checkPropertyAccessExpression to resolve symbol.
// i.e class C extends foo()./*do language service operation here*/B {}
return isEntityNameExpression(name.expression) ?
this.resolveEntityName((name.expression as EntityNameOrEntityNameExpression), meaning, ignoreErrors, dontResolveAlias, location) :
undefined;
}
else {
Debug.fail("Unknown entity name kind.");
}
Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
return (symbol.flags & meaning) || dontResolveAlias ? symbol : this.resolveAlias(symbol);
}
public resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression): Symbol {
return this.resolveExternalModuleNameWorker(location, moduleReferenceExpression, Diagnostics.Cannot_find_module_0);
}
public resolveExternalModuleNameWorker(location: Node, moduleReferenceExpression: Expression, moduleNotFoundError: DiagnosticMessage, isForAugmentation = false): Symbol {
if (moduleReferenceExpression.kind !== SyntaxKind.StringLiteral && moduleReferenceExpression.kind !== SyntaxKind.NoSubstitutionTemplateLiteral) {
return;
}
const moduleReferenceLiteral = moduleReferenceExpression;
return this.resolveExternalModule(location, moduleReferenceLiteral.text, moduleNotFoundError, moduleReferenceLiteral, isForAugmentation);
}
public resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage, errorNode: Node, isForAugmentation = false): Symbol {
if (moduleReference === undefined) {
return;
}
if (startsWith(moduleReference, "@types/")) {
const diag = Diagnostics.Cannot_import_type_declaration_files_Consider_importing_0_instead_of_1;
const withoutAtTypePrefix = removePrefix(moduleReference, "@types/");
this.error(errorNode, diag, withoutAtTypePrefix, moduleReference);
}
const ambientModule = this.tryFindAmbientModule(moduleReference, /*withAugmentations*/ true);
if (ambientModule) {
return ambientModule;
}
const isRelative = isExternalModuleNameRelative(moduleReference);
const resolvedModule = getResolvedModule(getSourceFileOfNode(location), moduleReference);
const resolutionDiagnostic = resolvedModule && getResolutionDiagnostic(this.compilerOptions, resolvedModule);
const sourceFile = resolvedModule && !resolutionDiagnostic && this.host.getSourceFile(resolvedModule.resolvedFileName);
if (sourceFile) {
if (sourceFile.symbol) {
// merged symbol is module declaration symbol combined with all augmentations
return this.getMergedSymbol(sourceFile.symbol);
}
if (moduleNotFoundError) {
// report errors only if it was requested
this.error(errorNode, Diagnostics.File_0_is_not_a_module, sourceFile.fileName);
}
return undefined;
}
if (this.patternAmbientModules) {
const pattern = findBestPatternMatch(this.patternAmbientModules, _ => _.pattern, moduleReference);
if (pattern) {
return this.getMergedSymbol(pattern.symbol);
}
}
// May be an untyped module. If so, ignore resolutionDiagnostic.
if (!isRelative && resolvedModule && !extensionIsTypeScript(resolvedModule.extension)) {
if (isForAugmentation) {
const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented;
this.error(errorNode, diag, moduleReference, resolvedModule.resolvedFileName);
}
else if (this.noImplicitAny && moduleNotFoundError) {
let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, moduleReference);
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type, moduleReference, resolvedModule.resolvedFileName);
this.diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo));
}
// Failed imports and untyped modules are both treated in an untyped manner; only difference is whether we give a diagnostic first.
return undefined;
}
if (moduleNotFoundError) {
// report errors only if it was requested
if (resolutionDiagnostic) {
this.error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName);
}
else {
const tsExtension = tryExtractTypeScriptExtension(moduleReference);
if (tsExtension) {
const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead;
this.error(errorNode, diag, tsExtension, removeExtension(moduleReference, tsExtension));
}
else {
this.error(errorNode, moduleNotFoundError, moduleReference);
}
}
}
return undefined;
}
// An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
// and an external module with no 'export =' declaration resolves to the module itself.
public resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol {
return moduleSymbol && this.getMergedSymbol(this.resolveSymbol(moduleSymbol.exports.get(InternalSymbolName.ExportEquals), dontResolveAlias)) || moduleSymbol;
}
// An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export ='
// references a symbol that is at least declared as a module or a variable. The target of the 'export =' may
// combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable).
public resolveESModuleSymbol(moduleSymbol: Symbol, moduleReferenceExpression: Expression, dontResolveAlias: boolean): Symbol {
const symbol = this.resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias);
if (!dontResolveAlias && symbol && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) {
this.error(moduleReferenceExpression, Diagnostics.Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, this.symbolToString(moduleSymbol));
}
return symbol;
}
public hasExportAssignmentSymbol(moduleSymbol: Symbol): boolean {
return moduleSymbol.exports.get(InternalSymbolName.ExportEquals) !== undefined;
}
public getExportsOfModuleAsArray(moduleSymbol: Symbol): Symbol[] {
return this.symbolsToArray(this.getExportsOfModule(moduleSymbol));
}
public getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[] {
const exports = this.getExportsOfModuleAsArray(moduleSymbol);
const exportEquals = this.resolveExternalModuleSymbol(moduleSymbol);
if (exportEquals !== moduleSymbol) {
addRange(exports, this.getPropertiesOfType(this.getTypeOfSymbol(exportEquals)));
}
return exports;
}
public tryGetMemberInModuleExports(memberName: __String, moduleSymbol: Symbol): Symbol | undefined {
const symbolTable = this.getExportsOfModule(moduleSymbol);
if (symbolTable) {
return symbolTable.get(memberName);
}
}
public tryGetMemberInModuleExportsAndProperties(memberName: __String, moduleSymbol: Symbol): Symbol | undefined {
const symbol = this.tryGetMemberInModuleExports(memberName, moduleSymbol);
if (!symbol) {
const exportEquals = this.resolveExternalModuleSymbol(moduleSymbol);
if (exportEquals !== moduleSymbol) {
return this.getPropertyOfType(this.getTypeOfSymbol(exportEquals), memberName);
}
}
return symbol;
}
public getExportsOfSymbol(symbol: Symbol): SymbolTable {
return symbol.flags & SymbolFlags.Module ? this.getExportsOfModule(symbol) : symbol.exports || this.emptySymbols;
}
public getExportsOfModule(moduleSymbol: Symbol): SymbolTable {
const links = this.getSymbolLinks(moduleSymbol);
return links.resolvedExports || (links.resolvedExports = this.getExportsOfModuleWorker(moduleSymbol));
}
/**
* Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument
* Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables
*/
public extendExportSymbols(target: SymbolTable, source: SymbolTable, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) {
const __conv_self__ = this;
source && source.forEach((sourceSymbol, id) => {
if (id === "default")
return;
const targetSymbol = target.get(id);
if (!targetSymbol) {
target.set(id, sourceSymbol);
if (lookupTable && exportNode) {
lookupTable.set(id, {
specifierText: getTextOfNode(exportNode.moduleSpecifier)
} as ExportCollisionTracker);
}
}
else if (lookupTable && exportNode && targetSymbol && __conv_self__.resolveSymbol(targetSymbol) !== __conv_self__.resolveSymbol(sourceSymbol)) {
const collisionTracker = lookupTable.get(id);
if (!collisionTracker.exportsWithDuplicate) {
collisionTracker.exportsWithDuplicate = [exportNode];
}
else {
collisionTracker.exportsWithDuplicate.push(exportNode);
}
}
});
}
public getExportsOfModuleWorker(moduleSymbol: Symbol): SymbolTable {
const __conv_self__ = this;
const visitedSymbols: Symbol[] = [];
// A module defined by an 'export=' consists on one export that needs to be resolved
moduleSymbol = this.resolveExternalModuleSymbol(moduleSymbol);
return visit(moduleSymbol) || this.emptySymbols;
// The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
// module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
function visit(symbol: Symbol): SymbolTable {
if (!(symbol && symbol.flags & SymbolFlags.HasExports && !contains(visitedSymbols, symbol))) {
return;
}
visitedSymbols.push(symbol);
const symbols = cloneMap(symbol.exports);
// All export * declarations are collected in an __export symbol by the binder
const exportStars = symbol.exports.get(InternalSymbolName.ExportStar);
if (exportStars) {
const nestedSymbols = createSymbolTable();
const lookupTable = createMap() as ExportCollisionTrackerTable;
for (const node of exportStars.declarations) {
const resolvedModule = __conv_self__.resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier);
const exportedSymbols = visit(resolvedModule);
__conv_self__.extendExportSymbols(nestedSymbols, exportedSymbols, lookupTable, (node as ExportDeclaration));
}
lookupTable.forEach(({ exportsWithDuplicate }, id) => {
// It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself
if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || symbols.has(id)) {
return;
}
for (const node of exportsWithDuplicate) {
__conv_self__.diagnostics.add(createDiagnosticForNode(node, Diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, lookupTable.get(id).specifierText, unescapeLeadingUnderscores(id)));
}
});
__conv_self__.extendExportSymbols(symbols, nestedSymbols);
}
return symbols;
}
}
public getMergedSymbol(symbol: Symbol): Symbol {
let merged: Symbol;
return symbol && symbol.mergeId && (merged = this.mergedSymbols[symbol.mergeId]) ? merged : symbol;
}
public getSymbolOfNode(node: Node): Symbol {
return this.getMergedSymbol(node.symbol);
}
public getParentOfSymbol(symbol: Symbol): Symbol {
return this.getMergedSymbol(symbol.parent);
}
public getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol {
return symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0
? this.getMergedSymbol(symbol.exportSymbol)
: symbol;
}
public symbolIsValue(symbol: Symbol): boolean {
return !!(symbol.flags & SymbolFlags.Value || symbol.flags & SymbolFlags.Alias && this.resolveAlias(symbol).flags & SymbolFlags.Value);
}
public findConstructorDeclaration(node: ClassLikeDeclaration): ConstructorDeclaration {
const members = node.members;
for (const member of members) {
if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member).body)) {
return member;
}
}
}
public createType(flags: TypeFlags): Type {
const result = new this.Type(this.checker, flags);
this.typeCount++;
result.id = this.typeCount;
return result;
}
public createIntrinsicType(kind: TypeFlags, intrinsicName: string): IntrinsicType {
const type = (this.createType(kind));
type.intrinsicName = intrinsicName;
return type;
}
public createBooleanType(trueFalseTypes: Type[]): IntrinsicType & UnionType {
const type = (this.getUnionType(trueFalseTypes));
type.flags |= TypeFlags.Boolean;
type.intrinsicName = "boolean";
return type;
}
public createObjectType(objectFlags: ObjectFlags, symbol?: Symbol): ObjectType {
const type = (this.createType(TypeFlags.Object));
type.objectFlags = objectFlags;
type.symbol = symbol;
return type;
}
public createTypeofType() {
return this.getUnionType(arrayFrom(this.typeofEQFacts.keys(), this.getLiteralType));
}
// A reserved member name starts with two underscores, but the third character cannot be an underscore
// or the @ symbol. A third underscore indicates an escaped form of an identifer that started
// with at least two underscores. The @ character indicates that the name is denoted by a well known ES
// Symbol instance.
public isReservedMemberName(name: __String) {
return (name as string).charCodeAt(0) === CharacterCodes._ &&
(name as string).charCodeAt(1) === CharacterCodes._ &&
(name as string).charCodeAt(2) !== CharacterCodes._ &&
(name as string).charCodeAt(2) !== CharacterCodes.at;
}
public getNamedMembers(members: SymbolTable): Symbol[] {
const __conv_self__ = this;
let result: Symbol[];
members.forEach((symbol, id) => {
if (!__conv_self__.isReservedMemberName(id)) {
if (!result)
result = [];
if (__conv_self__.symbolIsValue(symbol)) {
result.push(symbol);
}
}
});
return result || emptyArray;
}
public setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): ResolvedType {
(type).members = members;
(type).properties = this.getNamedMembers(members);
(type).callSignatures = callSignatures;
(type).constructSignatures = constructSignatures;
if (stringIndexInfo)
(type).stringIndexInfo = stringIndexInfo;
if (numberIndexInfo)
(type).numberIndexInfo = numberIndexInfo;
return type;
}
public createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): ResolvedType {
return this.setStructuredTypeMembers(this.createObjectType(ObjectFlags.Anonymous, symbol), members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
}
public forEachSymbolTableInScope(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T {
let result: T;
for (let location = enclosingDeclaration; location; location = location.parent) {
// Locals of a source file are not in scope (because they get merged into the global symbol table)
if (location.locals && !this.isGlobalSourceFile(location)) {
if (result = callback(location.locals)) {
return result;
}
}
switch (location.kind) {
case SyntaxKind.SourceFile:
if (!isExternalOrCommonJsModule(location)) {
break;
}
// falls through
case SyntaxKind.ModuleDeclaration:
if (result = callback(this.getSymbolOfNode(location).exports)) {
return result;
}
break;
}
}
return callback(this.globals);
}
public getQualifiedLeftMeaning(rightMeaning: SymbolFlags) {
// If we are looking in value space, the parent meaning is value, other wise it is namespace
return rightMeaning === SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.Namespace;
}
public getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] {
const __conv_self__ = this;
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable) {
return getAccessibleSymbolChainFromSymbolTableWorker(symbols, []);
}
function getAccessibleSymbolChainFromSymbolTableWorker(symbols: SymbolTable, visitedSymbolTables: SymbolTable[]): Symbol[] {
if (contains(visitedSymbolTables, symbols)) {
return undefined;
}
visitedSymbolTables.push(symbols);
const result = trySymbolTable(symbols);
visitedSymbolTables.pop();
return result;
function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) {
// If the symbol is equivalent and doesn't need further qualification, this symbol is accessible
if (!__conv_self__.needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning)) {
return true;
}
// If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too
const accessibleParent = __conv_self__.getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, __conv_self__.getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing);
return !!accessibleParent;
}
function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol) {
if (symbol === (resolvedAliasSymbol || symbolFromSymbolTable)) {
// if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table)
// and if symbolFromSymbolTable or alias resolution matches the symbol,
// check the symbol can be qualified, it is only then this symbol is accessible
return !forEach(symbolFromSymbolTable.declarations, __conv_self__.hasExternalModuleSymbol) &&
canQualifySymbol(symbolFromSymbolTable, meaning);
}
}
function trySymbolTable(symbols: SymbolTable) {
// If symbol is directly available by its name in the symbol table
if (isAccessible(symbols.get(symbol.escapedName))) {
return [symbol];
}
// Check if symbol is any of the alias
return forEachEntry(symbols, symbolFromSymbolTable => {
if (symbolFromSymbolTable.flags & SymbolFlags.Alias
&& symbolFromSymbolTable.escapedName !== "export="
&& !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) {
if (!useOnlyExternalAliasing ||
// Is this external alias, then use it to name
ts.forEach(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) {
const resolvedImportedSymbol = __conv_self__.resolveAlias(symbolFromSymbolTable);
if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol)) {
return [symbolFromSymbolTable];
}
// Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain
// but only if the symbolFromSymbolTable can be qualified
const accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTableWorker(resolvedImportedSymbol.exports, visitedSymbolTables) : undefined;
if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, __conv_self__.getQualifiedLeftMeaning(meaning))) {
return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports);
}
}
}
});
}
}
if (symbol && !this.isPropertyOrMethodDeclarationSymbol(symbol)) {
return this.forEachSymbolTableInScope(enclosingDeclaration, getAccessibleSymbolChainFromSymbolTable);
}
}
public needsQualification(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) {
const __conv_self__ = this;
let qualify = false;
this.forEachSymbolTableInScope(enclosingDeclaration, symbolTable => {
// If symbol of this name is not available in the symbol table we are ok
let symbolFromSymbolTable = symbolTable.get(symbol.escapedName);
if (!symbolFromSymbolTable) {
// Continue to the next symbol table
return false;
}
// If the symbol with this name is present it should refer to the symbol
if (symbolFromSymbolTable === symbol) {
// No need to qualify
return true;
}
// Qualify if the symbol from symbol table has same meaning as expected
symbolFromSymbolTable = (symbolFromSymbolTable.flags & SymbolFlags.Alias && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) ? __conv_self__.resolveAlias(symbolFromSymbolTable) : symbolFromSymbolTable;
if (symbolFromSymbolTable.flags & meaning) {
qualify = true;
return true;
}
// Continue to the next symbol table
return false;
});
return qualify;
}
public isPropertyOrMethodDeclarationSymbol(symbol: Symbol) {
if (symbol.declarations && symbol.declarations.length) {
for (const declaration of symbol.declarations) {
switch (declaration.kind) {
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
continue;
default:
return false;
}
}
return true;
}
return false;
}
/**
* Check if the given symbol in given enclosing declaration is accessible and mark all associated alias to be visible if requested
*
* @param symbol a Symbol to check if accessible
* @param enclosingDeclaration a Node containing reference to the symbol
* @param meaning a SymbolFlags to check if such meaning of the symbol is accessible
* @param shouldComputeAliasToMakeVisible a boolean value to indicate whether to return aliases to be mark visible in case the symbol is accessible
*/
public isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult {
const __conv_self__ = this;
if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) {
const initialSymbol = symbol;
let meaningToLook = meaning;
while (symbol) {
// Symbol is accessible if it by itself is accessible
const accessibleSymbolChain = this.getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false);
if (accessibleSymbolChain) {
const hasAccessibleDeclarations = this.hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible);
if (!hasAccessibleDeclarations) {
return {
accessibility: SymbolAccessibility.NotAccessible,
errorSymbolName: this.symbolToString(initialSymbol, enclosingDeclaration, meaning),
errorModuleName: symbol !== initialSymbol ? this.symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
};
}
return hasAccessibleDeclarations;
}
// If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible.
// It could be a qualified symbol and hence verify the path
// e.g.:
// module m {
// export class c {
// }
// }
// const x: typeof m.c
// In the above example when we start with checking if typeof m.c symbol is accessible,
// we are going to see if c can be accessed in scope directly.
// But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
// It is accessible if the parent m is accessible because then m.c can be accessed through qualification
meaningToLook = this.getQualifiedLeftMeaning(meaning);
symbol = this.getParentOfSymbol(symbol);
}
// This could be a symbol that is not exported in the external module
// or it could be a symbol from different external module that is not aliased and hence cannot be named
const symbolExternalModule = forEach(initialSymbol.declarations, getExternalModuleContainer);
if (symbolExternalModule) {
const enclosingExternalModule = getExternalModuleContainer(enclosingDeclaration);
if (symbolExternalModule !== enclosingExternalModule) {
// name from different external module that is not visible
return {
accessibility: SymbolAccessibility.CannotBeNamed,
errorSymbolName: this.symbolToString(initialSymbol, enclosingDeclaration, meaning),
errorModuleName: this.symbolToString(symbolExternalModule)
};
}
}
// Just a local name that is not accessible
return {
accessibility: SymbolAccessibility.NotAccessible,
errorSymbolName: this.symbolToString(initialSymbol, enclosingDeclaration, meaning),
};
}
return { accessibility: SymbolAccessibility.Accessible };
function getExternalModuleContainer(declaration: Node) {
const node = findAncestor(declaration, __conv_self__.hasExternalModuleSymbol);
return node && __conv_self__.getSymbolOfNode(node);
}
}
public hasExternalModuleSymbol(declaration: Node) {
return isAmbientModule(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration));
}
public hasVisibleDeclarations(symbol: Symbol, shouldComputeAliasToMakeVisible: boolean): SymbolVisibilityResult {
const __conv_self__ = this;
let aliasesToMakeVisible: AnyImportSyntax[];
if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) {
return undefined;
}
return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible };
function getIsDeclarationVisible(declaration: Declaration) {
if (!__conv_self__.isDeclarationVisible(declaration)) {
// Mark the unexported alias as visible if its parent is visible
// because these kind of aliases can be used to name types in declaration file
const anyImportSyntax = __conv_self__.getAnyImportSyntax(declaration);
if (anyImportSyntax &&
!hasModifier(anyImportSyntax, ModifierFlags.Export) &&
__conv_self__.isDeclarationVisible((anyImportSyntax.parent))) {
// In function "buildTypeDisplay" where we decide whether to write type-alias or serialize types,
// we want to just check if type- alias is accessible or not but we don't care about emitting those alias at that time
// since we will do the emitting later in trackSymbol.
if (shouldComputeAliasToMakeVisible) {
__conv_self__.getNodeLinks(declaration).isVisible = true;
if (aliasesToMakeVisible) {
if (!contains(aliasesToMakeVisible, anyImportSyntax)) {
aliasesToMakeVisible.push(anyImportSyntax);
}
}
else {
aliasesToMakeVisible = [anyImportSyntax];
}
}
return true;
}
// Declaration is not visible
return false;
}
return true;
}
}
public isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult {
// get symbol of the first identifier of the entityName
let meaning: SymbolFlags;
if (entityName.parent.kind === SyntaxKind.TypeQuery || isExpressionWithTypeArgumentsInClassExtendsClause(entityName.parent)) {
// Typeof value
meaning = SymbolFlags.Value | SymbolFlags.ExportValue;
}
else if (entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression ||
entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration) {
// Left identifier from type reference or TypeAlias
// Entity name of the import declaration
meaning = SymbolFlags.Namespace;
}
else {
// Type Reference or TypeAlias entity = Identifier
meaning = SymbolFlags.Type;
}
const firstIdentifier = this.getFirstIdentifier(entityName);
const symbol = this.resolveName(enclosingDeclaration, firstIdentifier.escapedText, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined);
// Verify if the symbol is accessible
return (symbol && this.hasVisibleDeclarations(symbol, /*shouldComputeAliasToMakeVisible*/ true)) || {
accessibility: SymbolAccessibility.NotAccessible,
errorSymbolName: getTextOfNode(firstIdentifier),
errorNode: firstIdentifier
};
}
public writeKeyword(writer: SymbolWriter, kind: SyntaxKind) {
writer.writeKeyword(tokenToString(kind));
}
public writePunctuation(writer: SymbolWriter, kind: SyntaxKind) {
writer.writePunctuation(tokenToString(kind));
}
public writeSpace(writer: SymbolWriter) {
writer.writeSpace(" ");
}
public symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string {
const __conv_self__ = this;
return usingSingleLineStringWriter(writer => {
__conv_self__.getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning);
});
}
public signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string {
const __conv_self__ = this;
return usingSingleLineStringWriter(writer => {
__conv_self__.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags, kind);
});
}
public typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string {
const typeNode = this.nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName);
Debug.assert(typeNode !== undefined, "should always get typenode");
const options = { removeComments: true };
const writer = createTextWriter("");
const printer = createPrinter(options);
const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration);
printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer);
const result = writer.getText();
const maxLength = this.compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100;
if (maxLength && result.length >= maxLength) {
return result.substr(0, maxLength - "...".length) + "...";
}
return result;
function toNodeBuilderFlags(flags?: TypeFormatFlags): NodeBuilderFlags {
let result = NodeBuilderFlags.None;
if (!flags) {
return result;
}
if (flags & TypeFormatFlags.NoTruncation) {
result |= NodeBuilderFlags.NoTruncation;
}
if (flags & TypeFormatFlags.UseFullyQualifiedType) {
result |= NodeBuilderFlags.UseFullyQualifiedType;
}
if (flags & TypeFormatFlags.SuppressAnyReturnType) {
result |= NodeBuilderFlags.SuppressAnyReturnType;
}
if (flags & TypeFormatFlags.WriteArrayAsGenericType) {
result |= NodeBuilderFlags.WriteArrayAsGenericType;
}
if (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature) {
result |= NodeBuilderFlags.WriteTypeArgumentsOfSignature;
}
return result;
}
}
public createNodeBuilder() {
const __conv_self__ = this;
return {
typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
const context = createNodeBuilderContext(enclosingDeclaration, flags);
const resultingNode = typeToTypeNodeHelper(type, context);
const result = context.encounteredError ? undefined : resultingNode;
return result;
},
indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
const context = createNodeBuilderContext(enclosingDeclaration, flags);
const resultingNode = indexInfoToIndexSignatureDeclarationHelper(indexInfo, kind, context);
const result = context.encounteredError ? undefined : resultingNode;
return result;
},
signatureToSignatureDeclaration: (signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
const context = createNodeBuilderContext(enclosingDeclaration, flags);
const resultingNode = signatureToSignatureDeclarationHelper(signature, kind, context);
const result = context.encounteredError ? undefined : resultingNode;
return result;
}
};
interface NodeBuilderContext {
enclosingDeclaration: Node | undefined;
flags: NodeBuilderFlags | undefined;
// State
encounteredError: boolean;
symbolStack: Symbol[] | undefined;
}
function createNodeBuilderContext(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): NodeBuilderContext {
return {
enclosingDeclaration,
flags,
encounteredError: false,
symbolStack: undefined
};
}
function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode {
const inTypeAlias = context.flags & NodeBuilderFlags.InTypeAlias;
context.flags &= ~NodeBuilderFlags.InTypeAlias;
if (!type) {
context.encounteredError = true;
return undefined;
}
if (type.flags & TypeFlags.Any) {
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
if (type.flags & TypeFlags.String) {
return createKeywordTypeNode(SyntaxKind.StringKeyword);
}
if (type.flags & TypeFlags.Number) {
return createKeywordTypeNode(SyntaxKind.NumberKeyword);
}
if (type.flags & TypeFlags.Boolean) {
return createKeywordTypeNode(SyntaxKind.BooleanKeyword);
}
if (type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union)) {
const parentSymbol = __conv_self__.getParentOfSymbol(type.symbol);
const parentName = symbolToName(parentSymbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false);
const enumLiteralName = __conv_self__.getDeclaredTypeOfSymbol(parentSymbol) === type ? parentName : createQualifiedName(parentName, getNameOfSymbol(type.symbol, context));
return createTypeReferenceNode(enumLiteralName, /*typeArguments*/ undefined);
}
if (type.flags & TypeFlags.EnumLike) {
const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false);
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
}
if (type.flags & (TypeFlags.StringLiteral)) {
return createLiteralTypeNode(setEmitFlags(createLiteral((type).value), EmitFlags.NoAsciiEscaping));
}
if (type.flags & (TypeFlags.NumberLiteral)) {
return createLiteralTypeNode((createLiteral((type).value)));
}
if (type.flags & TypeFlags.BooleanLiteral) {
return (type).intrinsicName === "true" ? createTrue() : createFalse();
}
if (type.flags & TypeFlags.Void) {
return createKeywordTypeNode(SyntaxKind.VoidKeyword);
}
if (type.flags & TypeFlags.Undefined) {
return createKeywordTypeNode(SyntaxKind.UndefinedKeyword);
}
if (type.flags & TypeFlags.Null) {
return createKeywordTypeNode(SyntaxKind.NullKeyword);
}
if (type.flags & TypeFlags.Never) {
return createKeywordTypeNode(SyntaxKind.NeverKeyword);
}
if (type.flags & TypeFlags.ESSymbol) {
return createKeywordTypeNode(SyntaxKind.SymbolKeyword);
}
if (type.flags & TypeFlags.NonPrimitive) {
return createKeywordTypeNode(SyntaxKind.ObjectKeyword);
}
if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) {
if (context.flags & NodeBuilderFlags.InObjectTypeLiteral) {
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowThisInObjectLiteral)) {
context.encounteredError = true;
}
}
return createThis();
}
const objectFlags = __conv_self__.getObjectFlags(type);
if (objectFlags & ObjectFlags.Reference) {
Debug.assert(!!(type.flags & TypeFlags.Object));
return typeReferenceToTypeNode(type);
}
if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) {
const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false);
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
}
if (!inTypeAlias && type.aliasSymbol &&
__conv_self__.isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
const name = symbolToTypeReferenceName(type.aliasSymbol);
const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context);
return createTypeReferenceNode(name, typeArgumentNodes);
}
if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) {
const types = type.flags & TypeFlags.Union ? __conv_self__.formatUnionTypes((type).types) : (type).types;
const typeNodes = mapToTypeNodes(types, context);
if (typeNodes && typeNodes.length > 0) {
const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes);
return unionOrIntersectionTypeNode;
}
else {
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) {
context.encounteredError = true;
}
return undefined;
}
}
if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
Debug.assert(!!(type.flags & TypeFlags.Object));
// The type is an object literal type.
return createAnonymousTypeNode(type);
}
if (type.flags & TypeFlags.Index) {
const indexedType = (type).type;
const indexTypeNode = typeToTypeNodeHelper(indexedType, context);
return createTypeOperatorNode(indexTypeNode);
}
if (type.flags & TypeFlags.IndexedAccess) {
const objectTypeNode = typeToTypeNodeHelper((type).objectType, context);
const indexTypeNode = typeToTypeNodeHelper((type).indexType, context);
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
}
Debug.fail("Should be unreachable.");
function createMappedTypeNodeFromType(type: MappedType) {
Debug.assert(!!(type.flags & TypeFlags.Object));
const readonlyToken = type.declaration && type.declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
const questionToken = type.declaration && type.declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
const typeParameterNode = typeParameterToDeclaration(__conv_self__.getTypeParameterFromMappedType(type), context);
const templateTypeNode = typeToTypeNodeHelper(__conv_self__.getTemplateTypeFromMappedType(type), context);
const mappedTypeNode = createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine);
}
function createAnonymousTypeNode(type: ObjectType): TypeNode {
const symbol = type.symbol;
if (symbol) {
// Always use 'typeof T' for type of class, enum, and module objects
if (symbol.flags & SymbolFlags.Class && !__conv_self__.getBaseTypeVariableOfClass(symbol) ||
symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) ||
shouldWriteTypeOfFunctionSymbol()) {
return createTypeQueryNodeFromSymbol(symbol, SymbolFlags.Value);
}
else if (contains(context.symbolStack, symbol)) {
// If type is an anonymous type literal in a type alias declaration, use type alias name
const typeAlias = __conv_self__.getTypeAliasForTypeLiteral(type);
if (typeAlias) {
// The specified symbol flags need to be reinterpreted as type flags
const entityName = symbolToName(typeAlias, context, SymbolFlags.Type, /*expectsIdentifier*/ false);
return createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
}
else {
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
}
else {
// Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
// of types allows us to catch circular references to instantiations of the same anonymous type
if (!context.symbolStack) {
context.symbolStack = [];
}
context.symbolStack.push(symbol);
const result = createTypeNodeFromObjectType(type);
context.symbolStack.pop();
return result;
}
}
else {
// Anonymous types without a symbol are never circular.
return createTypeNodeFromObjectType(type);
}
function shouldWriteTypeOfFunctionSymbol() {
const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) &&
some(symbol.declarations, declaration => hasModifier(declaration, ModifierFlags.Static));
const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) &&
(symbol.parent ||
forEach(symbol.declarations, declaration => declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
// typeof is allowed only for static/non local functions
return contains(context.symbolStack, symbol); // it is type of the symbol uses itself recursively
}
}
}
function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
if (__conv_self__.isGenericMappedType(type)) {
return createMappedTypeNodeFromType(type);
}
const resolved = __conv_self__.resolveStructuredTypeMembers(type);
if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
return setEmitFlags(createTypeLiteralNode(/*members*/ undefined), EmitFlags.SingleLine);
}
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
const signature = resolved.callSignatures[0];
const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context);
return signatureNode;
}
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
const signature = resolved.constructSignatures[0];
const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context);
return signatureNode;
}
}
const savedFlags = context.flags;
context.flags |= NodeBuilderFlags.InObjectTypeLiteral;
const members = createTypeNodesFromResolvedType(resolved);
context.flags = savedFlags;
const typeLiteralNode = createTypeLiteralNode(members);
return setEmitFlags(typeLiteralNode, EmitFlags.SingleLine);
}
function createTypeQueryNodeFromSymbol(symbol: Symbol, symbolFlags: SymbolFlags) {
const entityName = symbolToName(symbol, context, symbolFlags, /*expectsIdentifier*/ false);
return createTypeQueryNode(entityName);
}
function symbolToTypeReferenceName(symbol: Symbol) {
// Unnamed function expressions and arrow functions have reserved names that we don't want to display
const entityName = symbol.flags & SymbolFlags.Class || !__conv_self__.isReservedMemberName(symbol.escapedName) ? symbolToName(symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false) : createIdentifier("");
return entityName;
}
function typeReferenceToTypeNode(type: TypeReference) {
const typeArguments: Type[] = type.typeArguments || emptyArray;
if (type.target === __conv_self__.globalArrayType) {
if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) {
const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context);
return createTypeReferenceNode("Array", [typeArgumentNode]);
}
const elementType = typeToTypeNodeHelper(typeArguments[0], context);
return createArrayTypeNode(elementType);
}
else if (type.target.objectFlags & ObjectFlags.Tuple) {
if (typeArguments.length > 0) {
const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, __conv_self__.getTypeReferenceArity(type)), context);
if (tupleConstituentNodes && tupleConstituentNodes.length > 0) {
return createTupleTypeNode(tupleConstituentNodes);
}
}
if (context.encounteredError || (context.flags & NodeBuilderFlags.AllowEmptyTuple)) {
return createTupleTypeNode([]);
}
context.encounteredError = true;
return undefined;
}
else {
const outerTypeParameters = type.target.outerTypeParameters;
let i = 0;
let qualifiedName: QualifiedName | undefined;
if (outerTypeParameters) {
const length = outerTypeParameters.length;
while (i < length) {
// Find group of type arguments for type parameters with the same declaring container.
const start = i;
const parent = __conv_self__.getParentSymbolOfTypeParameter(outerTypeParameters[i]);
do {
i++;
} while (i < length && __conv_self__.getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent);
// When type parameters are their own type arguments for the whole group (i.e. we have
// the default outer type arguments), we don't show the group.
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
const typeArgumentSlice = mapToTypeNodes(typeArguments.slice(start, i), context);
const typeArgumentNodes = typeArgumentSlice && createNodeArray(typeArgumentSlice);
const namePart = symbolToTypeReferenceName(parent);
(namePart.kind === SyntaxKind.Identifier ? namePart : namePart.right).typeArguments = typeArgumentNodes;
if (qualifiedName) {
Debug.assert(!qualifiedName.right);
qualifiedName = addToQualifiedNameMissingRightIdentifier(qualifiedName, namePart);
qualifiedName = createQualifiedName(qualifiedName, /*right*/ undefined);
}
else {
qualifiedName = createQualifiedName(namePart, /*right*/ undefined);
}
}
}
}
let entityName: EntityName = undefined;
const nameIdentifier = symbolToTypeReferenceName(type.symbol);
if (qualifiedName) {
Debug.assert(!qualifiedName.right);
qualifiedName = addToQualifiedNameMissingRightIdentifier(qualifiedName, nameIdentifier);
entityName = qualifiedName;
}
else {
entityName = nameIdentifier;
}
let typeArgumentNodes: ReadonlyArray | undefined;
if (typeArguments.length > 0) {
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
typeArgumentNodes = mapToTypeNodes(typeArguments.slice(i, typeParameterCount), context);
}
if (typeArgumentNodes) {
const lastIdentifier = entityName.kind === SyntaxKind.Identifier ? entityName : entityName.right;
lastIdentifier.typeArguments = undefined;
}
return createTypeReferenceNode(entityName, typeArgumentNodes);
}
}
function addToQualifiedNameMissingRightIdentifier(left: QualifiedName, right: Identifier | QualifiedName) {
Debug.assert(left.right === undefined);
if (right.kind === SyntaxKind.Identifier) {
left.right = right;
return left;
}
let rightPart = right;
while (rightPart.left.kind !== SyntaxKind.Identifier) {
rightPart = rightPart.left;
}
left.right = rightPart.left;
rightPart.left = left;
return right;
}
function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] {
const typeElements: TypeElement[] = [];
for (const signature of resolvedType.callSignatures) {
typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, context));
}
for (const signature of resolvedType.constructSignatures) {
typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, context));
}
if (resolvedType.stringIndexInfo) {
typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String, context));
}
if (resolvedType.numberIndexInfo) {
typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.numberIndexInfo, IndexKind.Number, context));
}
const properties = resolvedType.properties;
if (!properties) {
return typeElements;
}
for (const propertySymbol of properties) {
const propertyType = __conv_self__.getTypeOfSymbol(propertySymbol);
const saveEnclosingDeclaration = context.enclosingDeclaration;
context.enclosingDeclaration = undefined;
const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true);
context.enclosingDeclaration = saveEnclosingDeclaration;
const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined;
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !__conv_self__.getPropertiesOfObjectType(propertyType).length) {
const signatures = __conv_self__.getSignaturesOfType(propertyType, SignatureKind.Call);
for (const signature of signatures) {
const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context);
methodDeclaration.name = propertyName;
methodDeclaration.questionToken = optionalToken;
typeElements.push(methodDeclaration);
}
}
else {
const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
const modifiers = __conv_self__.isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined;
const propertySignature = createPropertySignature(modifiers, propertyName, optionalToken, propertyTypeNode,
/*initializer*/ undefined);
typeElements.push(propertySignature);
}
}
return typeElements.length ? typeElements : undefined;
}
}
function mapToTypeNodes(types: Type[], context: NodeBuilderContext): TypeNode[] {
if (some(types)) {
const result = [];
for (let i = 0; i < types.length; ++i) {
const type = types[i];
const typeNode = typeToTypeNodeHelper(type, context);
if (typeNode) {
result.push(typeNode);
}
}
return result;
}
}
function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration {
const name = getNameFromIndexInfo(indexInfo) || "x";
const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword);
const indexingParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined, name,
/*questionToken*/ undefined, indexerTypeNode,
/*initializer*/ undefined);
const typeNode = typeToTypeNodeHelper(indexInfo.type, context);
return createIndexSignature(
/*decorators*/ undefined, indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined, [indexingParameter], typeNode);
}
function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind, context: NodeBuilderContext): SignatureDeclaration {
const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context));
const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter, context));
if (signature.thisParameter) {
const thisParameter = symbolToParameterDeclaration(signature.thisParameter, context);
parameters.unshift(thisParameter);
}
let returnTypeNode: TypeNode;
if (signature.typePredicate) {
const typePredicate = signature.typePredicate;
const parameterName = typePredicate.kind === TypePredicateKind.Identifier ?
setEmitFlags(createIdentifier((typePredicate).parameterName), EmitFlags.NoAsciiEscaping) :
createThisTypeNode();
const typeNode = typeToTypeNodeHelper(typePredicate.type, context);
returnTypeNode = createTypePredicateNode(parameterName, typeNode);
}
else {
const returnType = __conv_self__.getReturnTypeOfSignature(signature);
returnTypeNode = returnType && typeToTypeNodeHelper(returnType, context);
}
if (context.flags & NodeBuilderFlags.SuppressAnyReturnType) {
if (returnTypeNode && returnTypeNode.kind === SyntaxKind.AnyKeyword) {
returnTypeNode = undefined;
}
}
else if (!returnTypeNode) {
returnTypeNode = createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNode);
}
function typeParameterToDeclaration(type: TypeParameter, context: NodeBuilderContext): TypeParameterDeclaration {
const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ true);
const constraint = __conv_self__.getConstraintFromTypeParameter(type);
const constraintNode = constraint && typeToTypeNodeHelper(constraint, context);
const defaultParameter = __conv_self__.getDefaultFromTypeParameter(type);
const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, context);
return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode);
}
function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext): ParameterDeclaration {
const parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter);
if (__conv_self__.isTransientSymbol(parameterSymbol) && parameterSymbol.isRestParameter) {
// special-case synthetic rest parameters in JS files
return createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined, parameterSymbol.isRestParameter ? createToken(SyntaxKind.DotDotDotToken) : undefined, "args",
/*questionToken*/ undefined, typeToTypeNodeHelper(__conv_self__.anyArrayType, context),
/*initializer*/ undefined);
}
const modifiers = parameterDeclaration.modifiers && parameterDeclaration.modifiers.map(getSynthesizedClone);
const dotDotDotToken = isRestParameter(parameterDeclaration) ? createToken(SyntaxKind.DotDotDotToken) : undefined;
const name = parameterDeclaration.name ?
parameterDeclaration.name.kind === SyntaxKind.Identifier ?
setEmitFlags(getSynthesizedClone(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) :
cloneBindingName(parameterDeclaration.name) :
unescapeLeadingUnderscores(parameterSymbol.escapedName);
const questionToken = __conv_self__.isOptionalParameter(parameterDeclaration) ? createToken(SyntaxKind.QuestionToken) : undefined;
let parameterType = __conv_self__.getTypeOfSymbol(parameterSymbol);
if (__conv_self__.isRequiredInitializedParameter(parameterDeclaration)) {
parameterType = __conv_self__.getNullableType(parameterType, TypeFlags.Undefined);
}
const parameterTypeNode = typeToTypeNodeHelper(parameterType, context);
const parameterNode = createParameter(
/*decorators*/ undefined, modifiers, dotDotDotToken, name, questionToken, parameterTypeNode,
/*initializer*/ undefined);
return parameterNode;
function cloneBindingName(node: BindingName): BindingName {
return elideInitializerAndSetEmitFlags(node);
function elideInitializerAndSetEmitFlags(node: Node): Node {
const visited = visitEachChild(node, elideInitializerAndSetEmitFlags, nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags);
const clone = nodeIsSynthesized(visited) ? visited : getSynthesizedClone(visited);
if (clone.kind === SyntaxKind.BindingElement) {
(clone).initializer = undefined;
}
return setEmitFlags(clone, EmitFlags.SingleLine | EmitFlags.NoAsciiEscaping);
}
}
}
function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: true): Identifier;
function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: false): EntityName;
function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: boolean): EntityName {
// Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration.
let chain: Symbol[];
const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter;
if (!isTypeParameter && (context.enclosingDeclaration || context.flags & NodeBuilderFlags.UseFullyQualifiedType)) {
chain = getSymbolChain(symbol, meaning, /*endOfChain*/ true);
Debug.assert(chain && chain.length > 0);
}
else {
chain = [symbol];
}
if (expectsIdentifier && chain.length !== 1
&& !context.encounteredError
&& !(context.flags & NodeBuilderFlags.AllowQualifedNameInPlaceOfIdentifier)) {
context.encounteredError = true;
}
return createEntityNameFromSymbolChain(chain, chain.length - 1);
function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName {
Debug.assert(chain && 0 <= index && index < chain.length);
const symbol = chain[index];
let typeParameterNodes: ReadonlyArray | undefined;
if (context.flags & NodeBuilderFlags.WriteTypeParametersInQualifiedName && index > 0) {
const parentSymbol = chain[index - 1];
let typeParameters: TypeParameter[];
if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
typeParameters = __conv_self__.getTypeParametersOfClassOrInterface(parentSymbol);
}
else {
const targetSymbol = __conv_self__.getTargetSymbol(parentSymbol);
if (targetSymbol.flags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeAlias)) {
typeParameters = __conv_self__.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
}
}
typeParameterNodes = mapToTypeNodes(typeParameters, context);
}
const symbolName = getNameOfSymbol(symbol, context);
const identifier = setEmitFlags(createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping);
return index > 0 ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier;
}
/** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */
function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined {
let accessibleSymbolChain = __conv_self__.getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/ false);
let parentSymbol: Symbol;
if (!accessibleSymbolChain ||
__conv_self__.needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : __conv_self__.getQualifiedLeftMeaning(meaning))) {
// Go up and add our parent.
const parent = __conv_self__.getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
if (parent) {
const parentChain = getSymbolChain(parent, __conv_self__.getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
if (parentChain) {
parentSymbol = parent;
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [symbol]);
}
}
}
if (accessibleSymbolChain) {
return accessibleSymbolChain;
}
if (
// If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols.
endOfChain ||
// If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.)
!(!parentSymbol && ts.forEach(symbol.declarations, __conv_self__.hasExternalModuleSymbol)) &&
// If a parent symbol is an anonymous type, don't write it.
!(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral))) {
return [symbol];
}
}
}
function getNameOfSymbol(symbol: Symbol, context: NodeBuilderContext): string {
const declaration = firstOrUndefined(symbol.declarations);
if (declaration) {
const name = getNameOfDeclaration(declaration);
if (name) {
return declarationNameToString(name);
}
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
return declarationNameToString((declaration.parent).name);
}
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) {
context.encounteredError = true;
}
switch (declaration.kind) {
case SyntaxKind.ClassExpression:
return "(Anonymous class)";
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return "(Anonymous function)";
}
}
return unescapeLeadingUnderscores(symbol.escapedName);
}
}
public typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Declaration, flags?: TypeFormatFlags): string {
const __conv_self__ = this;
return usingSingleLineStringWriter(writer => {
__conv_self__.getSymbolDisplayBuilder().buildTypePredicateDisplay(typePredicate, writer, enclosingDeclaration, flags);
});
}
public formatUnionTypes(types: Type[]): Type[] {
const result: Type[] = [];
let flags: TypeFlags = 0;
for (let i = 0; i < types.length; i++) {
const t = types[i];
flags |= t.flags;
if (!(t.flags & TypeFlags.Nullable)) {
if (t.flags & (TypeFlags.BooleanLiteral | TypeFlags.EnumLiteral)) {
const baseType = t.flags & TypeFlags.BooleanLiteral ? this.booleanType : this.getBaseTypeOfEnumLiteralType((t));
if (baseType.flags & TypeFlags.Union) {
const count = (baseType).types.length;
if (i + count <= types.length && types[i + count - 1] === (baseType).types[count - 1]) {
result.push(baseType);
i += count - 1;
continue;
}
}
}
result.push(t);
}
}
if (flags & TypeFlags.Null)
result.push(this.nullType);
if (flags & TypeFlags.Undefined)
result.push(this.undefinedType);
return result || types;
}
public visibilityToString(flags: ModifierFlags): string | undefined {
if (flags === ModifierFlags.Private) {
return "private";
}
if (flags === ModifierFlags.Protected) {
return "protected";
}
return "public";
}
public getTypeAliasForTypeLiteral(type: Type): Symbol {
if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral) {
const node = findAncestor(type.symbol.declarations[0].parent, n => n.kind !== SyntaxKind.ParenthesizedType);
if (node.kind === SyntaxKind.TypeAliasDeclaration) {
return this.getSymbolOfNode(node);
}
}
return undefined;
}
public isTopLevelInExternalModuleAugmentation(node: Node): boolean {
return node && node.parent &&
node.parent.kind === SyntaxKind.ModuleBlock &&
isExternalModuleAugmentation(node.parent.parent);
}
public literalTypeToString(type: LiteralType) {
return type.flags & TypeFlags.StringLiteral ? `"${escapeString((type).value)}"` : "" + (type).value;
}
public getNameOfSymbol(symbol: Symbol): string {
if (symbol.declarations && symbol.declarations.length) {
const declaration = symbol.declarations[0];
const name = getNameOfDeclaration(declaration);
if (name) {
return declarationNameToString(name);
}
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
return declarationNameToString((declaration.parent).name);
}
switch (declaration.kind) {
case SyntaxKind.ClassExpression:
return "(Anonymous class)";
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return "(Anonymous function)";
}
}
return unescapeLeadingUnderscores(symbol.escapedName);
}
public getSymbolDisplayBuilder(): SymbolDisplayBuilder {
const __conv_self__ = this;
/**
* Writes only the name of the symbol out to the writer. Uses the original source text
* for the name of the symbol if it is available to match how the user wrote the name.
*/
function appendSymbolNameOnly(symbol: Symbol, writer: SymbolWriter): void {
writer.writeSymbol(__conv_self__.getNameOfSymbol(symbol), symbol);
}
/**
* Writes a property access or element access with the name of the symbol out to the writer.
* Uses the original source text for the name of the symbol if it is available to match how the user wrote the name,
* ensuring that any names written with literals use element accesses.
*/
function appendPropertyOrElementAccessForSymbol(symbol: Symbol, writer: SymbolWriter): void {
const symbolName = __conv_self__.getNameOfSymbol(symbol);
const firstChar = symbolName.charCodeAt(0);
const needsElementAccess = !isIdentifierStart(firstChar, __conv_self__.languageVersion);
if (needsElementAccess) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBracketToken);
if (isSingleOrDoubleQuote(firstChar)) {
writer.writeStringLiteral(symbolName);
}
else {
writer.writeSymbol(symbolName, symbol);
}
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
else {
__conv_self__.writePunctuation(writer, SyntaxKind.DotToken);
writer.writeSymbol(symbolName, symbol);
}
}
/**
* Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope
* Meaning needs to be specified if the enclosing declaration is given
*/
function buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags, typeFlags?: TypeFormatFlags): void {
let parentSymbol: Symbol;
function appendParentTypeArgumentsAndSymbolName(symbol: Symbol): void {
if (parentSymbol) {
// Write type arguments of instantiated class/interface here
if (flags & SymbolFormatFlags.WriteTypeParametersOrArguments) {
if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
const params = __conv_self__.getTypeParametersOfClassOrInterface(parentSymbol.flags & SymbolFlags.Alias ? __conv_self__.resolveAlias(parentSymbol) : parentSymbol);
buildDisplayForTypeArgumentsAndDelimiters(params, (symbol).mapper, writer, enclosingDeclaration);
}
else {
buildTypeParameterDisplayFromSymbol(parentSymbol, writer, enclosingDeclaration);
}
}
appendPropertyOrElementAccessForSymbol(symbol, writer);
}
else {
appendSymbolNameOnly(symbol, writer);
}
parentSymbol = symbol;
}
// Let the writer know we just wrote out a symbol. The declaration emitter writer uses
// this to determine if an import it has previously seen (and not written out) needs
// to be written to the file once the walk of the tree is complete.
//
// NOTE(cyrusn): This approach feels somewhat unfortunate. A simple pass over the tree
// up front (for example, during checking) could determine if we need to emit the imports
// and we could then access that data during declaration emit.
writer.trackSymbol(symbol, enclosingDeclaration, meaning);
/** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */
function walkSymbol(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): void {
const accessibleSymbolChain = __conv_self__.getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, !!(flags & SymbolFormatFlags.UseOnlyExternalAliasing));
if (!accessibleSymbolChain ||
__conv_self__.needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : __conv_self__.getQualifiedLeftMeaning(meaning))) {
// Go up and add our parent.
const parent = __conv_self__.getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
if (parent) {
walkSymbol(parent, __conv_self__.getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
}
}
if (accessibleSymbolChain) {
for (const accessibleSymbol of accessibleSymbolChain) {
appendParentTypeArgumentsAndSymbolName(accessibleSymbol);
}
}
else if (
// If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols.
endOfChain ||
// If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.)
!(!parentSymbol && ts.forEach(symbol.declarations, __conv_self__.hasExternalModuleSymbol)) &&
// If a parent symbol is an anonymous type, don't write it.
!(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral))) {
appendParentTypeArgumentsAndSymbolName(symbol);
}
}
// Get qualified name if the symbol is not a type parameter
// and there is an enclosing declaration or we specifically
// asked for it
const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter;
const typeFormatFlag = TypeFormatFlags.UseFullyQualifiedType & typeFlags;
if (!isTypeParameter && (enclosingDeclaration || typeFormatFlag)) {
walkSymbol(symbol, meaning, /*endOfChain*/ true);
}
else {
appendParentTypeArgumentsAndSymbolName(symbol);
}
}
function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) {
const globalFlagsToPass = globalFlags & (TypeFormatFlags.WriteOwnNameForAnyLike | TypeFormatFlags.WriteClassExpressionAsTypeLiteral);
let inObjectTypeLiteral = false;
return writeType(type, globalFlags);
function writeType(type: Type, flags: TypeFormatFlags) {
const nextFlags = flags & ~TypeFormatFlags.InTypeAlias;
// Write undefined/null type as any
if (type.flags & TypeFlags.Intrinsic) {
// Special handling for unknown / resolving types, they should show up as any and not unknown or __resolving
writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && __conv_self__.isTypeAny(type)
? "any"
: (type).intrinsicName);
}
else if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) {
if (inObjectTypeLiteral) {
writer.reportInaccessibleThisError();
}
writer.writeKeyword("this");
}
else if (__conv_self__.getObjectFlags(type) & ObjectFlags.Reference) {
writeTypeReference(type, nextFlags);
}
else if (type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union)) {
const parent = __conv_self__.getParentOfSymbol(type.symbol);
buildSymbolDisplay(parent, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags);
// In a literal enum type with a single member E { A }, E and E.A denote the
// same type. We always display this type simply as E.
if (__conv_self__.getDeclaredTypeOfSymbol(parent) !== type) {
__conv_self__.writePunctuation(writer, SyntaxKind.DotToken);
appendSymbolNameOnly(type.symbol, writer);
}
}
else if (__conv_self__.getObjectFlags(type) & ObjectFlags.ClassOrInterface || type.flags & (TypeFlags.EnumLike | TypeFlags.TypeParameter)) {
// The specified symbol flags need to be reinterpreted as type flags
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags);
}
else if (!(flags & TypeFormatFlags.InTypeAlias) && type.aliasSymbol &&
__conv_self__.isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
const typeArguments = type.aliasTypeArguments;
writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, length(typeArguments), nextFlags);
}
else if (type.flags & TypeFlags.UnionOrIntersection) {
writeUnionOrIntersectionType(type, nextFlags);
}
else if (__conv_self__.getObjectFlags(type) & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
writeAnonymousType(type, nextFlags);
}
else if (type.flags & TypeFlags.StringOrNumberLiteral) {
writer.writeStringLiteral(__conv_self__.literalTypeToString((type)));
}
else if (type.flags & TypeFlags.Index) {
if (flags & TypeFormatFlags.InElementType) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenParenToken);
}
writer.writeKeyword("keyof");
__conv_self__.writeSpace(writer);
writeType((type).type, TypeFormatFlags.InElementType);
if (flags & TypeFormatFlags.InElementType) {
__conv_self__.writePunctuation(writer, SyntaxKind.CloseParenToken);
}
}
else if (type.flags & TypeFlags.IndexedAccess) {
writeType((type).objectType, TypeFormatFlags.InElementType);
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBracketToken);
writeType((type).indexType, TypeFormatFlags.None);
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
else {
// Should never get here
// { ... }
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBraceToken);
__conv_self__.writeSpace(writer);
__conv_self__.writePunctuation(writer, SyntaxKind.DotDotDotToken);
__conv_self__.writeSpace(writer);
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBraceToken);
}
}
function writeTypeList(types: Type[], delimiter: SyntaxKind) {
for (let i = 0; i < types.length; i++) {
if (i > 0) {
if (delimiter !== SyntaxKind.CommaToken) {
__conv_self__.writeSpace(writer);
}
__conv_self__.writePunctuation(writer, delimiter);
__conv_self__.writeSpace(writer);
}
writeType(types[i], delimiter === SyntaxKind.CommaToken ? TypeFormatFlags.None : TypeFormatFlags.InElementType);
}
}
function writeSymbolTypeReference(symbol: Symbol, typeArguments: Type[], pos: number, end: number, flags: TypeFormatFlags) {
// Unnamed function expressions and arrow functions have reserved names that we don't want to display
if (symbol.flags & SymbolFlags.Class || !__conv_self__.isReservedMemberName(symbol.escapedName)) {
buildSymbolDisplay(symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
}
if (pos < end) {
__conv_self__.writePunctuation(writer, SyntaxKind.LessThanToken);
writeType(typeArguments[pos], TypeFormatFlags.InFirstTypeArgument);
pos++;
while (pos < end) {
__conv_self__.writePunctuation(writer, SyntaxKind.CommaToken);
__conv_self__.writeSpace(writer);
writeType(typeArguments[pos], TypeFormatFlags.None);
pos++;
}
__conv_self__.writePunctuation(writer, SyntaxKind.GreaterThanToken);
}
}
function writeTypeReference(type: TypeReference, flags: TypeFormatFlags) {
const typeArguments = type.typeArguments || emptyArray;
if (type.target === __conv_self__.globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) {
writeType(typeArguments[0], TypeFormatFlags.InElementType | TypeFormatFlags.InArrayType);
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBracketToken);
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
else if (type.target.objectFlags & ObjectFlags.Tuple) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBracketToken);
writeTypeList(type.typeArguments.slice(0, __conv_self__.getTypeReferenceArity(type)), SyntaxKind.CommaToken);
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
else if (flags & TypeFormatFlags.WriteClassExpressionAsTypeLiteral &&
type.symbol.valueDeclaration &&
type.symbol.valueDeclaration.kind === SyntaxKind.ClassExpression) {
writeAnonymousType(__conv_self__.getDeclaredTypeOfClassOrInterface(type.symbol), flags);
}
else {
// Write the type reference in the format f.g.C where A and B are type arguments
// for outer type parameters, and f and g are the respective declaring containers of those
// type parameters.
const outerTypeParameters = type.target.outerTypeParameters;
let i = 0;
if (outerTypeParameters) {
const length = outerTypeParameters.length;
while (i < length) {
// Find group of type arguments for type parameters with the same declaring container.
const start = i;
const parent = __conv_self__.getParentSymbolOfTypeParameter(outerTypeParameters[i]);
do {
i++;
} while (i < length && __conv_self__.getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent);
// When type parameters are their own type arguments for the whole group (i.e. we have
// the default outer type arguments), we don't show the group.
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
writeSymbolTypeReference(parent, typeArguments, start, i, flags);
__conv_self__.writePunctuation(writer, SyntaxKind.DotToken);
}
}
}
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
writeSymbolTypeReference(type.symbol, typeArguments, i, typeParameterCount, flags);
}
}
function writeUnionOrIntersectionType(type: UnionOrIntersectionType, flags: TypeFormatFlags) {
if (flags & TypeFormatFlags.InElementType) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenParenToken);
}
if (type.flags & TypeFlags.Union) {
writeTypeList(__conv_self__.formatUnionTypes(type.types), SyntaxKind.BarToken);
}
else {
writeTypeList(type.types, SyntaxKind.AmpersandToken);
}
if (flags & TypeFormatFlags.InElementType) {
__conv_self__.writePunctuation(writer, SyntaxKind.CloseParenToken);
}
}
function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) {
const symbol = type.symbol;
if (symbol) {
// Always use 'typeof T' for type of class, enum, and module objects
if (symbol.flags & SymbolFlags.Class &&
!__conv_self__.getBaseTypeVariableOfClass(symbol) &&
!(symbol.valueDeclaration.kind === SyntaxKind.ClassExpression && flags & TypeFormatFlags.WriteClassExpressionAsTypeLiteral) ||
symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule)) {
writeTypeOfSymbol(type, flags);
}
else if (shouldWriteTypeOfFunctionSymbol()) {
writeTypeOfSymbol(type, flags);
}
else if (contains(symbolStack, symbol)) {
// If type is an anonymous type literal in a type alias declaration, use type alias name
const typeAlias = __conv_self__.getTypeAliasForTypeLiteral(type);
if (typeAlias) {
// The specified symbol flags need to be reinterpreted as type flags
buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
}
else {
// Recursive usage, use any
__conv_self__.writeKeyword(writer, SyntaxKind.AnyKeyword);
}
}
else {
// Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
// of types allows us to catch circular references to instantiations of the same anonymous type
// However, in case of class expressions, we want to write both the static side and the instance side.
// We skip adding the static side so that the instance side has a chance to be written
// before checking for circular references.
if (!symbolStack) {
symbolStack = [];
}
const isConstructorObject = type.objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class;
if (isConstructorObject) {
writeLiteralType(type, flags);
}
else {
symbolStack.push(symbol);
writeLiteralType(type, flags);
symbolStack.pop();
}
}
}
else {
// Anonymous types with no symbol are never circular
writeLiteralType(type, flags);
}
function shouldWriteTypeOfFunctionSymbol() {
const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) &&
some(symbol.declarations, declaration => hasModifier(declaration, ModifierFlags.Static));
const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) &&
(symbol.parent ||
some(symbol.declarations, declaration => declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
// typeof is allowed only for static/non local functions
return !!(flags & TypeFormatFlags.UseTypeOfFunction) ||
contains(symbolStack, symbol); // it is type of the symbol uses itself recursively
}
}
}
function writeTypeOfSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) {
if (typeFormatFlags & TypeFormatFlags.InArrayType) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenParenToken);
}
__conv_self__.writeKeyword(writer, SyntaxKind.TypeOfKeyword);
__conv_self__.writeSpace(writer);
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags);
if (typeFormatFlags & TypeFormatFlags.InArrayType) {
__conv_self__.writePunctuation(writer, SyntaxKind.CloseParenToken);
}
}
function writePropertyWithModifiers(prop: Symbol) {
if (__conv_self__.isReadonlySymbol(prop)) {
__conv_self__.writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
__conv_self__.writeSpace(writer);
}
buildSymbolDisplay(prop, writer);
if (prop.flags & SymbolFlags.Optional) {
__conv_self__.writePunctuation(writer, SyntaxKind.QuestionToken);
}
}
function shouldAddParenthesisAroundFunctionType(callSignature: Signature, flags: TypeFormatFlags) {
if (flags & TypeFormatFlags.InElementType) {
return true;
}
else if (flags & TypeFormatFlags.InFirstTypeArgument) {
// Add parenthesis around function type for the first type argument to avoid ambiguity
const typeParameters = callSignature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature) ?
callSignature.target.typeParameters : callSignature.typeParameters;
return typeParameters && typeParameters.length !== 0;
}
return false;
}
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
if (__conv_self__.isGenericMappedType(type)) {
writeMappedType(type);
return;
}
const resolved = __conv_self__.resolveStructuredTypeMembers(type);
if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBraceToken);
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBraceToken);
return;
}
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
const parenthesizeSignature = shouldAddParenthesisAroundFunctionType(resolved.callSignatures[0], flags);
if (parenthesizeSignature) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenParenToken);
}
buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
if (parenthesizeSignature) {
__conv_self__.writePunctuation(writer, SyntaxKind.CloseParenToken);
}
return;
}
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
if (flags & TypeFormatFlags.InElementType) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenParenToken);
}
__conv_self__.writeKeyword(writer, SyntaxKind.NewKeyword);
__conv_self__.writeSpace(writer);
buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
if (flags & TypeFormatFlags.InElementType) {
__conv_self__.writePunctuation(writer, SyntaxKind.CloseParenToken);
}
return;
}
}
const saveInObjectTypeLiteral = inObjectTypeLiteral;
inObjectTypeLiteral = true;
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBraceToken);
writer.writeLine();
writer.increaseIndent();
writeObjectLiteralType(resolved);
writer.decreaseIndent();
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBraceToken);
inObjectTypeLiteral = saveInObjectTypeLiteral;
}
function writeObjectLiteralType(resolved: ResolvedType) {
for (const signature of resolved.callSignatures) {
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
__conv_self__.writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
for (const signature of resolved.constructSignatures) {
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, SignatureKind.Construct, symbolStack);
__conv_self__.writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
buildIndexSignatureDisplay(resolved.stringIndexInfo, writer, IndexKind.String, enclosingDeclaration, globalFlags, symbolStack);
buildIndexSignatureDisplay(resolved.numberIndexInfo, writer, IndexKind.Number, enclosingDeclaration, globalFlags, symbolStack);
for (const p of resolved.properties) {
if (globalFlags & TypeFormatFlags.WriteClassExpressionAsTypeLiteral) {
if (p.flags & SymbolFlags.Prototype) {
continue;
}
if (getDeclarationModifierFlagsFromSymbol(p) & (ModifierFlags.Private | ModifierFlags.Protected)) {
writer.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(p.escapedName));
}
}
const t = __conv_self__.getTypeOfSymbol(p);
if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !__conv_self__.getPropertiesOfObjectType(t).length) {
const signatures = __conv_self__.getSignaturesOfType(t, SignatureKind.Call);
for (const signature of signatures) {
writePropertyWithModifiers(p);
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
__conv_self__.writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
}
else {
writePropertyWithModifiers(p);
__conv_self__.writePunctuation(writer, SyntaxKind.ColonToken);
__conv_self__.writeSpace(writer);
writeType(t, globalFlags & TypeFormatFlags.WriteClassExpressionAsTypeLiteral);
__conv_self__.writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
}
}
function writeMappedType(type: MappedType) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBraceToken);
writer.writeLine();
writer.increaseIndent();
if (type.declaration.readonlyToken) {
__conv_self__.writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
__conv_self__.writeSpace(writer);
}
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBracketToken);
appendSymbolNameOnly(__conv_self__.getTypeParameterFromMappedType(type).symbol, writer);
__conv_self__.writeSpace(writer);
__conv_self__.writeKeyword(writer, SyntaxKind.InKeyword);
__conv_self__.writeSpace(writer);
writeType(__conv_self__.getConstraintTypeFromMappedType(type), TypeFormatFlags.None);
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBracketToken);
if (type.declaration.questionToken) {
__conv_self__.writePunctuation(writer, SyntaxKind.QuestionToken);
}
__conv_self__.writePunctuation(writer, SyntaxKind.ColonToken);
__conv_self__.writeSpace(writer);
writeType(__conv_self__.getTemplateTypeFromMappedType(type), TypeFormatFlags.None);
__conv_self__.writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
writer.decreaseIndent();
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBraceToken);
}
}
function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) {
const targetSymbol = __conv_self__.getTargetSymbol(symbol);
if (targetSymbol.flags & SymbolFlags.Class || targetSymbol.flags & SymbolFlags.Interface || targetSymbol.flags & SymbolFlags.TypeAlias) {
buildDisplayForTypeParametersAndDelimiters(__conv_self__.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), writer, enclosingDeclaration, flags);
}
}
function buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
appendSymbolNameOnly(tp.symbol, writer);
const constraint = __conv_self__.getConstraintOfTypeParameter(tp);
if (constraint) {
__conv_self__.writeSpace(writer);
__conv_self__.writeKeyword(writer, SyntaxKind.ExtendsKeyword);
__conv_self__.writeSpace(writer);
buildTypeDisplay(constraint, writer, enclosingDeclaration, flags, symbolStack);
}
const defaultType = __conv_self__.getDefaultFromTypeParameter(tp);
if (defaultType) {
__conv_self__.writeSpace(writer);
__conv_self__.writePunctuation(writer, SyntaxKind.EqualsToken);
__conv_self__.writeSpace(writer);
buildTypeDisplay(defaultType, writer, enclosingDeclaration, flags, symbolStack);
}
}
function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
const parameterNode = p.valueDeclaration;
if (parameterNode ? isRestParameter(parameterNode) : __conv_self__.isTransientSymbol(p) && p.isRestParameter) {
__conv_self__.writePunctuation(writer, SyntaxKind.DotDotDotToken);
}
if (parameterNode && isBindingPattern(parameterNode.name)) {
buildBindingPatternDisplay(parameterNode.name, writer, enclosingDeclaration, flags, symbolStack);
}
else {
appendSymbolNameOnly(p, writer);
}
if (parameterNode && __conv_self__.isOptionalParameter(parameterNode)) {
__conv_self__.writePunctuation(writer, SyntaxKind.QuestionToken);
}
__conv_self__.writePunctuation(writer, SyntaxKind.ColonToken);
__conv_self__.writeSpace(writer);
let type = __conv_self__.getTypeOfSymbol(p);
if (parameterNode && __conv_self__.isRequiredInitializedParameter(parameterNode)) {
type = __conv_self__.getNullableType(type, TypeFlags.Undefined);
}
buildTypeDisplay(type, writer, enclosingDeclaration, flags, symbolStack);
}
function buildBindingPatternDisplay(bindingPattern: BindingPattern, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
// We have to explicitly emit square bracket and bracket because these tokens are not stored inside the node.
if (bindingPattern.kind === SyntaxKind.ObjectBindingPattern) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBraceToken);
buildDisplayForCommaSeparatedList(bindingPattern.elements, writer, e => buildBindingElementDisplay(e, writer, enclosingDeclaration, flags, symbolStack));
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBraceToken);
}
else if (bindingPattern.kind === SyntaxKind.ArrayBindingPattern) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBracketToken);
const elements = bindingPattern.elements;
buildDisplayForCommaSeparatedList(elements, writer, e => buildBindingElementDisplay(e, writer, enclosingDeclaration, flags, symbolStack));
if (elements && elements.hasTrailingComma) {
__conv_self__.writePunctuation(writer, SyntaxKind.CommaToken);
}
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
}
function buildBindingElementDisplay(bindingElement: ArrayBindingElement, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
if (isOmittedExpression(bindingElement)) {
return;
}
Debug.assert(bindingElement.kind === SyntaxKind.BindingElement);
if (bindingElement.propertyName) {
writer.writeProperty(getTextOfNode(bindingElement.propertyName));
__conv_self__.writePunctuation(writer, SyntaxKind.ColonToken);
__conv_self__.writeSpace(writer);
}
if (isBindingPattern(bindingElement.name)) {
buildBindingPatternDisplay(bindingElement.name, writer, enclosingDeclaration, flags, symbolStack);
}
else {
if (bindingElement.dotDotDotToken) {
__conv_self__.writePunctuation(writer, SyntaxKind.DotDotDotToken);
}
appendSymbolNameOnly(bindingElement.symbol, writer);
}
}
function buildDisplayForTypeParametersAndDelimiters(typeParameters: ReadonlyArray, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
if (typeParameters && typeParameters.length) {
__conv_self__.writePunctuation(writer, SyntaxKind.LessThanToken);
buildDisplayForCommaSeparatedList(typeParameters, writer, p => buildTypeParameterDisplay(p, writer, enclosingDeclaration, flags, symbolStack));
__conv_self__.writePunctuation(writer, SyntaxKind.GreaterThanToken);
}
}
function buildDisplayForCommaSeparatedList(list: ReadonlyArray, writer: SymbolWriter, action: (item: T) => void) {
for (let i = 0; i < list.length; i++) {
if (i > 0) {
__conv_self__.writePunctuation(writer, SyntaxKind.CommaToken);
__conv_self__.writeSpace(writer);
}
action(list[i]);
}
}
function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: ReadonlyArray, mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node) {
if (typeParameters && typeParameters.length) {
__conv_self__.writePunctuation(writer, SyntaxKind.LessThanToken);
let flags = TypeFormatFlags.InFirstTypeArgument;
for (let i = 0; i < typeParameters.length; i++) {
if (i > 0) {
__conv_self__.writePunctuation(writer, SyntaxKind.CommaToken);
__conv_self__.writeSpace(writer);
flags = TypeFormatFlags.None;
}
buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, flags);
}
__conv_self__.writePunctuation(writer, SyntaxKind.GreaterThanToken);
}
}
function buildDisplayForParametersAndDelimiters(thisParameter: Symbol | undefined, parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
__conv_self__.writePunctuation(writer, SyntaxKind.OpenParenToken);
if (thisParameter) {
buildParameterDisplay(thisParameter, writer, enclosingDeclaration, flags, symbolStack);
}
for (let i = 0; i < parameters.length; i++) {
if (i > 0 || thisParameter) {
__conv_self__.writePunctuation(writer, SyntaxKind.CommaToken);
__conv_self__.writeSpace(writer);
}
buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, symbolStack);
}
__conv_self__.writePunctuation(writer, SyntaxKind.CloseParenToken);
}
function buildTypePredicateDisplay(predicate: TypePredicate, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]): void {
if (isIdentifierTypePredicate(predicate)) {
writer.writeParameter(predicate.parameterName);
}
else {
__conv_self__.writeKeyword(writer, SyntaxKind.ThisKeyword);
}
__conv_self__.writeSpace(writer);
__conv_self__.writeKeyword(writer, SyntaxKind.IsKeyword);
__conv_self__.writeSpace(writer);
buildTypeDisplay(predicate.type, writer, enclosingDeclaration, flags, symbolStack);
}
function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
const returnType = __conv_self__.getReturnTypeOfSignature(signature);
if (flags & TypeFormatFlags.SuppressAnyReturnType && __conv_self__.isTypeAny(returnType)) {
return;
}
if (flags & TypeFormatFlags.WriteArrowStyleSignature) {
__conv_self__.writeSpace(writer);
__conv_self__.writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken);
}
else {
__conv_self__.writePunctuation(writer, SyntaxKind.ColonToken);
}
__conv_self__.writeSpace(writer);
if (signature.typePredicate) {
buildTypePredicateDisplay(signature.typePredicate, writer, enclosingDeclaration, flags, symbolStack);
}
else {
buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack);
}
}
function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind, symbolStack?: Symbol[]) {
if (kind === SignatureKind.Construct) {
__conv_self__.writeKeyword(writer, SyntaxKind.NewKeyword);
__conv_self__.writeSpace(writer);
}
if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) {
// Instantiated signature, write type arguments instead
// This is achieved by passing in the mapper separately
buildDisplayForTypeArgumentsAndDelimiters(signature.target.typeParameters, signature.mapper, writer, enclosingDeclaration);
}
else {
buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, symbolStack);
}
buildDisplayForParametersAndDelimiters(signature.thisParameter, signature.parameters, writer, enclosingDeclaration, flags, symbolStack);
buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, symbolStack);
}
function buildIndexSignatureDisplay(info: IndexInfo, writer: SymbolWriter, kind: IndexKind, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) {
if (info) {
if (info.isReadonly) {
__conv_self__.writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
__conv_self__.writeSpace(writer);
}
__conv_self__.writePunctuation(writer, SyntaxKind.OpenBracketToken);
writer.writeParameter(info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : "x");
__conv_self__.writePunctuation(writer, SyntaxKind.ColonToken);
__conv_self__.writeSpace(writer);
switch (kind) {
case IndexKind.Number:
__conv_self__.writeKeyword(writer, SyntaxKind.NumberKeyword);
break;
case IndexKind.String:
__conv_self__.writeKeyword(writer, SyntaxKind.StringKeyword);
break;
}
__conv_self__.writePunctuation(writer, SyntaxKind.CloseBracketToken);
__conv_self__.writePunctuation(writer, SyntaxKind.ColonToken);
__conv_self__.writeSpace(writer);
buildTypeDisplay(info.type, writer, enclosingDeclaration, globalFlags, symbolStack);
__conv_self__.writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
}
return this._displayBuilder || (this._displayBuilder = {
buildSymbolDisplay,
buildTypeDisplay,
buildTypeParameterDisplay,
buildTypePredicateDisplay,
buildParameterDisplay,
buildDisplayForParametersAndDelimiters,
buildDisplayForTypeParametersAndDelimiters,
buildTypeParameterDisplayFromSymbol,
buildSignatureDisplay,
buildIndexSignatureDisplay,
buildReturnTypeDisplay
});
}
public isDeclarationVisible(node: Declaration): boolean {
const __conv_self__ = this;
if (node) {
const links = this.getNodeLinks(node);
if (links.isVisible === undefined) {
links.isVisible = !!determineIfDeclarationIsVisible();
}
return links.isVisible;
}
return false;
function determineIfDeclarationIsVisible() {
switch (node.kind) {
case SyntaxKind.BindingElement:
return __conv_self__.isDeclarationVisible((node.parent.parent));
case SyntaxKind.VariableDeclaration:
if (isBindingPattern((node as VariableDeclaration).name) &&
!((node as VariableDeclaration).name as BindingPattern).elements.length) {
// If the binding pattern is empty, this variable declaration is not visible
return false;
}
// falls through
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ImportEqualsDeclaration:
// external module augmentation is always visible
if (isExternalModuleAugmentation(node)) {
return true;
}
const parent = __conv_self__.getDeclarationContainer(node);
// If the node is not exported or it is not ambient module element (except import declaration)
if (!(getCombinedModifierFlags(node) & ModifierFlags.Export) &&
!(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) {
return __conv_self__.isGlobalSourceFile(parent);
}
// Exported members/ambient module elements (exception import declaration) are visible if parent is visible
return __conv_self__.isDeclarationVisible((parent));
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
if (hasModifier(node, ModifierFlags.Private | ModifierFlags.Protected)) {
// Private/protected properties/methods are not visible
return false;
}
// Public properties/methods are visible if its parents are visible, so:
// falls through
case SyntaxKind.Constructor:
case SyntaxKind.ConstructSignature:
case SyntaxKind.CallSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.Parameter:
case SyntaxKind.ModuleBlock:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.TypeLiteral:
case SyntaxKind.TypeReference:
case SyntaxKind.ArrayType:
case SyntaxKind.TupleType:
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
case SyntaxKind.ParenthesizedType:
return __conv_self__.isDeclarationVisible((node.parent));
// Default binding, import specifier and namespace import is visible
// only on demand so by default it is not visible
case SyntaxKind.ImportClause:
case SyntaxKind.NamespaceImport:
case SyntaxKind.ImportSpecifier:
return false;
// Type parameters are always visible
case SyntaxKind.TypeParameter:
// Source file and namespace export are always visible
case SyntaxKind.SourceFile:
case SyntaxKind.NamespaceExportDeclaration:
return true;
// Export assignments do not create name bindings outside the module
case SyntaxKind.ExportAssignment:
return false;
default:
return false;
}
}
}
public collectLinkedAliases(node: Identifier): Node[] {
const __conv_self__ = this;
let exportSymbol: Symbol;
if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) {
exportSymbol = this.resolveName(node.parent, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, Diagnostics.Cannot_find_name_0, node);
}
else if (node.parent.kind === SyntaxKind.ExportSpecifier) {
exportSymbol = this.getTargetOfExportSpecifier((node.parent), SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias);
}
const result: Node[] = [];
if (exportSymbol) {
buildVisibleNodeList(exportSymbol.declarations);
}
return result;
function buildVisibleNodeList(declarations: Declaration[]) {
forEach(declarations, declaration => {
__conv_self__.getNodeLinks(declaration).isVisible = true;
const resultNode = __conv_self__.getAnyImportSyntax(declaration) || declaration;
if (!contains(result, resultNode)) {
result.push(resultNode);
}
if (isInternalModuleImportEqualsDeclaration(declaration)) {
// Add the referenced top container visible
const internalModuleReference = (declaration).moduleReference;
const firstIdentifier = __conv_self__.getFirstIdentifier(internalModuleReference);
const importSymbol = __conv_self__.resolveName(declaration, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, undefined, undefined);
if (importSymbol) {
buildVisibleNodeList(importSymbol.declarations);
}
}
});
}
}
/**
* Push an entry on the type resolution stack. If an entry with the given target and the given property name
* is already on the stack, and no entries in between already have a type, then a circularity has occurred.
* In this case, the result values of the existing entry and all entries pushed after it are changed to false,
* and the value false is returned. Otherwise, the new entry is just pushed onto the stack, and true is returned.
* In order to see if the same query has already been done before, the target object and the propertyName both
* must match the one passed in.
*
* @param target The symbol, type, or signature whose type is being queried
* @param propertyName The property name that should be used to query the target for its type
*/
public pushTypeResolution(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean {
const resolutionCycleStartIndex = this.findResolutionCycleStartIndex(target, propertyName);
if (resolutionCycleStartIndex >= 0) {
// A cycle was found
const { length } = this.resolutionTargets;
for (let i = resolutionCycleStartIndex; i < length; i++) {
this.resolutionResults[i] = false;
}
return false;
}
this.resolutionTargets.push(target);
this.resolutionResults.push(/*items*/ true);
this.resolutionPropertyNames.push(propertyName);
return true;
}
public findResolutionCycleStartIndex(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): number {
for (let i = this.resolutionTargets.length - 1; i >= 0; i--) {
if (this.hasType(this.resolutionTargets[i], this.resolutionPropertyNames[i])) {
return -1;
}
if (this.resolutionTargets[i] === target && this.resolutionPropertyNames[i] === propertyName) {
return i;
}
}
return -1;
}
public hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): Type {
if (propertyName === TypeSystemPropertyName.Type) {
return this.getSymbolLinks((target)).type;
}
if (propertyName === TypeSystemPropertyName.DeclaredType) {
return this.getSymbolLinks((target)).declaredType;
}
if (propertyName === TypeSystemPropertyName.ResolvedBaseConstructorType) {
return (target).resolvedBaseConstructorType;
}
if (propertyName === TypeSystemPropertyName.ResolvedReturnType) {
return (target).resolvedReturnType;
}
Debug.fail("Unhandled TypeSystemPropertyName " + propertyName);
}
// Pop an entry from the type resolution stack and return its associated result value. The result value will
// be true if no circularities were detected, or false if a circularity was found.
public popTypeResolution(): boolean {
this.resolutionTargets.pop();
this.resolutionPropertyNames.pop();
return this.resolutionResults.pop();
}
public getDeclarationContainer(node: Node): Node {
node = findAncestor(getRootDeclaration(node), node => {
switch (node.kind) {
case SyntaxKind.VariableDeclaration:
case SyntaxKind.VariableDeclarationList:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.NamedImports:
case SyntaxKind.NamespaceImport:
case SyntaxKind.ImportClause:
return false;
default:
return true;
}
});
return node && node.parent;
}
public getTypeOfPrototypeProperty(prototype: Symbol): Type {
const __conv_self__ = this;
// TypeScript 1.0 spec (April 2014): 8.4
// Every class automatically contains a static property member named 'prototype',
// the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter.
// It is an error to explicitly declare a static property member with the name 'prototype'.
const classType = (this.getDeclaredTypeOfSymbol(this.getParentOfSymbol(prototype)));
return classType.typeParameters ? this.createTypeReference((classType), map(classType.typeParameters, _ => __conv_self__.anyType)) : classType;
}
// Return the type of the given property in the given type, or undefined if no such property exists
public getTypeOfPropertyOfType(type: Type, name: __String): Type {
const prop = this.getPropertyOfType(type, name);
return prop ? this.getTypeOfSymbol(prop) : undefined;
}
public isTypeAny(type: Type) {
return type && (type.flags & TypeFlags.Any) !== 0;
}
// Return the type of a binding element parent. We check SymbolLinks first to see if a type has been
// assigned by contextual typing.
public getTypeForBindingElementParent(node: VariableLikeDeclaration) {
const symbol = this.getSymbolOfNode(node);
return symbol && this.getSymbolLinks(symbol).type || this.getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false);
}
public isComputedNonLiteralName(name: PropertyName): boolean {
return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((name).expression);
}
public getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type {
const __conv_self__ = this;
source = this.filterType(source, t => !(t.flags & TypeFlags.Nullable));
if (source.flags & TypeFlags.Never) {
return this.emptyObjectType;
}
if (source.flags & TypeFlags.Union) {
return this.mapType(source, t => __conv_self__.getRestType(t, properties, symbol));
}
const members = createSymbolTable();
const names = createUnderscoreEscapedMap();
for (const name of properties) {
names.set(getTextOfPropertyName(name), true);
}
for (const prop of this.getPropertiesOfType(source)) {
const inNamesToRemove = names.has(prop.escapedName);
const isPrivate = getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected);
const isSetOnlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
if (!inNamesToRemove && !isPrivate && !this.isClassMethod(prop) && !isSetOnlyAccessor) {
members.set(prop.escapedName, prop);
}
}
const stringIndexInfo = this.getIndexInfoOfType(source, IndexKind.String);
const numberIndexInfo = this.getIndexInfoOfType(source, IndexKind.Number);
return this.createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
}
/** Return the inferred type for a binding element */
public getTypeForBindingElement(declaration: BindingElement): Type {
const pattern = declaration.parent;
const parentType = this.getTypeForBindingElementParent(pattern.parent);
// If parent has the unknown (error) type, then so does this binding element
if (parentType === this.unknownType) {
return this.unknownType;
}
// If no type was specified or inferred for parent, or if the specified or inferred type is any,
// infer from the initializer of the binding element if one is present. Otherwise, go with the
// undefined or any type of the parent.
if (!parentType || this.isTypeAny(parentType)) {
if (declaration.initializer) {
return this.checkDeclarationInitializer(declaration);
}
return parentType;
}
let type: Type;
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
if (declaration.dotDotDotToken) {
if (!this.isValidSpreadType(parentType)) {
this.error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types);
return this.unknownType;
}
const literalMembers: PropertyName[] = [];
for (const element of pattern.elements) {
if (!(element as BindingElement).dotDotDotToken) {
literalMembers.push(element.propertyName || element.name as Identifier);
}
}
type = this.getRestType(parentType, literalMembers, declaration.symbol);
}
else {
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
const name = declaration.propertyName || declaration.name;
if (this.isComputedNonLiteralName(name)) {
// computed properties with non-literal names are treated as 'any'
return this.anyType;
}
if (declaration.initializer) {
this.getContextualType(declaration.initializer);
}
// Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
// or otherwise the type of the string index signature.
const text = getTextOfPropertyName(name);
const declaredType = this.getTypeOfPropertyOfType(parentType, text);
type = declaredType && this.getFlowTypeOfReference(declaration, declaredType) ||
this.isNumericLiteralName(text) && this.getIndexTypeOfType(parentType, IndexKind.Number) ||
this.getIndexTypeOfType(parentType, IndexKind.String);
if (!type) {
this.error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, this.typeToString(parentType), declarationNameToString(name));
return this.unknownType;
}
}
}
else {
// This elementType will be used if the specific property corresponding to this index is not
// present (aka the tuple element property). This call also checks that the parentType is in
// fact an iterable or array (depending on target language).
const elementType = this.checkIteratedTypeOrElementType(parentType, pattern, /*allowStringInput*/ false, /*allowAsyncIterables*/ false);
if (declaration.dotDotDotToken) {
// Rest element has an array type with the same element type as the parent type
type = this.createArrayType(elementType);
}
else {
// Use specific property type when parent is a tuple or numeric index type when parent is an array
const propName = "" + indexOf(pattern.elements, declaration);
type = this.isTupleLikeType(parentType)
? this.getTypeOfPropertyOfType(parentType, (propName as __String))
: elementType;
if (!type) {
if (this.isTupleType(parentType)) {
this.error(declaration, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, this.typeToString(parentType), this.getTypeReferenceArity((parentType)), pattern.elements.length);
}
else {
this.error(declaration, Diagnostics.Type_0_has_no_property_1, this.typeToString(parentType), propName);
}
return this.unknownType;
}
}
}
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
// undefined from the final type.
if (this.strictNullChecks && declaration.initializer && !(this.getFalsyFlags(this.checkExpressionCached(declaration.initializer)) & TypeFlags.Undefined)) {
type = this.getTypeWithFacts(type, TypeFacts.NEUndefined);
}
return declaration.initializer ?
this.getUnionType([type, this.checkExpressionCached(declaration.initializer)], /*subtypeReduction*/ true) :
type;
}
public getTypeForDeclarationFromJSDocComment(declaration: Node) {
const jsdocType = getJSDocType(declaration);
if (jsdocType) {
return this.getTypeFromTypeNode(jsdocType);
}
return undefined;
}
public isNullOrUndefined(node: Expression) {
const expr = skipParentheses(node);
return expr.kind === SyntaxKind.NullKeyword || expr.kind === SyntaxKind.Identifier && this.getResolvedSymbol((expr)) === this.undefinedSymbol;
}
public isEmptyArrayLiteral(node: Expression) {
const expr = skipParentheses(node);
return expr.kind === SyntaxKind.ArrayLiteralExpression && (expr).elements.length === 0;
}
public addOptionality(type: Type, optional: boolean): Type {
return this.strictNullChecks && optional ? this.getNullableType(type, TypeFlags.Undefined) : type;
}
// Return the inferred type for a variable, parameter, or property declaration
public getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, includeOptionality: boolean): Type {
// A variable declared in a for..in statement is of type string, or of type keyof T when the
// right hand expression is of a type parameter type.
if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) {
const indexType = this.getIndexType(this.checkNonNullExpression((declaration.parent.parent).expression));
return indexType.flags & (TypeFlags.TypeParameter | TypeFlags.Index) ? indexType : this.stringType;
}
if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
// checkRightHandSideOfForOf will return undefined if the for-of expression type was
// missing properties/signatures required to get its iteratedType (like
// [Symbol.iterator] or next). This may be because we accessed properties from anyType,
// or it may have led to an error inside getElementTypeOfIterable.
const forOfStatement = declaration.parent.parent;
return this.checkRightHandSideOfForOf(forOfStatement.expression, forOfStatement.awaitModifier) || this.anyType;
}
if (isBindingPattern(declaration.parent)) {
return this.getTypeForBindingElement((declaration));
}
// Use type from type annotation if one is present
const typeNode = getEffectiveTypeAnnotationNode(declaration);
if (typeNode) {
const declaredType = this.getTypeFromTypeNode(typeNode);
return this.addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality);
}
if ((this.noImplicitAny || isInJavaScriptFile(declaration)) &&
declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) &&
!(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !isInAmbientContext(declaration)) {
// If --noImplicitAny is on or the declaration is in a Javascript file,
// use control flow tracked 'any' type for non-ambient, non-exported var or let variables with no
// initializer or a 'null' or 'undefined' initializer.
if (!(getCombinedNodeFlags(declaration) & NodeFlags.Const) && (!declaration.initializer || this.isNullOrUndefined(declaration.initializer))) {
return this.autoType;
}
// Use control flow tracked 'any[]' type for non-ambient, non-exported variables with an empty array
// literal initializer.
if (declaration.initializer && this.isEmptyArrayLiteral(declaration.initializer)) {
return this.autoArrayType;
}
}
if (declaration.kind === SyntaxKind.Parameter) {
const func = declaration.parent;
// For a parameter of a set accessor, use the type of the get accessor if one is present
if (func.kind === SyntaxKind.SetAccessor && !hasDynamicName(func)) {
const getter = getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor);
if (getter) {
const getterSignature = this.getSignatureFromDeclaration(getter);
const thisParameter = this.getAccessorThisParameter((func as AccessorDeclaration));
if (thisParameter && declaration === thisParameter) {
// Use the type from the *getter*
Debug.assert(!thisParameter.type);
return this.getTypeOfSymbol(getterSignature.thisParameter);
}
return this.getReturnTypeOfSignature(getterSignature);
}
}
// Use contextual parameter type if one is available
let type: Type;
if (declaration.symbol.escapedName === "this") {
type = this.getContextualThisParameterType(func);
}
else {
type = this.getContextuallyTypedParameterType((declaration));
}
if (type) {
return this.addOptionality(type, /*optional*/ declaration.questionToken && includeOptionality);
}
}
// Use the type of the initializer expression if one is present
if (declaration.initializer) {
const type = this.checkDeclarationInitializer(declaration);
return this.addOptionality(type, /*optional*/ declaration.questionToken && includeOptionality);
}
if (isJsxAttribute(declaration)) {
// if JSX attribute doesn't have initializer, by default the attribute will have boolean value of true.
// I.e is sugar for
return this.trueType;
}
// If it is a short-hand property assignment, use the type of the identifier
if (declaration.kind === SyntaxKind.ShorthandPropertyAssignment) {
return this.checkIdentifier((declaration.name));
}
// If the declaration specifies a binding pattern, use the type implied by the binding pattern
if (isBindingPattern(declaration.name)) {
return this.getTypeFromBindingPattern((declaration.name), /*includePatternInType*/ false, /*reportErrors*/ true);
}
// No type specified and nothing can be inferred
return undefined;
}
public getWidenedTypeFromJSSpecialPropertyDeclarations(symbol: Symbol) {
const types: Type[] = [];
let definedInConstructor = false;
let definedInMethod = false;
let jsDocType: Type;
for (const declaration of symbol.declarations) {
const expression = declaration.kind === SyntaxKind.BinaryExpression ? declaration :
declaration.kind === SyntaxKind.PropertyAccessExpression ? getAncestor(declaration, SyntaxKind.BinaryExpression) :
undefined;
if (!expression) {
return this.unknownType;
}
if (isPropertyAccessExpression(expression.left) && expression.left.expression.kind === SyntaxKind.ThisKeyword) {
if (getThisContainer(expression, /*includeArrowFunctions*/ false).kind === SyntaxKind.Constructor) {
definedInConstructor = true;
}
else {
definedInMethod = true;
}
}
// If there is a JSDoc type, use it
const type = this.getTypeForDeclarationFromJSDocComment(expression.parent);
if (type) {
const declarationType = this.getWidenedType(type);
if (!jsDocType) {
jsDocType = declarationType;
}
else if (jsDocType !== this.unknownType && declarationType !== this.unknownType && !this.isTypeIdenticalTo(jsDocType, declarationType)) {
const name = getNameOfDeclaration(declaration);
this.error(name, Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, declarationNameToString(name), this.typeToString(jsDocType), this.typeToString(declarationType));
}
}
else if (!jsDocType) {
// If we don't have an explicit JSDoc type, get the type from the expression.
types.push(this.getWidenedLiteralType(this.checkExpressionCached(expression.right)));
}
}
const type = jsDocType || this.getUnionType(types, /*subtypeReduction*/ true);
return this.getWidenedType(this.addOptionality(type, definedInMethod && !definedInConstructor));
}
// Return the type implied by a binding pattern element. This is the type of the initializer of the element if
// one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding
// pattern. Otherwise, it is the type any.
public getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type {
if (element.initializer) {
return this.checkDeclarationInitializer(element);
}
if (isBindingPattern(element.name)) {
return this.getTypeFromBindingPattern((element.name), includePatternInType, reportErrors);
}
if (reportErrors && this.noImplicitAny && !this.declarationBelongsToPrivateAmbientMember(element)) {
this.reportImplicitAnyError(element, this.anyType);
}
return this.anyType;
}
// Return the type implied by an object binding pattern
public getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
const __conv_self__ = this;
const members = createSymbolTable();
let stringIndexInfo: IndexInfo;
let hasComputedProperties = false;
forEach(pattern.elements, e => {
const name = e.propertyName || e.name;
if (__conv_self__.isComputedNonLiteralName(name)) {
// do not include computed properties in the implied type
hasComputedProperties = true;
return;
}
if (e.dotDotDotToken) {
stringIndexInfo = __conv_self__.createIndexInfo(__conv_self__.anyType, /*isReadonly*/ false);
return;
}
const text = getTextOfPropertyName(name);
const flags = SymbolFlags.Property | (e.initializer ? SymbolFlags.Optional : 0);
const symbol = __conv_self__.createSymbol(flags, text);
symbol.type = __conv_self__.getTypeFromBindingElement(e, includePatternInType, reportErrors);
symbol.bindingElement = e;
members.set(symbol.escapedName, symbol);
});
const result = this.createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, undefined);
if (includePatternInType) {
result.pattern = pattern;
}
if (hasComputedProperties) {
result.objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties;
}
return result;
}
// Return the type implied by an array binding pattern
public getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
const __conv_self__ = this;
const elements = pattern.elements;
const lastElement = lastOrUndefined(elements);
if (elements.length === 0 || (!isOmittedExpression(lastElement) && lastElement.dotDotDotToken)) {
return this.languageVersion >= ScriptTarget.ES2015 ? this.createIterableType(this.anyType) : this.anyArrayType;
}
// If the pattern has at least one element, and no rest element, then it should imply a tuple type.
const elementTypes = map(elements, e => isOmittedExpression(e) ? __conv_self__.anyType : __conv_self__.getTypeFromBindingElement(e, includePatternInType, reportErrors));
let result = this.createTupleType(elementTypes);
if (includePatternInType) {
result = this.cloneTypeReference(result);
result.pattern = pattern;
}
return result;
}
// Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
// and without regard to its context (i.e. without regard any type annotation or initializer associated with the
// declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any]
// and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is
// used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring
// parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of
// the parameter.
public getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean, reportErrors?: boolean): Type {
return pattern.kind === SyntaxKind.ObjectBindingPattern
? this.getTypeFromObjectBindingPattern((pattern), includePatternInType, reportErrors)
: this.getTypeFromArrayBindingPattern((pattern), includePatternInType, reportErrors);
}
// Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
// specified in a type annotation or inferred from an initializer. However, in the case of a destructuring declaration it
// is a bit more involved. For example:
//
// var [x, s = ""] = [1, "one"];
//
// Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the
// binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the
// tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string.
public getWidenedTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, reportErrors?: boolean): Type {
let type = this.getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true);
if (type) {
if (reportErrors) {
this.reportErrorsFromWidening(declaration, type);
}
// During a normal type check we'll never get to here with a property assignment (the check of the containing
// object literal uses a different path). We exclude widening only so that language services and type verification
// tools see the actual type.
if (declaration.kind === SyntaxKind.PropertyAssignment) {
return type;
}
return this.getWidenedType(type);
}
// Rest parameters default to type any[], other parameters default to type any
type = declaration.dotDotDotToken ? this.anyArrayType : this.anyType;
// Report implicit any errors unless this is a private property within an ambient declaration
if (reportErrors && this.noImplicitAny) {
if (!this.declarationBelongsToPrivateAmbientMember(declaration)) {
this.reportImplicitAnyError(declaration, type);
}
}
return type;
}
public declarationBelongsToPrivateAmbientMember(declaration: VariableLikeDeclaration) {
const root = getRootDeclaration(declaration);
const memberDeclaration = root.kind === SyntaxKind.Parameter ? root.parent : root;
return this.isPrivateWithinAmbient(memberDeclaration);
}
public getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (!links.type) {
// Handle prototype property
if (symbol.flags & SymbolFlags.Prototype) {
return links.type = this.getTypeOfPrototypeProperty(symbol);
}
// Handle catch clause variables
const declaration = symbol.valueDeclaration;
if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) {
return links.type = this.anyType;
}
// Handle export default expressions
if (declaration.kind === SyntaxKind.ExportAssignment) {
return links.type = this.checkExpression((declaration).expression);
}
if (isInJavaScriptFile(declaration) && isJSDocPropertyLikeTag(declaration) && declaration.typeExpression) {
return links.type = this.getTypeFromTypeNode(declaration.typeExpression.type);
}
// Handle variable, parameter or property
if (!this.pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return this.unknownType;
}
let type: Type;
// Handle certain special assignment kinds, which happen to union across multiple declarations:
// * module.exports = expr
// * exports.p = expr
// * this.p = expr
// * className.prototype.method = expr
if (declaration.kind === SyntaxKind.BinaryExpression ||
declaration.kind === SyntaxKind.PropertyAccessExpression && declaration.parent.kind === SyntaxKind.BinaryExpression) {
type = this.getWidenedTypeFromJSSpecialPropertyDeclarations(symbol);
}
else {
type = this.getWidenedTypeForVariableLikeDeclaration((declaration), /*reportErrors*/ true);
}
if (!this.popTypeResolution()) {
type = this.reportCircularityError(symbol);
}
links.type = type;
}
return links.type;
}
public getAnnotatedAccessorType(accessor: AccessorDeclaration): Type {
if (accessor) {
if (accessor.kind === SyntaxKind.GetAccessor) {
const getterTypeAnnotation = getEffectiveReturnTypeNode(accessor);
return getterTypeAnnotation && this.getTypeFromTypeNode(getterTypeAnnotation);
}
else {
const setterTypeAnnotation = getEffectiveSetAccessorTypeAnnotationNode(accessor);
return setterTypeAnnotation && this.getTypeFromTypeNode(setterTypeAnnotation);
}
}
return undefined;
}
public getAnnotatedAccessorThisParameter(accessor: AccessorDeclaration): Symbol | undefined {
const parameter = this.getAccessorThisParameter(accessor);
return parameter && parameter.symbol;
}
public getThisTypeOfDeclaration(declaration: SignatureDeclaration): Type | undefined {
return this.getThisTypeOfSignature(this.getSignatureFromDeclaration(declaration));
}
public getTypeOfAccessors(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (!links.type) {
const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor);
if (getter && isInJavaScriptFile(getter)) {
const jsDocType = this.getTypeForDeclarationFromJSDocComment(getter);
if (jsDocType) {
return links.type = jsDocType;
}
}
if (!this.pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return this.unknownType;
}
let type: Type;
// First try to see if the user specified a return type on the get-accessor.
const getterReturnType = this.getAnnotatedAccessorType(getter);
if (getterReturnType) {
type = getterReturnType;
}
else {
// If the user didn't specify a return type, try to use the set-accessor's parameter type.
const setterParameterType = this.getAnnotatedAccessorType(setter);
if (setterParameterType) {
type = setterParameterType;
}
else {
// If there are no specified types, try to infer it from the body of the get accessor if it exists.
if (getter && getter.body) {
type = this.getReturnTypeFromBody(getter);
}
else {
if (this.noImplicitAny) {
if (setter) {
this.error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, this.symbolToString(symbol));
}
else {
Debug.assert(!!getter, "there must existed getter as we are current checking either setter or getter in this function");
this.error(getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, this.symbolToString(symbol));
}
}
type = this.anyType;
}
}
}
if (!this.popTypeResolution()) {
type = this.anyType;
if (this.noImplicitAny) {
const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
this.error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, this.symbolToString(symbol));
}
}
links.type = type;
}
return links.type;
}
public getBaseTypeVariableOfClass(symbol: Symbol) {
const baseConstructorType = this.getBaseConstructorTypeOfClass(this.getDeclaredTypeOfClassOrInterface(symbol));
return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType : undefined;
}
public getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (!links.type) {
if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) {
links.type = this.anyType;
}
else {
const type = this.createObjectType(ObjectFlags.Anonymous, symbol);
if (symbol.flags & SymbolFlags.Class) {
const baseTypeVariable = this.getBaseTypeVariableOfClass(symbol);
links.type = baseTypeVariable ? this.getIntersectionType([type, baseTypeVariable]) : type;
}
else {
links.type = this.strictNullChecks && symbol.flags & SymbolFlags.Optional ? this.getNullableType(type, TypeFlags.Undefined) : type;
}
}
}
return links.type;
}
public getTypeOfEnumMember(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (!links.type) {
links.type = this.getDeclaredTypeOfEnumMember(symbol);
}
return links.type;
}
public getTypeOfAlias(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (!links.type) {
const targetSymbol = this.resolveAlias(symbol);
// It only makes sense to get the type of a value symbol. If the result of resolving
// the alias is not a value, then it has no type. To get the type associated with a
// type symbol, call getDeclaredTypeOfSymbol.
// This check is important because without it, a call to getTypeOfSymbol could end
// up recursively calling getTypeOfAlias, causing a stack overflow.
links.type = targetSymbol.flags & SymbolFlags.Value
? this.getTypeOfSymbol(targetSymbol)
: this.unknownType;
}
return links.type;
}
public getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (!links.type) {
if (this.symbolInstantiationDepth === 100) {
this.error(symbol.valueDeclaration, Diagnostics.Generic_type_instantiation_is_excessively_deep_and_possibly_infinite);
links.type = this.unknownType;
}
else {
if (!this.pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return this.unknownType;
}
this.symbolInstantiationDepth++;
let type = this.instantiateType(this.getTypeOfSymbol(links.target), links.mapper);
this.symbolInstantiationDepth--;
if (!this.popTypeResolution()) {
type = this.reportCircularityError(symbol);
}
links.type = type;
}
}
return links.type;
}
public reportCircularityError(symbol: Symbol) {
// Check if variable has type annotation that circularly references the variable itself
if (getEffectiveTypeAnnotationNode(symbol.valueDeclaration)) {
this.error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, this.symbolToString(symbol));
return this.unknownType;
}
// Otherwise variable has initializer that circularly references the variable itself
if (this.noImplicitAny) {
this.error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer, this.symbolToString(symbol));
}
return this.anyType;
}
public getTypeOfSymbol(symbol: Symbol): Type {
if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
return this.getTypeOfInstantiatedSymbol(symbol);
}
if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) {
return this.getTypeOfVariableOrParameterOrProperty(symbol);
}
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
return this.getTypeOfFuncClassEnumModule(symbol);
}
if (symbol.flags & SymbolFlags.EnumMember) {
return this.getTypeOfEnumMember(symbol);
}
if (symbol.flags & SymbolFlags.Accessor) {
return this.getTypeOfAccessors(symbol);
}
if (symbol.flags & SymbolFlags.Alias) {
return this.getTypeOfAlias(symbol);
}
return this.unknownType;
}
public isReferenceToType(type: Type, target: Type) {
return type !== undefined
&& target !== undefined
&& (this.getObjectFlags(type) & ObjectFlags.Reference) !== 0
&& (type).target === target;
}
public getTargetType(type: Type): Type {
return this.getObjectFlags(type) & ObjectFlags.Reference ? (type).target : type;
}
public hasBaseType(type: Type, checkBase: Type) {
const __conv_self__ = this;
return check(type);
function check(type: Type): boolean {
if (__conv_self__.getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) {
const target = (__conv_self__.getTargetType(type));
return target === checkBase || forEach(__conv_self__.getBaseTypes(target), check);
}
else if (type.flags & TypeFlags.Intersection) {
return forEach((type).types, check);
}
}
}
// Appends the type parameters given by a list of declarations to a set of type parameters and returns the resulting set.
// The function allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set
// in-place and returns the same array.
public appendTypeParameters(typeParameters: TypeParameter[], declarations: ReadonlyArray): TypeParameter[] {
for (const declaration of declarations) {
const tp = this.getDeclaredTypeOfTypeParameter(this.getSymbolOfNode(declaration));
if (!typeParameters) {
typeParameters = [tp];
}
else if (!contains(typeParameters, tp)) {
typeParameters.push(tp);
}
}
return typeParameters;
}
// Appends the outer type parameters of a node to a set of type parameters and returns the resulting set. The function
// allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set in-place and
// returns the same array.
public appendOuterTypeParameters(typeParameters: TypeParameter[], node: Node): TypeParameter[] {
while (true) {
node = node.parent;
if (!node) {
return typeParameters;
}
if (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression ||
node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression ||
node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.ArrowFunction) {
const declarations = (node).typeParameters;
if (declarations) {
return this.appendTypeParameters(this.appendOuterTypeParameters(typeParameters, node), declarations);
}
}
}
}
// The outer type parameters are those defined by enclosing generic classes, methods, or functions.
public getOuterTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
const declaration = symbol.flags & SymbolFlags.Class ? symbol.valueDeclaration : getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration);
return this.appendOuterTypeParameters(/*typeParameters*/ undefined, declaration);
}
// The local type parameters are the combined set of type parameters from all declarations of the class,
// interface, or type alias.
public getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): TypeParameter[] {
let result: TypeParameter[];
for (const node of symbol.declarations) {
if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration ||
node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.TypeAliasDeclaration) {
const declaration = node;
if (declaration.typeParameters) {
result = this.appendTypeParameters(result, declaration.typeParameters);
}
}
}
return result;
}
// The full set of type parameters for a generic class or interface type consists of its outer type parameters plus
// its locally declared type parameters.
public getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
return concatenate(this.getOuterTypeParametersOfClassOrInterface(symbol), this.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol));
}
// A type is a mixin constructor if it has a single construct signature taking no type parameters and a single
// rest parameter of type any[].
public isMixinConstructorType(type: Type) {
const signatures = this.getSignaturesOfType(type, SignatureKind.Construct);
if (signatures.length === 1) {
const s = signatures[0];
return !s.typeParameters && s.parameters.length === 1 && s.hasRestParameter && this.getTypeOfParameter(s.parameters[0]) === this.anyArrayType;
}
return false;
}
public isConstructorType(type: Type): boolean {
if (this.isValidBaseType(type) && this.getSignaturesOfType(type, SignatureKind.Construct).length > 0) {
return true;
}
if (type.flags & TypeFlags.TypeVariable) {
const constraint = this.getBaseConstraintOfType(type);
return constraint && this.isValidBaseType(constraint) && this.isMixinConstructorType(constraint);
}
return false;
}
public getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments {
return getClassExtendsHeritageClauseElement(type.symbol.valueDeclaration);
}
public getConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray, location: Node): Signature[] {
const __conv_self__ = this;
const typeArgCount = length(typeArgumentNodes);
const isJavaScript = isInJavaScriptFile(location);
return filter(this.getSignaturesOfType(type, SignatureKind.Construct), sig => (isJavaScript || typeArgCount >= __conv_self__.getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters));
}
public getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray, location: Node): Signature[] {
const __conv_self__ = this;
const signatures = this.getConstructorsForTypeArguments(type, typeArgumentNodes, location);
const typeArguments = map(typeArgumentNodes, this.getTypeFromTypeNode);
return sameMap(signatures, sig => some(sig.typeParameters) ? __conv_self__.getSignatureInstantiation(sig, typeArguments) : sig);
}
/**
* The base constructor of a class can resolve to
* * undefinedType if the class has no extends clause,
* * unknownType if an error occurred during resolution of the extends expression,
* * nullType if the extends expression is the null value,
* * anyType if the extends expression has type any, or
* * an object type with at least one construct signature.
*/
public getBaseConstructorTypeOfClass(type: InterfaceType): Type {
if (!type.resolvedBaseConstructorType) {
const baseTypeNode = this.getBaseTypeNodeOfClass(type);
if (!baseTypeNode) {
return type.resolvedBaseConstructorType = this.undefinedType;
}
if (!this.pushTypeResolution(type, TypeSystemPropertyName.ResolvedBaseConstructorType)) {
return this.unknownType;
}
const baseConstructorType = this.checkExpression(baseTypeNode.expression);
if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
// Resolving the members of a class requires us to resolve the base class of that class.
// We force resolution here such that we catch circularities now.
this.resolveStructuredTypeMembers((baseConstructorType));
}
if (!this.popTypeResolution()) {
this.error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, this.symbolToString(type.symbol));
return type.resolvedBaseConstructorType = this.unknownType;
}
if (!(baseConstructorType.flags & TypeFlags.Any) && baseConstructorType !== this.nullWideningType && !this.isConstructorType(baseConstructorType)) {
this.error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, this.typeToString(baseConstructorType));
return type.resolvedBaseConstructorType = this.unknownType;
}
type.resolvedBaseConstructorType = baseConstructorType;
}
return type.resolvedBaseConstructorType;
}
public getBaseTypes(type: InterfaceType): BaseType[] {
if (!type.resolvedBaseTypes) {
if (type.objectFlags & ObjectFlags.Tuple) {
type.resolvedBaseTypes = [this.createArrayType(this.getUnionType(type.typeParameters))];
}
else if (type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
if (type.symbol.flags & SymbolFlags.Class) {
this.resolveBaseTypesOfClass(type);
}
if (type.symbol.flags & SymbolFlags.Interface) {
this.resolveBaseTypesOfInterface(type);
}
}
else {
Debug.fail("type must be class or interface");
}
}
return type.resolvedBaseTypes;
}
public resolveBaseTypesOfClass(type: InterfaceType): void {
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
const baseConstructorType = this.getApparentType(this.getBaseConstructorTypeOfClass(type));
if (!(baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Any))) {
return;
}
const baseTypeNode = this.getBaseTypeNodeOfClass(type);
const typeArgs = this.typeArgumentsFromTypeReferenceNode(baseTypeNode);
let baseType: Type;
const originalBaseType = baseConstructorType && baseConstructorType.symbol ? this.getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined;
if (baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class &&
this.areAllOuterTypeParametersApplied(originalBaseType)) {
// When base constructor type is a class with no captured type arguments we know that the constructors all have the same type parameters as the
// class and all return the instance type of the class. There is no need for further checks and we can apply the
// type arguments in the same manner as a type reference to get the same error reporting experience.
baseType = this.getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol, typeArgs);
}
else if (baseConstructorType.flags & TypeFlags.Any) {
baseType = baseConstructorType;
}
else {
// The class derives from a "class-like" constructor function, check that we have at least one construct signature
// with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere
// we check that all instantiated signatures return the same type.
const constructors = this.getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments, baseTypeNode);
if (!constructors.length) {
this.error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments);
return;
}
baseType = this.getReturnTypeOfSignature(constructors[0]);
}
// In a JS file, you can use the @augments jsdoc tag to specify a base type with type parameters
const valueDecl = type.symbol.valueDeclaration;
if (valueDecl && isInJavaScriptFile(valueDecl)) {
const augTag = getJSDocAugmentsTag(type.symbol.valueDeclaration);
if (augTag) {
baseType = this.getTypeFromTypeNode(augTag.typeExpression.type);
}
}
if (baseType === this.unknownType) {
return;
}
if (!this.isValidBaseType(baseType)) {
this.error(baseTypeNode.expression, Diagnostics.Base_constructor_return_type_0_is_not_a_class_or_interface_type, this.typeToString(baseType));
return;
}
if (type === baseType || this.hasBaseType((baseType), type)) {
this.error(valueDecl, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, this.typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
return;
}
if (type.resolvedBaseTypes === emptyArray) {
type.resolvedBaseTypes = [baseType];
}
else {
type.resolvedBaseTypes.push(baseType);
}
}
public areAllOuterTypeParametersApplied(type: Type): boolean {
// An unapplied type parameter has its symbol still the same as the matching argument symbol.
// Since parameters are applied outer-to-inner, only the last outer parameter needs to be checked.
const outerTypeParameters = (type).outerTypeParameters;
if (outerTypeParameters) {
const last = outerTypeParameters.length - 1;
const typeArguments = (type).typeArguments;
return outerTypeParameters[last].symbol !== typeArguments[last].symbol;
}
return true;
}
// A valid base type is `any`, any non-generic object type or intersection of non-generic
// object types.
public isValidBaseType(type: Type): boolean {
const __conv_self__ = this;
return type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) && !this.isGenericMappedType(type) ||
type.flags & TypeFlags.Intersection && !forEach((type).types, t => !__conv_self__.isValidBaseType(t));
}
public resolveBaseTypesOfInterface(type: InterfaceType): void {
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
for (const declaration of type.symbol.declarations) {
if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(declaration)) {
for (const node of getInterfaceBaseTypeNodes(declaration)) {
const baseType = this.getTypeFromTypeNode(node);
if (baseType !== this.unknownType) {
if (this.isValidBaseType(baseType)) {
if (type !== baseType && !this.hasBaseType((baseType), type)) {
if (type.resolvedBaseTypes === emptyArray) {
type.resolvedBaseTypes = [baseType];
}
else {
type.resolvedBaseTypes.push(baseType);
}
}
else {
this.error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, this.typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
}
}
else {
this.error(node, Diagnostics.An_interface_may_only_extend_a_class_or_another_interface);
}
}
}
}
}
}
// Returns true if the interface given by the symbol is free of "this" references. Specifically, the result is
// true if the interface itself contains no references to "this" in its body, if all base types are interfaces,
// and if none of the base interfaces have a "this" type.
public isIndependentInterface(symbol: Symbol): boolean {
for (const declaration of symbol.declarations) {
if (declaration.kind === SyntaxKind.InterfaceDeclaration) {
if (declaration.flags & NodeFlags.ContainsThis) {
return false;
}
const baseTypeNodes = getInterfaceBaseTypeNodes(declaration);
if (baseTypeNodes) {
for (const node of baseTypeNodes) {
if (isEntityNameExpression(node.expression)) {
const baseSymbol = this.resolveEntityName(node.expression, SymbolFlags.Type, /*ignoreErrors*/ true);
if (!baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || this.getDeclaredTypeOfClassOrInterface(baseSymbol).thisType) {
return false;
}
}
}
}
}
}
return true;
}
public getDeclaredTypeOfClassOrInterface(symbol: Symbol): InterfaceType {
const links = this.getSymbolLinks(symbol);
if (!links.declaredType) {
const kind = symbol.flags & SymbolFlags.Class ? ObjectFlags.Class : ObjectFlags.Interface;
const type = links.declaredType = (this.createObjectType(kind, symbol));
const outerTypeParameters = this.getOuterTypeParametersOfClassOrInterface(symbol);
const localTypeParameters = this.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
// A class or interface is generic if it has type parameters or a "this" type. We always give classes a "this" type
// because it is not feasible to analyze all members to determine if the "this" type escapes the class (in particular,
// property types inferred from initializers and method return types inferred from return statements are very hard
// to exhaustively analyze). We give interfaces a "this" type if we can't definitely determine that they are free of
// "this" references.
if (outerTypeParameters || localTypeParameters || kind === ObjectFlags.Class || !this.isIndependentInterface(symbol)) {
type.objectFlags |= ObjectFlags.Reference;
type.typeParameters = concatenate(outerTypeParameters, localTypeParameters);
type.outerTypeParameters = outerTypeParameters;
type.localTypeParameters = localTypeParameters;
(type).instantiations = createMap();
(type).instantiations.set(this.getTypeListId(type.typeParameters), (type));
(type).target = type;
(type).typeArguments = type.typeParameters;
type.thisType = (this.createType(TypeFlags.TypeParameter));
type.thisType.isThisType = true;
type.thisType.symbol = symbol;
type.thisType.constraint = type;
}
}
return links.declaredType;
}
public getDeclaredTypeOfTypeAlias(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (!links.declaredType) {
// Note that we use the links object as the target here because the symbol object is used as the unique
// identity for resolution of the 'type' property in SymbolLinks.
if (!this.pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) {
return this.unknownType;
}
const declaration = find(symbol.declarations, d => d.kind === SyntaxKind.JSDocTypedefTag || d.kind === SyntaxKind.TypeAliasDeclaration);
let type = this.getTypeFromTypeNode(declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type);
if (this.popTypeResolution()) {
const typeParameters = this.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
if (typeParameters) {
// Initialize the instantiation cache for generic type aliases. The declared type corresponds to
// an instantiation of the type alias with the type parameters supplied as type arguments.
links.typeParameters = typeParameters;
links.instantiations = createMap();
links.instantiations.set(this.getTypeListId(typeParameters), type);
}
}
else {
type = this.unknownType;
this.error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, this.symbolToString(symbol));
}
links.declaredType = type;
}
return links.declaredType;
}
public isLiteralEnumMember(member: EnumMember) {
const expr = member.initializer;
if (!expr) {
return !isInAmbientContext(member);
}
switch (expr.kind) {
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
return true;
case SyntaxKind.PrefixUnaryExpression:
return (expr).operator === SyntaxKind.MinusToken &&
(expr).operand.kind === SyntaxKind.NumericLiteral;
case SyntaxKind.Identifier:
return nodeIsMissing(expr) || !!this.getSymbolOfNode(member.parent).exports.get((expr).escapedText);
default:
return false;
}
}
public getEnumKind(symbol: Symbol): EnumKind {
const links = this.getSymbolLinks(symbol);
if (links.enumKind !== undefined) {
return links.enumKind;
}
let hasNonLiteralMember = false;
for (const declaration of symbol.declarations) {
if (declaration.kind === SyntaxKind.EnumDeclaration) {
for (const member of (declaration).members) {
if (member.initializer && member.initializer.kind === SyntaxKind.StringLiteral) {
return links.enumKind = EnumKind.Literal;
}
if (!this.isLiteralEnumMember(member)) {
hasNonLiteralMember = true;
}
}
}
}
return links.enumKind = hasNonLiteralMember ? EnumKind.Numeric : EnumKind.Literal;
}
public getBaseTypeOfEnumLiteralType(type: Type) {
return type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union) ? this.getDeclaredTypeOfSymbol(this.getParentOfSymbol(type.symbol)) : type;
}
public getDeclaredTypeOfEnum(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (links.declaredType) {
return links.declaredType;
}
if (this.getEnumKind(symbol) === EnumKind.Literal) {
this.enumCount++;
const memberTypeList: Type[] = [];
for (const declaration of symbol.declarations) {
if (declaration.kind === SyntaxKind.EnumDeclaration) {
for (const member of (declaration).members) {
const memberType = this.getLiteralType(this.getEnumMemberValue(member), this.enumCount, this.getSymbolOfNode(member));
this.getSymbolLinks(this.getSymbolOfNode(member)).declaredType = memberType;
memberTypeList.push(memberType);
}
}
}
if (memberTypeList.length) {
const enumType = this.getUnionType(memberTypeList, /*subtypeReduction*/ false, symbol, /*aliasTypeArguments*/ undefined);
if (enumType.flags & TypeFlags.Union) {
enumType.flags |= TypeFlags.EnumLiteral;
enumType.symbol = symbol;
}
return links.declaredType = enumType;
}
}
const enumType = this.createType(TypeFlags.Enum);
enumType.symbol = symbol;
return links.declaredType = enumType;
}
public getDeclaredTypeOfEnumMember(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (!links.declaredType) {
const enumType = this.getDeclaredTypeOfEnum(this.getParentOfSymbol(symbol));
if (!links.declaredType) {
links.declaredType = enumType;
}
}
return links.declaredType;
}
public getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter {
const links = this.getSymbolLinks(symbol);
if (!links.declaredType) {
const type = (this.createType(TypeFlags.TypeParameter));
type.symbol = symbol;
links.declaredType = type;
}
return links.declaredType;
}
public getDeclaredTypeOfAlias(symbol: Symbol): Type {
const links = this.getSymbolLinks(symbol);
if (!links.declaredType) {
links.declaredType = this.getDeclaredTypeOfSymbol(this.resolveAlias(symbol));
}
return links.declaredType;
}
public getDeclaredTypeOfSymbol(symbol: Symbol): Type {
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
return this.getDeclaredTypeOfClassOrInterface(symbol);
}
if (symbol.flags & SymbolFlags.TypeAlias) {
return this.getDeclaredTypeOfTypeAlias(symbol);
}
if (symbol.flags & SymbolFlags.TypeParameter) {
return this.getDeclaredTypeOfTypeParameter(symbol);
}
if (symbol.flags & SymbolFlags.Enum) {
return this.getDeclaredTypeOfEnum(symbol);
}
if (symbol.flags & SymbolFlags.EnumMember) {
return this.getDeclaredTypeOfEnumMember(symbol);
}
if (symbol.flags & SymbolFlags.Alias) {
return this.getDeclaredTypeOfAlias(symbol);
}
return this.unknownType;
}
// A type reference is considered independent if each type argument is considered independent.
public isIndependentTypeReference(node: TypeReferenceNode): boolean {
if (node.typeArguments) {
for (const typeNode of node.typeArguments) {
if (!this.isIndependentType(typeNode)) {
return false;
}
}
}
return true;
}
// A type is considered independent if it the any, string, number, boolean, symbol, or void keyword, a string
// literal type, an array with an element type that is considered independent, or a type reference that is
// considered independent.
public isIndependentType(node: TypeNode): boolean {
switch (node.kind) {
case SyntaxKind.AnyKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.ObjectKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.LiteralType:
return true;
case SyntaxKind.ArrayType:
return this.isIndependentType((node).elementType);
case SyntaxKind.TypeReference:
return this.isIndependentTypeReference((node));
}
return false;
}
// A variable-like declaration is considered independent (free of this references) if it has a type annotation
// that specifies an independent type, or if it has no type annotation and no initializer (and thus of type any).
public isIndependentVariableLikeDeclaration(node: VariableLikeDeclaration): boolean {
const typeNode = getEffectiveTypeAnnotationNode(node);
return typeNode ? this.isIndependentType(typeNode) : !node.initializer;
}
// A function-like declaration is considered independent (free of this references) if it has a return type
// annotation that is considered independent and if each parameter is considered independent.
public isIndependentFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean {
if (node.kind !== SyntaxKind.Constructor) {
const typeNode = getEffectiveReturnTypeNode(node);
if (!typeNode || !this.isIndependentType(typeNode)) {
return false;
}
}
for (const parameter of node.parameters) {
if (!this.isIndependentVariableLikeDeclaration(parameter)) {
return false;
}
}
return true;
}
// Returns true if the class or interface member given by the symbol is free of "this" references. The
// function may return false for symbols that are actually free of "this" references because it is not
// feasible to perform a complete analysis in all cases. In particular, property members with types
// inferred from their initializers and function members with inferred return types are conservatively
// assumed not to be free of "this" references.
public isIndependentMember(symbol: Symbol): boolean {
if (symbol.declarations && symbol.declarations.length === 1) {
const declaration = symbol.declarations[0];
if (declaration) {
switch (declaration.kind) {
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
return this.isIndependentVariableLikeDeclaration((declaration));
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Constructor:
return this.isIndependentFunctionLikeDeclaration((declaration));
}
}
}
return false;
}
// The mappingThisOnly flag indicates that the only type parameter being mapped is "this". When the flag is true,
// we check symbols to see if we can quickly conclude they are free of "this" references, thus needing no instantiation.
public createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper, mappingThisOnly: boolean): SymbolTable {
const result = createSymbolTable();
for (const symbol of symbols) {
result.set(symbol.escapedName, mappingThisOnly && this.isIndependentMember(symbol) ? symbol : this.instantiateSymbol(symbol, mapper));
}
return result;
}
public addInheritedMembers(symbols: SymbolTable, baseSymbols: Symbol[]) {
for (const s of baseSymbols) {
if (!symbols.has(s.escapedName)) {
symbols.set(s.escapedName, s);
}
}
}
public resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers {
if (!(type).declaredProperties) {
const symbol = type.symbol;
(type).declaredProperties = this.getNamedMembers(symbol.members);
(type).declaredCallSignatures = this.getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Call));
(type).declaredConstructSignatures = this.getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.New));
(type).declaredStringIndexInfo = this.getIndexInfoOfSymbol(symbol, IndexKind.String);
(type).declaredNumberIndexInfo = this.getIndexInfoOfSymbol(symbol, IndexKind.Number);
}
return type;
}
public getTypeWithThisArgument(type: Type, thisArgument?: Type): Type {
const __conv_self__ = this;
if (this.getObjectFlags(type) & ObjectFlags.Reference) {
const target = (type).target;
const typeArguments = (type).typeArguments;
if (length(target.typeParameters) === length(typeArguments)) {
return this.createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType]));
}
}
else if (type.flags & TypeFlags.Intersection) {
return this.getIntersectionType(map((type).types, t => __conv_self__.getTypeWithThisArgument(t, thisArgument)));
}
return type;
}
public resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) {
let mapper: TypeMapper;
let members: SymbolTable;
let callSignatures: Signature[];
let constructSignatures: Signature[];
let stringIndexInfo: IndexInfo;
let numberIndexInfo: IndexInfo;
if (rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) {
mapper = this.identityMapper;
members = source.symbol ? source.symbol.members : createSymbolTable(source.declaredProperties);
callSignatures = source.declaredCallSignatures;
constructSignatures = source.declaredConstructSignatures;
stringIndexInfo = source.declaredStringIndexInfo;
numberIndexInfo = source.declaredNumberIndexInfo;
}
else {
mapper = this.createTypeMapper(typeParameters, typeArguments);
members = this.createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1);
callSignatures = this.instantiateSignatures(source.declaredCallSignatures, mapper);
constructSignatures = this.instantiateSignatures(source.declaredConstructSignatures, mapper);
stringIndexInfo = this.instantiateIndexInfo(source.declaredStringIndexInfo, mapper);
numberIndexInfo = this.instantiateIndexInfo(source.declaredNumberIndexInfo, mapper);
}
const baseTypes = this.getBaseTypes(source);
if (baseTypes.length) {
if (source.symbol && members === source.symbol.members) {
members = createSymbolTable(source.declaredProperties);
}
const thisArgument = lastOrUndefined(typeArguments);
for (const baseType of baseTypes) {
const instantiatedBaseType = thisArgument ? this.getTypeWithThisArgument(this.instantiateType(baseType, mapper), thisArgument) : baseType;
this.addInheritedMembers(members, this.getPropertiesOfType(instantiatedBaseType));
callSignatures = concatenate(callSignatures, this.getSignaturesOfType(instantiatedBaseType, SignatureKind.Call));
constructSignatures = concatenate(constructSignatures, this.getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct));
if (!stringIndexInfo) {
stringIndexInfo = instantiatedBaseType === this.anyType ?
this.createIndexInfo(this.anyType, /*isReadonly*/ false) :
this.getIndexInfoOfType(instantiatedBaseType, IndexKind.String);
}
numberIndexInfo = numberIndexInfo || this.getIndexInfoOfType(instantiatedBaseType, IndexKind.Number);
}
}
this.setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
}
public resolveClassOrInterfaceMembers(type: InterfaceType): void {
this.resolveObjectTypeMembers(type, this.resolveDeclaredMembers(type), emptyArray, emptyArray);
}
public resolveTypeReferenceMembers(type: TypeReference): void {
const source = this.resolveDeclaredMembers(type.target);
const typeParameters = concatenate(source.typeParameters, [source.thisType]);
const typeArguments = type.typeArguments && type.typeArguments.length === typeParameters.length ?
type.typeArguments : concatenate(type.typeArguments, [type]);
this.resolveObjectTypeMembers(type, source, typeParameters, typeArguments);
}
public createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], thisParameter: Symbol | undefined, parameters: Symbol[], resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasLiteralTypes: boolean): Signature {
const sig = new this.Signature(this.checker);
sig.declaration = declaration;
sig.typeParameters = typeParameters;
sig.parameters = parameters;
sig.thisParameter = thisParameter;
sig.resolvedReturnType = resolvedReturnType;
sig.typePredicate = typePredicate;
sig.minArgumentCount = minArgumentCount;
sig.hasRestParameter = hasRestParameter;
sig.hasLiteralTypes = hasLiteralTypes;
return sig;
}
public cloneSignature(sig: Signature): Signature {
return this.createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, sig.resolvedReturnType, sig.typePredicate, sig.minArgumentCount, sig.hasRestParameter, sig.hasLiteralTypes);
}
public getDefaultConstructSignatures(classType: InterfaceType): Signature[] {
const baseConstructorType = this.getBaseConstructorTypeOfClass(classType);
const baseSignatures = this.getSignaturesOfType(baseConstructorType, SignatureKind.Construct);
if (baseSignatures.length === 0) {
return [this.createSignature(undefined, classType.localTypeParameters, undefined, emptyArray, classType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false)];
}
const baseTypeNode = this.getBaseTypeNodeOfClass(classType);
const isJavaScript = isInJavaScriptFile(baseTypeNode);
const typeArguments = this.typeArgumentsFromTypeReferenceNode(baseTypeNode);
const typeArgCount = length(typeArguments);
const result: Signature[] = [];
for (const baseSig of baseSignatures) {
const minTypeArgumentCount = this.getMinTypeArgumentCount(baseSig.typeParameters);
const typeParamCount = length(baseSig.typeParameters);
if ((isJavaScript || typeArgCount >= minTypeArgumentCount) && typeArgCount <= typeParamCount) {
const sig = typeParamCount ? this.createSignatureInstantiation(baseSig, this.fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, baseTypeNode)) : this.cloneSignature(baseSig);
sig.typeParameters = classType.localTypeParameters;
sig.resolvedReturnType = classType;
result.push(sig);
}
}
return result;
}
public findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature {
for (const s of signatureList) {
if (this.compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, this.compareTypesIdentical)) {
return s;
}
}
}
public findMatchingSignatures(signatureLists: Signature[][], signature: Signature, listIndex: number): Signature[] {
if (signature.typeParameters) {
// We require an exact match for generic signatures, so we only return signatures from the first
// signature list and only if they have exact matches in the other signature lists.
if (listIndex > 0) {
return undefined;
}
for (let i = 1; i < signatureLists.length; i++) {
if (!this.findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false)) {
return undefined;
}
}
return [signature];
}
let result: Signature[] = undefined;
for (let i = 0; i < signatureLists.length; i++) {
// Allow matching non-generic signatures to have excess parameters and different return types
const match = i === listIndex ? signature : this.findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true);
if (!match) {
return undefined;
}
if (!contains(result, match)) {
(result || (result = [])).push(match);
}
}
return result;
}
// The signatures of a union type are those signatures that are present in each of the constituent types.
// Generic signatures must match exactly, but non-generic signatures are allowed to have extra optional
// parameters and may differ in return types. When signatures differ in return types, the resulting return
// type is the union of the constituent return types.
public getUnionSignatures(types: Type[], kind: SignatureKind): Signature[] {
const __conv_self__ = this;
const signatureLists = map(types, t => __conv_self__.getSignaturesOfType(t, kind));
let result: Signature[] = undefined;
for (let i = 0; i < signatureLists.length; i++) {
for (const signature of signatureLists[i]) {
// Only process signatures with parameter lists that aren't already in the result list
if (!result || !this.findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true)) {
const unionSignatures = this.findMatchingSignatures(signatureLists, signature, i);
if (unionSignatures) {
let s = signature;
// Union the result types when more than one signature matches
if (unionSignatures.length > 1) {
s = this.cloneSignature(signature);
if (forEach(unionSignatures, sig => sig.thisParameter)) {
const thisType = this.getUnionType(map(unionSignatures, sig => __conv_self__.getTypeOfSymbol(sig.thisParameter) || __conv_self__.anyType), /*subtypeReduction*/ true);
s.thisParameter = this.createSymbolWithType(signature.thisParameter, thisType);
}
// Clear resolved return type we possibly got from cloneSignature
s.resolvedReturnType = undefined;
s.unionSignatures = unionSignatures;
}
(result || (result = [])).push(s);
}
}
}
}
return result || emptyArray;
}
public getUnionIndexInfo(types: Type[], kind: IndexKind): IndexInfo {
const indexTypes: Type[] = [];
let isAnyReadonly = false;
for (const type of types) {
const indexInfo = this.getIndexInfoOfType(type, kind);
if (!indexInfo) {
return undefined;
}
indexTypes.push(indexInfo.type);
isAnyReadonly = isAnyReadonly || indexInfo.isReadonly;
}
return this.createIndexInfo(this.getUnionType(indexTypes, /*subtypeReduction*/ true), isAnyReadonly);
}
public resolveUnionTypeMembers(type: UnionType) {
// The members and properties collections are empty for union types. To get all properties of a union
// type use getPropertiesOfType (only the language service uses this).
const callSignatures = this.getUnionSignatures(type.types, SignatureKind.Call);
const constructSignatures = this.getUnionSignatures(type.types, SignatureKind.Construct);
const stringIndexInfo = this.getUnionIndexInfo(type.types, IndexKind.String);
const numberIndexInfo = this.getUnionIndexInfo(type.types, IndexKind.Number);
this.setStructuredTypeMembers(type, this.emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
}
public intersectTypes(type1: Type, type2: Type): Type {
return !type1 ? type2 : !type2 ? type1 : this.getIntersectionType([type1, type2]);
}
public intersectIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo {
return !info1 ? info2 : !info2 ? info1 : this.createIndexInfo(this.getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly);
}
public unionSpreadIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo {
return info1 && info2 && this.createIndexInfo(this.getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly);
}
public includeMixinType(type: Type, types: Type[], index: number): Type {
const mixedTypes: Type[] = [];
for (let i = 0; i < types.length; i++) {
if (i === index) {
mixedTypes.push(type);
}
else if (this.isMixinConstructorType(types[i])) {
mixedTypes.push(this.getReturnTypeOfSignature(this.getSignaturesOfType(types[i], SignatureKind.Construct)[0]));
}
}
return this.getIntersectionType(mixedTypes);
}
public resolveIntersectionTypeMembers(type: IntersectionType) {
const __conv_self__ = this;
// The members and properties collections are empty for intersection types. To get all properties of an
// intersection type use getPropertiesOfType (only the language service uses this).
let callSignatures: Signature[] = emptyArray;
let constructSignatures: Signature[] = emptyArray;
let stringIndexInfo: IndexInfo;
let numberIndexInfo: IndexInfo;
const types = type.types;
const mixinCount = countWhere(types, this.isMixinConstructorType);
for (let i = 0; i < types.length; i++) {
const t = type.types[i];
// When an intersection type contains mixin constructor types, the construct signatures from
// those types are discarded and their return types are mixed into the return types of all
// other construct signatures in the intersection type. For example, the intersection type
// '{ new(...args: any[]) => A } & { new(s: string) => B }' has a single construct signature
// 'new(s: string) => A & B'.
if (mixinCount === 0 || mixinCount === types.length && i === 0 || !this.isMixinConstructorType(t)) {
let signatures = this.getSignaturesOfType(t, SignatureKind.Construct);
if (signatures.length && mixinCount > 0) {
signatures = map(signatures, s => {
const clone = __conv_self__.cloneSignature(s);
clone.resolvedReturnType = __conv_self__.includeMixinType(__conv_self__.getReturnTypeOfSignature(s), types, i);
return clone;
});
}
constructSignatures = concatenate(constructSignatures, signatures);
}
callSignatures = concatenate(callSignatures, this.getSignaturesOfType(t, SignatureKind.Call));
stringIndexInfo = this.intersectIndexInfos(stringIndexInfo, this.getIndexInfoOfType(t, IndexKind.String));
numberIndexInfo = this.intersectIndexInfos(numberIndexInfo, this.getIndexInfoOfType(t, IndexKind.Number));
}
this.setStructuredTypeMembers(type, this.emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
}
/**
* Converts an AnonymousType to a ResolvedType.
*/
public resolveAnonymousTypeMembers(type: AnonymousType) {
const symbol = type.symbol;
if (type.target) {
const members = this.createInstantiatedSymbolTable(this.getPropertiesOfObjectType(type.target), type.mapper, /*mappingThisOnly*/ false);
const callSignatures = this.instantiateSignatures(this.getSignaturesOfType(type.target, SignatureKind.Call), type.mapper);
const constructSignatures = this.instantiateSignatures(this.getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper);
const stringIndexInfo = this.instantiateIndexInfo(this.getIndexInfoOfType(type.target, IndexKind.String), type.mapper);
const numberIndexInfo = this.instantiateIndexInfo(this.getIndexInfoOfType(type.target, IndexKind.Number), type.mapper);
this.setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
}
else if (symbol.flags & SymbolFlags.TypeLiteral) {
const members = symbol.members;
const callSignatures = this.getSignaturesOfSymbol(members.get(InternalSymbolName.Call));
const constructSignatures = this.getSignaturesOfSymbol(members.get(InternalSymbolName.New));
const stringIndexInfo = this.getIndexInfoOfSymbol(symbol, IndexKind.String);
const numberIndexInfo = this.getIndexInfoOfSymbol(symbol, IndexKind.Number);
this.setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
}
else {
// Combinations of function, class, enum and module
let members = this.emptySymbols;
let constructSignatures: Signature[] = emptyArray;
let stringIndexInfo: IndexInfo = undefined;
if (symbol.exports) {
members = this.getExportsOfSymbol(symbol);
}
if (symbol.flags & SymbolFlags.Class) {
const classType = this.getDeclaredTypeOfClassOrInterface(symbol);
constructSignatures = this.getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Constructor));
if (!constructSignatures.length) {
constructSignatures = this.getDefaultConstructSignatures(classType);
}
const baseConstructorType = this.getBaseConstructorTypeOfClass(classType);
if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.TypeVariable)) {
members = createSymbolTable(this.getNamedMembers(members));
this.addInheritedMembers(members, this.getPropertiesOfType(baseConstructorType));
}
else if (baseConstructorType === this.anyType) {
stringIndexInfo = this.createIndexInfo(this.anyType, /*isReadonly*/ false);
}
}
const numberIndexInfo = symbol.flags & SymbolFlags.Enum ? this.enumNumberIndexInfo : undefined;
this.setStructuredTypeMembers(type, members, emptyArray, constructSignatures, stringIndexInfo, numberIndexInfo);
// We resolve the members before computing the signatures because a signature may use
// typeof with a qualified name expression that circularly references the type we are
// in the process of resolving (see issue #6072). The temporarily empty signature list
// will never be observed because a qualified name can't reference signatures.
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) {
(type).callSignatures = this.getSignaturesOfSymbol(symbol);
}
}
}
/** Resolve the members of a mapped type { [P in K]: T } */
public resolveMappedTypeMembers(type: MappedType) {
const __conv_self__ = this;
const members: SymbolTable = createSymbolTable();
let stringIndexInfo: IndexInfo;
// Resolve upfront such that recursive references see an empty object type.
this.setStructuredTypeMembers(type, this.emptySymbols, emptyArray, emptyArray, undefined, undefined);
// In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type,
// and T as the template type.
const typeParameter = this.getTypeParameterFromMappedType(type);
const constraintType = this.getConstraintTypeFromMappedType(type);
const templateType = this.getTemplateTypeFromMappedType(type);
const modifiersType = this.getApparentType(this.getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T'
const templateReadonly = !!type.declaration.readonlyToken;
const templateOptional = !!type.declaration.questionToken;
if (type.declaration.typeParameter.constraint.kind === SyntaxKind.TypeOperator) {
// We have a { [P in keyof T]: X }
for (const propertySymbol of this.getPropertiesOfType(modifiersType)) {
addMemberForKeyType(this.getLiteralTypeFromPropertyName(propertySymbol), propertySymbol);
}
if (this.getIndexInfoOfType(modifiersType, IndexKind.String)) {
addMemberForKeyType(this.stringType);
}
}
else {
// First, if the constraint type is a type parameter, obtain the base constraint. Then,
// if the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X.
// Finally, iterate over the constituents of the resulting iteration type.
const keyType = constraintType.flags & TypeFlags.TypeVariable ? this.getApparentType(constraintType) : constraintType;
const iterationType = keyType.flags & TypeFlags.Index ? this.getIndexType(this.getApparentType((keyType).type)) : keyType;
this.forEachType(iterationType, addMemberForKeyType);
}
this.setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined);
function addMemberForKeyType(t: Type, propertySymbol?: Symbol) {
// Create a mapper from T to the current iteration type constituent. Then, if the
// mapped type is itself an instantiated type, combine the iteration mapper with the
// instantiation mapper.
const iterationMapper = __conv_self__.createTypeMapper([typeParameter], [t]);
const templateMapper = type.mapper ? __conv_self__.combineTypeMappers(type.mapper, iterationMapper) : iterationMapper;
const propType = __conv_self__.instantiateType(templateType, templateMapper);
// If the current iteration type constituent is a string literal type, create a property.
// Otherwise, for type string create a string index signature.
if (t.flags & TypeFlags.StringLiteral) {
const propName = escapeLeadingUnderscores((t).value);
const modifiersProp = __conv_self__.getPropertyOfType(modifiersType, propName);
const isOptional = templateOptional || !!(modifiersProp && modifiersProp.flags & SymbolFlags.Optional);
const prop = __conv_self__.createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName);
prop.checkFlags = templateReadonly || modifiersProp && __conv_self__.isReadonlySymbol(modifiersProp) ? CheckFlags.Readonly : 0;
prop.type = propType;
if (propertySymbol) {
prop.syntheticOrigin = propertySymbol;
prop.declarations = propertySymbol.declarations;
}
members.set(propName, prop);
}
else if (t.flags & TypeFlags.String) {
stringIndexInfo = __conv_self__.createIndexInfo(propType, templateReadonly);
}
}
}
public getTypeParameterFromMappedType(type: MappedType) {
return type.typeParameter ||
(type.typeParameter = this.getDeclaredTypeOfTypeParameter(this.getSymbolOfNode(type.declaration.typeParameter)));
}
public getConstraintTypeFromMappedType(type: MappedType) {
return type.constraintType ||
(type.constraintType = this.instantiateType(this.getConstraintOfTypeParameter(this.getTypeParameterFromMappedType(type)), type.mapper || this.identityMapper) || this.unknownType);
}
public getTemplateTypeFromMappedType(type: MappedType) {
return type.templateType ||
(type.templateType = type.declaration.type ?
this.instantiateType(this.addOptionality(this.getTypeFromTypeNode(type.declaration.type), !!type.declaration.questionToken), type.mapper || this.identityMapper) : this.unknownType);
}
public getModifiersTypeFromMappedType(type: MappedType) {
if (!type.modifiersType) {
const constraintDeclaration = type.declaration.typeParameter.constraint;
if (constraintDeclaration.kind === SyntaxKind.TypeOperator) {
// If the constraint declaration is a 'keyof T' node, the modifiers type is T. We check
// AST nodes here because, when T is a non-generic type, the logic below eagerly resolves
// 'keyof T' to a literal union type and we can't recover T from that type.
type.modifiersType = this.instantiateType(this.getTypeFromTypeNode((constraintDeclaration).type), type.mapper || this.identityMapper);
}
else {
// Otherwise, get the declared constraint type, and if the constraint type is a type parameter,
// get the constraint of that type parameter. If the resulting type is an indexed type 'keyof T',
// the modifiers type is T. Otherwise, the modifiers type is {}.
const declaredType = (this.getTypeFromMappedTypeNode(type.declaration));
const constraint = this.getConstraintTypeFromMappedType(declaredType);
const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? this.getConstraintOfTypeParameter((constraint)) : constraint;
type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? this.instantiateType((extendedConstraint).type, type.mapper || this.identityMapper) : this.emptyObjectType;
}
}
return type.modifiersType;
}
public isPartialMappedType(type: Type) {
return this.getObjectFlags(type) & ObjectFlags.Mapped && !!(type).declaration.questionToken;
}
public isGenericMappedType(type: Type) {
return this.getObjectFlags(type) & ObjectFlags.Mapped && this.isGenericIndexType(this.getConstraintTypeFromMappedType((type)));
}
public resolveStructuredTypeMembers(type: StructuredType): ResolvedType {
if (!(type).members) {
if (type.flags & TypeFlags.Object) {
if ((