Fix potential leaks in checker (#36491)

This commit is contained in:
Ron Buckton 2020-01-28 16:48:28 -08:00 committed by GitHub
parent 869a8211fc
commit 6769313eee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 64 deletions

View File

@ -60,7 +60,7 @@ function updateTsFile(tsFilePath: string, tsFileContents: string, majorMinor: st
const parsedMajorMinor = majorMinorMatch![1];
assert(parsedMajorMinor === majorMinor, `versionMajorMinor does not match. ${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`);
const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)(-dev)?`;/;
const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)(-\w+)?`;/;
const patchMatch = versionRgx.exec(tsFileContents);
assert(patchMatch !== null, `The file '${tsFilePath}' seems to no longer have a string matching '${versionRgx.toString()}'.`);
const parsedPatch = patchMatch![1];

View File

@ -738,10 +738,11 @@ namespace ts {
const iterationTypesCache = createMap<IterationTypes>(); // cache for common IterationTypes instances
const noIterationTypes: IterationTypes = {
get yieldType(): Type { throw new Error("Not supported"); },
get returnType(): Type { throw new Error("Not supported"); },
get nextType(): Type { throw new Error("Not supported"); },
get yieldType(): Type { return Debug.fail("Not supported"); },
get returnType(): Type { return Debug.fail("Not supported"); },
get nextType(): Type { return Debug.fail("Not supported"); },
};
const anyIterationTypes = createIterationTypes(anyType, anyType, anyType);
const anyIterationTypesExceptNext = createIterationTypes(anyType, anyType, unknownType);
const defaultIterationTypes = createIterationTypes(neverType, anyType, undefinedType); // default iteration types for `Iterator`.
@ -2323,8 +2324,8 @@ namespace ts {
result.declarations = deduplicate(concatenate(valueSymbol.declarations, typeSymbol.declarations), equateValues);
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;
if (typeSymbol.members) result.members = cloneMap(typeSymbol.members);
if (valueSymbol.exports) result.exports = cloneMap(valueSymbol.exports);
return result;
}
@ -5095,7 +5096,7 @@ namespace ts {
// See getNameForSymbolFromNameType for a stringy equivalent
function getPropertyNameNodeForSymbolFromNameType(symbol: Symbol, context: NodeBuilderContext, singleQuote?: boolean) {
const nameType = symbol.nameType;
const nameType = getSymbolLinks(symbol).nameType;
if (nameType) {
if (nameType.flags & TypeFlags.StringOrNumberLiteral) {
const name = "" + (<StringLiteralType | NumberLiteralType>nameType).value;
@ -6521,7 +6522,7 @@ namespace ts {
}
function getNameOfSymbolFromNameType(symbol: Symbol, context?: NodeBuilderContext) {
const nameType = symbol.nameType;
const nameType = getSymbolLinks(symbol).nameType;
if (nameType) {
if (nameType.flags & TypeFlags.StringOrNumberLiteral) {
const name = "" + (<StringLiteralType | NumberLiteralType>nameType).value;
@ -6563,11 +6564,14 @@ namespace ts {
if (isCallExpression(declaration) && isBindableObjectDefinePropertyCall(declaration)) {
return symbolName(symbol);
}
if (isComputedPropertyName(name) && !(getCheckFlags(symbol) & CheckFlags.Late) && symbol.nameType && symbol.nameType.flags & TypeFlags.StringOrNumberLiteral) {
// Computed property name isn't late bound, but has a well-known name type - use name type to generate a symbol name
const result = getNameOfSymbolFromNameType(symbol, context);
if (result !== undefined) {
return result;
if (isComputedPropertyName(name) && !(getCheckFlags(symbol) & CheckFlags.Late)) {
const nameType = getSymbolLinks(symbol).nameType;
if (nameType && nameType.flags & TypeFlags.StringOrNumberLiteral) {
// Computed property name isn't late bound, but has a well-known name type - use name type to generate a symbol name
const result = getNameOfSymbolFromNameType(symbol, context);
if (result !== undefined) {
return result;
}
}
}
return declarationNameToString(name);
@ -8697,7 +8701,7 @@ namespace ts {
* @param lateSymbols The late-bound symbols of the parent.
* @param decl The member to bind.
*/
function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: SymbolTable, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) {
function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: UnderscoreEscapedMap<TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) {
Debug.assert(!!decl.symbol, "The member is expected to have a symbol.");
const links = getNodeLinks(decl);
if (!links.resolvedSymbol) {
@ -8755,7 +8759,7 @@ namespace ts {
links[resolutionKind] = earlySymbols || emptySymbols;
// fill in any as-yet-unresolved late-bound members.
const lateSymbols = createSymbolTable();
const lateSymbols = createSymbolTable() as UnderscoreEscapedMap<TransientSymbol>;
for (const decl of symbol.declarations) {
const members = getMembersOfDeclaration(decl);
if (members) {
@ -9359,7 +9363,7 @@ namespace ts {
const checkFlags = CheckFlags.ReverseMapped | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0);
const inferredProp = createSymbol(SymbolFlags.Property | prop.flags & optionalMask, prop.escapedName, checkFlags) as ReverseMappedSymbol;
inferredProp.declarations = prop.declarations;
inferredProp.nameType = prop.nameType;
inferredProp.nameType = getSymbolLinks(prop).nameType;
inferredProp.propertyType = getTypeOfSymbol(prop);
inferredProp.mappedType = type.mappedType;
inferredProp.constraintType = type.constraintType;
@ -10048,7 +10052,7 @@ namespace ts {
const type = getTypeOfSymbol(prop);
if (!firstType) {
firstType = type;
nameType = prop.nameType;
nameType = getSymbolLinks(prop).nameType;
}
else if (type !== firstType) {
checkFlags |= CheckFlags.HasNonUniformType;
@ -12040,7 +12044,7 @@ namespace ts {
function getLiteralTypeFromProperty(prop: Symbol, include: TypeFlags) {
if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) {
let type = getLateBoundSymbol(prop).nameType;
let type = getSymbolLinks(getLateBoundSymbol(prop)).nameType;
if (!type && !isKnownSymbol(prop)) {
if (prop.escapedName === InternalSymbolName.Default) {
type = getLiteralType("default");
@ -12812,7 +12816,7 @@ namespace ts {
const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0);
result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop);
result.declarations = prop.declarations;
result.nameType = prop.nameType;
result.nameType = getSymbolLinks(prop).nameType;
result.syntheticOrigin = prop;
members.set(prop.escapedName, result);
}
@ -12920,7 +12924,7 @@ namespace ts {
result.leftSpread = leftProp;
result.rightSpread = rightProp;
result.declarations = declarations;
result.nameType = leftProp.nameType;
result.nameType = getSymbolLinks(leftProp).nameType;
members.set(leftProp.escapedName, result);
}
}
@ -12956,7 +12960,7 @@ namespace ts {
const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0);
result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop);
result.declarations = prop.declarations;
result.nameType = prop.nameType;
result.nameType = getSymbolLinks(prop).nameType;
result.syntheticOrigin = prop;
return result;
}
@ -13322,8 +13326,8 @@ namespace ts {
if (symbol.valueDeclaration) {
result.valueDeclaration = symbol.valueDeclaration;
}
if (symbol.nameType) {
result.nameType = symbol.nameType;
if (links.nameType) {
result.nameType = links.nameType;
}
return result;
}
@ -16280,7 +16284,11 @@ namespace ts {
const props = source.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(<IntersectionType>source) : getPropertiesOfObjectType(source);
for (const prop of props) {
// Skip over ignored JSX and symbol-named members
if (isIgnoredJsxProperty(source, prop) || prop.nameType && prop.nameType.flags & TypeFlags.UniqueESSymbol) {
if (isIgnoredJsxProperty(source, prop)) {
continue;
}
const nameType = getSymbolLinks(prop).nameType;
if (nameType && nameType.flags & TypeFlags.UniqueESSymbol) {
continue;
}
if (kind === IndexKind.String || isNumericLiteralName(prop.escapedName)) {
@ -17111,8 +17119,9 @@ namespace ts {
if (source.valueDeclaration) {
symbol.valueDeclaration = source.valueDeclaration;
}
if (source.nameType) {
symbol.nameType = source.nameType;
const nameType = getSymbolLinks(source).nameType;
if (nameType) {
symbol.nameType = nameType;
}
return symbol;
}
@ -27735,17 +27744,24 @@ namespace ts {
const context = getContextNode(node);
const saveContextualType = context.contextualType;
const saveInferenceContext = context.inferenceContext;
context.contextualType = contextualType;
context.inferenceContext = inferenceContext;
const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0));
// We strip literal freshness when an appropriate contextual type is present such that contextually typed
// literals always preserve their literal types (otherwise they might widen during type inference). An alternative
// here would be to not mark contextually typed literals as fresh in the first place.
const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node)) ?
getRegularTypeOfLiteralType(type) : type;
context.contextualType = saveContextualType;
context.inferenceContext = saveInferenceContext;
return result;
try {
context.contextualType = contextualType;
context.inferenceContext = inferenceContext;
const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0));
// We strip literal freshness when an appropriate contextual type is present such that contextually typed
// literals always preserve their literal types (otherwise they might widen during type inference). An alternative
// here would be to not mark contextually typed literals as fresh in the first place.
const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node)) ?
getRegularTypeOfLiteralType(type) : type;
return result;
}
finally {
// In the event our operation is canceled or some other exception occurs, reset the contextual type
// so that we do not accidentally hold onto an instance of the checker, as a Type created in the services layer
// may hold onto the checker that created it.
context.contextualType = saveContextualType;
context.inferenceContext = saveInferenceContext;
}
}
function checkExpressionCached(node: Expression | QualifiedName, checkMode?: CheckMode): Type {
@ -28090,9 +28106,16 @@ namespace ts {
}
const saveContextualType = node.contextualType;
node.contextualType = anyType;
const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
node.contextualType = saveContextualType;
return type;
try {
const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
return type;
}
finally {
// In the event our operation is canceled or some other exception occurs, reset the contextual type
// so that we do not accidentally hold onto an instance of the checker, as a Type created in the services layer
// may hold onto the checker that created it.
node.contextualType = saveContextualType;
}
}
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
@ -31241,6 +31264,14 @@ namespace ts {
return noIterationTypes;
}
function getCachedIterationTypes(type: Type, cacheKey: MatchingKeys<IterableOrIteratorType, IterationTypes | undefined>) {
return (type as IterableOrIteratorType)[cacheKey];
}
function setCachedIterationTypes(type: Type, cacheKey: MatchingKeys<IterableOrIteratorType, IterationTypes | undefined>, cachedTypes: IterationTypes) {
return (type as IterableOrIteratorType)[cacheKey] = cachedTypes;
}
/**
* Gets the *yield*, *return*, and *next* types from an `Iterable`-like or `AsyncIterable`-like type.
*
@ -31279,7 +31310,7 @@ namespace ts {
}
const cacheKey = use & IterationUse.AllowsAsyncIterablesFlag ? "iterationTypesOfAsyncIterable" : "iterationTypesOfIterable";
const cachedTypes = (type as IterableOrIteratorType)[cacheKey];
const cachedTypes = getCachedIterationTypes(type, cacheKey);
if (cachedTypes) return cachedTypes === noIterationTypes ? undefined : cachedTypes;
let allIterationTypes: IterationTypes[] | undefined;
@ -31297,7 +31328,7 @@ namespace ts {
}
const iterationTypes = allIterationTypes ? combineIterationTypes(allIterationTypes) : noIterationTypes;
(type as IterableOrIteratorType)[cacheKey] = iterationTypes;
setCachedIterationTypes(type, cacheKey, iterationTypes);
return iterationTypes === noIterationTypes ? undefined : iterationTypes;
}
@ -31343,7 +31374,7 @@ namespace ts {
if (use & IterationUse.AllowsAsyncIterablesFlag) {
// for a sync iterable in an async context, only use the cached types if they are valid.
if (iterationTypes !== noIterationTypes) {
return (type as IterableOrIteratorType).iterationTypesOfAsyncIterable = getAsyncFromSyncIterationTypes(iterationTypes, errorNode);
return setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", getAsyncFromSyncIterationTypes(iterationTypes, errorNode));
}
}
else {
@ -31363,9 +31394,9 @@ namespace ts {
const iterationTypes = getIterationTypesOfIterableSlow(type, syncIterationTypesResolver, errorNode);
if (iterationTypes !== noIterationTypes) {
if (use & IterationUse.AllowsAsyncIterablesFlag) {
return (type as IterableOrIteratorType).iterationTypesOfAsyncIterable = iterationTypes
return setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes
? getAsyncFromSyncIterationTypes(iterationTypes, errorNode)
: noIterationTypes;
: noIterationTypes);
}
else {
return iterationTypes;
@ -31384,7 +31415,7 @@ namespace ts {
* `getIterationTypesOfIterable` instead.
*/
function getIterationTypesOfIterableCached(type: Type, resolver: IterationTypesResolver) {
return (type as IterableOrIteratorType)[resolver.iterableCacheKey];
return getCachedIterationTypes(type, resolver.iterableCacheKey);
}
function getIterationTypesOfGlobalIterableType(globalType: Type, resolver: IterationTypesResolver) {
@ -31420,7 +31451,7 @@ namespace ts {
// While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use
// different definitions.
const { returnType, nextType } = getIterationTypesOfGlobalIterableType(globalType, resolver);
return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = createIterationTypes(yieldType, returnType, nextType);
return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(yieldType, returnType, nextType));
}
// As an optimization, if the type is an instantiation of the following global type, then
@ -31428,7 +31459,7 @@ namespace ts {
// - `Generator<T, TReturn, TNext>` or `AsyncGenerator<T, TReturn, TNext>`
if (isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) {
const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType);
return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = createIterationTypes(yieldType, returnType, nextType);
return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(yieldType, returnType, nextType));
}
}
@ -31446,17 +31477,17 @@ namespace ts {
const method = getPropertyOfType(type, getPropertyNameForKnownSymbolName(resolver.iteratorSymbolName));
const methodType = method && !(method.flags & SymbolFlags.Optional) ? getTypeOfSymbol(method) : undefined;
if (isTypeAny(methodType)) {
return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = anyIterationTypes;
return setCachedIterationTypes(type, resolver.iterableCacheKey, anyIterationTypes);
}
const signatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : undefined;
if (!some(signatures)) {
return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = noIterationTypes;
return setCachedIterationTypes(type, resolver.iterableCacheKey, noIterationTypes);
}
const iteratorType = getUnionType(map(signatures, getReturnTypeOfSignature), UnionReduction.Subtype);
const iterationTypes = getIterationTypesOfIterator(iteratorType, resolver, errorNode) || noIterationTypes;
return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = iterationTypes;
const iterationTypes = getIterationTypesOfIterator(iteratorType, resolver, errorNode) ?? noIterationTypes;
return setCachedIterationTypes(type, resolver.iterableCacheKey, iterationTypes);
}
function reportTypeNotIterableError(errorNode: Node, type: Type, allowAsyncIterables: boolean): void {
@ -31492,7 +31523,7 @@ namespace ts {
* `getIterationTypesOfIterator` instead.
*/
function getIterationTypesOfIteratorCached(type: Type, resolver: IterationTypesResolver) {
return (type as IterableOrIteratorType)[resolver.iteratorCacheKey];
return getCachedIterationTypes(type, resolver.iteratorCacheKey);
}
/**
@ -31523,12 +31554,12 @@ namespace ts {
getIterationTypesOfIteratorCached(globalType, resolver) ||
getIterationTypesOfIteratorSlow(globalType, resolver, /*errorNode*/ undefined);
const { returnType, nextType } = globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes;
return (type as IterableOrIteratorType)[resolver.iteratorCacheKey] = createIterationTypes(yieldType, returnType, nextType);
return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType));
}
if (isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) ||
isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) {
const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType);
return (type as IterableOrIteratorType)[resolver.iteratorCacheKey] = createIterationTypes(yieldType, returnType, nextType);
return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType));
}
}
@ -31561,7 +31592,7 @@ namespace ts {
return anyIterationTypes;
}
const cachedTypes = (type as IterableOrIteratorType).iterationTypesOfIteratorResult;
const cachedTypes = getCachedIterationTypes(type, "iterationTypesOfIteratorResult");
if (cachedTypes) {
return cachedTypes;
}
@ -31570,11 +31601,11 @@ namespace ts {
// or `IteratorReturnResult<TReturn>` types, then just grab its type argument.
if (isReferenceToType(type, getGlobalIteratorYieldResultType(/*reportErrors*/ false))) {
const yieldType = getTypeArguments(type as GenericType)[0];
return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined);
return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined));
}
if (isReferenceToType(type, getGlobalIteratorReturnResultType(/*reportErrors*/ false))) {
const returnType = getTypeArguments(type as GenericType)[0];
return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined);
return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined));
}
// Choose any constituents that can produce the requested iteration type.
@ -31585,14 +31616,14 @@ namespace ts {
const returnType = returnIteratorResult !== neverType ? getTypeOfPropertyOfType(returnIteratorResult, "value" as __String) : undefined;
if (!yieldType && !returnType) {
return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = noIterationTypes;
return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", noIterationTypes);
}
// From https://tc39.github.io/ecma262/#sec-iteratorresult-interface
// > ... If the iterator does not have a return value, `value` is `undefined`. In that case, the
// > `value` property may be absent from the conforming object if it does not inherit an explicit
// > `value` property.
return (type as IterableOrIteratorType).iterationTypesOfIteratorResult = createIterationTypes(yieldType, returnType || voidType, /*nextType*/ undefined);
return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, returnType || voidType, /*nextType*/ undefined));
}
/**
@ -31694,7 +31725,7 @@ namespace ts {
getIterationTypesOfMethod(type, resolver, "return", errorNode),
getIterationTypesOfMethod(type, resolver, "throw", errorNode),
]);
return (type as IterableOrIteratorType)[resolver.iteratorCacheKey] = iterationTypes;
return setCachedIterationTypes(type, resolver.iteratorCacheKey, iterationTypes);
}
/**

View File

@ -112,8 +112,6 @@ namespace ts {
version?: string;
}
type MatchingKeys<TRecord, TMatch, K extends keyof TRecord = keyof TRecord> = K extends (TRecord[K] extends TMatch ? K : never) ? K : never;
function readPackageJsonField<TMatch, K extends MatchingKeys<PackageJson, string | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined;
function readPackageJsonField<K extends MatchingKeys<PackageJson, object | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "object", state: ModuleResolutionState): PackageJson[K] | undefined;
function readPackageJsonField<K extends keyof PackageJson>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string" | "object", state: ModuleResolutionState): PackageJson[K] | undefined {

View File

@ -3,6 +3,9 @@ namespace ts {
// arbitrary file name can be converted to Path via toPath function
export type Path = string & { __pathBrand: any };
/* @internal */
export type MatchingKeys<TRecord, TMatch, K extends keyof TRecord = keyof TRecord> = K extends (TRecord[K] extends TMatch ? K : never) ? K : never;
export interface TextRange {
pos: number;
end: number;
@ -4045,7 +4048,6 @@ namespace ts {
/* @internal */ mergeId?: number; // Merge id (used to look up merged symbol)
/* @internal */ parent?: Symbol; // Parent symbol
/* @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol
/* @internal */ nameType?: Type; // Type associated with a late-bound symbol
/* @internal */ constEnumOnlyModule?: boolean; // True if module contains only const enums or other modules with only const enums
/* @internal */ isReferenced?: SymbolFlags; // True if the symbol is referenced elsewhere. Keeps track of the meaning of a reference in case a symbol is both a type parameter and parameter.
/* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol?
@ -4058,6 +4060,7 @@ namespace ts {
immediateTarget?: Symbol; // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead.
target?: Symbol; // Resolved (non-alias) target of an alias
type?: Type; // Type of value symbol
nameType?: Type; // Type associated with a late-bound symbol
uniqueESSymbolType?: Type; // UniqueESSymbol type for a symbol
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference