diff --git a/Gulpfile.ts b/Gulpfile.ts
index bf5a074ef06..4f205bfb0ff 100644
--- a/Gulpfile.ts
+++ b/Gulpfile.ts
@@ -50,7 +50,8 @@ const cmdLineOptions = minimist(process.argv.slice(2), {
r: "reporter",
color: "colors",
f: "files",
- file: "files"
+ file: "files",
+ w: "workers",
},
default: {
soft: false,
@@ -63,6 +64,7 @@ const cmdLineOptions = minimist(process.argv.slice(2), {
reporter: process.env.reporter || process.env.r,
lint: process.env.lint || true,
files: process.env.f || process.env.file || process.env.files || "",
+ workers: process.env.workerCount || os.cpus().length,
}
});
@@ -604,7 +606,7 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
} while (fs.existsSync(taskConfigsFolder));
fs.mkdirSync(taskConfigsFolder);
- workerCount = process.env.workerCount || os.cpus().length;
+ workerCount = cmdLineOptions["workers"];
}
if (tests || light || taskConfigsFolder) {
@@ -1017,7 +1019,7 @@ gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are:
cb();
}, (cb) => {
files = files.filter(file => fileMatcher.test(file.path)).sort((filea, fileb) => filea.stat.size - fileb.stat.size);
- const workerCount = (process.env.workerCount && +process.env.workerCount) || os.cpus().length;
+ const workerCount = cmdLineOptions["workers"];
for (let i = 0; i < workerCount; i++) {
spawnLintWorker(files, finished);
}
diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts
index 712c96a49f9..04dc4011a15 100644
--- a/src/compiler/binder.ts
+++ b/src/compiler/binder.ts
@@ -1512,7 +1512,7 @@ namespace ts {
errorOnFirstToken(node, Diagnostics.export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible);
}
if (isExternalModuleAugmentation(node)) {
- declareSymbolAndAddToSymbolTable(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes);
+ declareModuleSymbol(node);
}
else {
let pattern: Pattern | undefined;
@@ -1534,12 +1534,8 @@ namespace ts {
}
}
else {
- const state = getModuleInstanceState(node);
- if (state === ModuleInstanceState.NonInstantiated) {
- declareSymbolAndAddToSymbolTable(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes);
- }
- else {
- declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
+ const state = declareModuleSymbol(node);
+ if (state !== ModuleInstanceState.NonInstantiated) {
if (node.symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum)) {
// if module was already merged with some function, class or non-const enum
// treat is a non-const-enum-only
@@ -1560,6 +1556,15 @@ namespace ts {
}
}
+ function declareModuleSymbol(node: ModuleDeclaration): ModuleInstanceState {
+ const state = getModuleInstanceState(node);
+ const instantiated = state !== ModuleInstanceState.NonInstantiated;
+ declareSymbolAndAddToSymbolTable(node,
+ instantiated ? SymbolFlags.ValueModule : SymbolFlags.NamespaceModule,
+ instantiated ? SymbolFlags.ValueModuleExcludes : SymbolFlags.NamespaceModuleExcludes);
+ return state;
+ }
+
function bindFunctionOrConstructorType(node: SignatureDeclaration): void {
// For a given function symbol "<...>(...) => T" we want to generate a symbol identical
// to the one we would get for: { <...>(...): T }
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 918642dc74b..294571bdbf2 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -1,4 +1,4 @@
-///
+///
///
/* @internal */
@@ -486,6 +486,9 @@ namespace ts {
}
recordMergedSymbol(target, source);
}
+ else if (target.flags & SymbolFlags.NamespaceModule) {
+ error(source.valueDeclaration.name, Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, symbolToString(target));
+ }
else {
const message = target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable
? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0;
@@ -3739,11 +3742,16 @@ namespace ts {
return getObjectFlags(type) & ObjectFlags.Reference ? (type).target : type;
}
- function hasBaseType(type: InterfaceType, checkBase: InterfaceType) {
+ function hasBaseType(type: BaseType, checkBase: BaseType) {
return check(type);
- function check(type: InterfaceType): boolean {
- const target = getTargetType(type);
- return target === checkBase || forEach(getBaseTypes(target), check);
+ function check(type: BaseType): boolean {
+ if (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) {
+ const target = getTargetType(type);
+ return target === checkBase || forEach(getBaseTypes(target), check);
+ }
+ else if (type.flags & TypeFlags.Intersection) {
+ return forEach((type).types, check);
+ }
}
}
@@ -3812,7 +3820,7 @@ namespace ts {
}
function isConstructorType(type: Type): boolean {
- return type.flags & TypeFlags.Object && getSignaturesOfType(type, SignatureKind.Construct).length > 0;
+ return isValidBaseType(type) && getSignaturesOfType(type, SignatureKind.Construct).length > 0;
}
function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments {
@@ -3851,7 +3859,7 @@ namespace ts {
return unknownType;
}
const baseConstructorType = checkExpression(baseTypeNode.expression);
- if (baseConstructorType.flags & TypeFlags.Object) {
+ 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.
resolveStructuredTypeMembers(baseConstructorType);
@@ -3869,7 +3877,7 @@ namespace ts {
return type.resolvedBaseConstructorType;
}
- function getBaseTypes(type: InterfaceType): ObjectType[] {
+ function getBaseTypes(type: InterfaceType): BaseType[] {
if (!type.resolvedBaseTypes) {
if (type.objectFlags & ObjectFlags.Tuple) {
type.resolvedBaseTypes = [createArrayType(getUnionType(type.typeParameters))];
@@ -3892,7 +3900,7 @@ namespace ts {
function resolveBaseTypesOfClass(type: InterfaceType): void {
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
const baseConstructorType = getBaseConstructorTypeOfClass(type);
- if (!(baseConstructorType.flags & TypeFlags.Object)) {
+ if (!(baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection))) {
return;
}
const baseTypeNode = getBaseTypeNodeOfClass(type);
@@ -3929,11 +3937,11 @@ namespace ts {
if (baseType === unknownType) {
return;
}
- if (!(getObjectFlags(getTargetType(baseType)) & ObjectFlags.ClassOrInterface)) {
+ if (!isValidBaseType(baseType)) {
error(baseTypeNode.expression, Diagnostics.Base_constructor_return_type_0_is_not_a_class_or_interface_type, typeToString(baseType));
return;
}
- if (type === baseType || hasBaseType(baseType, type)) {
+ if (type === baseType || hasBaseType(baseType, type)) {
error(valueDecl, Diagnostics.Type_0_recursively_references_itself_as_a_base_type,
typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
return;
@@ -3958,6 +3966,13 @@ namespace ts {
return true;
}
+ // A valid base type is any non-generic object type or intersection of non-generic
+ // object types.
+ function isValidBaseType(type: Type): boolean {
+ return type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
+ type.flags & TypeFlags.Intersection && !forEach((type).types, t => !isValidBaseType(t));
+ }
+
function resolveBaseTypesOfInterface(type: InterfaceType): void {
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
for (const declaration of type.symbol.declarations) {
@@ -3965,8 +3980,8 @@ namespace ts {
for (const node of getInterfaceBaseTypeNodes(declaration)) {
const baseType = getTypeFromTypeNode(node);
if (baseType !== unknownType) {
- if (getObjectFlags(getTargetType(baseType)) & ObjectFlags.ClassOrInterface) {
- if (type !== baseType && !hasBaseType(baseType, type)) {
+ if (isValidBaseType(baseType)) {
+ if (type !== baseType && !hasBaseType(baseType, type)) {
if (type.resolvedBaseTypes === emptyArray) {
type.resolvedBaseTypes = [baseType];
}
@@ -4322,8 +4337,14 @@ namespace ts {
function getTypeWithThisArgument(type: Type, thisArgument?: Type): Type {
if (getObjectFlags(type) & ObjectFlags.Reference) {
- return createTypeReference((type).target,
- concatenate((type).typeArguments, [thisArgument || (type).target.thisType]));
+ const target = (type).target;
+ const typeArguments = (type).typeArguments;
+ if (length(target.typeParameters) === length(typeArguments)) {
+ return createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType]));
+ }
+ }
+ else if (type.flags & TypeFlags.Intersection) {
+ return getIntersectionType(map((type).types, t => getTypeWithThisArgument(t, thisArgument)));
}
return type;
}
@@ -4358,8 +4379,8 @@ namespace ts {
}
const thisArgument = lastOrUndefined(typeArguments);
for (const baseType of baseTypes) {
- const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType;
- addInheritedMembers(members, getPropertiesOfObjectType(instantiatedBaseType));
+ const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType;
+ addInheritedMembers(members, getPropertiesOfType(instantiatedBaseType));
callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call));
constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct));
stringIndexInfo = stringIndexInfo || getIndexInfoOfType(instantiatedBaseType, IndexKind.String);
@@ -4584,9 +4605,9 @@ namespace ts {
constructSignatures = getDefaultConstructSignatures(classType);
}
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
- if (baseConstructorType.flags & TypeFlags.Object) {
+ if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
members = createSymbolTable(getNamedMembers(members));
- addInheritedMembers(members, getPropertiesOfObjectType(baseConstructorType));
+ addInheritedMembers(members, getPropertiesOfType(baseConstructorType));
}
}
const numberIndexInfo = symbol.flags & SymbolFlags.Enum ? enumNumberIndexInfo : undefined;
@@ -4612,12 +4633,14 @@ namespace ts {
const typeParameter = getTypeParameterFromMappedType(type);
const constraintType = getConstraintTypeFromMappedType(type);
const templateType = getTemplateTypeFromMappedType(type);
- const modifiersType = getApparentType(getModifiersTypeFromMappedType(type));
+ const modifiersType = getApparentType(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 }
- forEachType(getLiteralTypeFromPropertyNames(modifiersType), addMemberForKeyType);
+ for (const propertySymbol of getPropertiesOfType(modifiersType)) {
+ addMemberForKeyType(getLiteralTypeFromPropertyName(propertySymbol), propertySymbol);
+ }
if (getIndexInfoOfType(modifiersType, IndexKind.String)) {
addMemberForKeyType(stringType);
}
@@ -4632,7 +4655,7 @@ namespace ts {
}
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined);
- function addMemberForKeyType(t: Type) {
+ 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.
@@ -4648,6 +4671,9 @@ namespace ts {
const prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName);
prop.type = propType;
prop.isReadonly = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp);
+ if (propertySymbol) {
+ prop.mappedTypeOrigin = propertySymbol;
+ }
members.set(propName, prop);
}
else if (t.flags & TypeFlags.String) {
@@ -4750,28 +4776,26 @@ namespace ts {
}
function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] {
- for (const current of type.types) {
- for (const prop of getPropertiesOfType(current)) {
- getUnionOrIntersectionProperty(type, prop.name);
- }
- // The properties of a union type are those that are present in all constituent types, so
- // we only need to check the properties of the first type
- if (type.flags & TypeFlags.Union) {
- break;
- }
- }
- const props = type.resolvedProperties;
- if (props) {
- const result: Symbol[] = [];
- props.forEach(prop => {
- // We need to filter out partial properties in union types
- if (!(prop.flags & SymbolFlags.SyntheticProperty && (prop).isPartial)) {
- result.push(prop);
+ if (!type.resolvedProperties) {
+ const members = createMap();
+ for (const current of type.types) {
+ for (const prop of getPropertiesOfType(current)) {
+ if (!members.has(prop.name)) {
+ const combinedProp = getPropertyOfUnionOrIntersectionType(type, prop.name);
+ if (combinedProp) {
+ members.set(prop.name, combinedProp);
+ }
+ }
}
- });
- return result;
+ // The properties of a union type are those that are present in all constituent types, so
+ // we only need to check the properties of the first type
+ if (type.flags & TypeFlags.Union) {
+ break;
+ }
+ }
+ type.resolvedProperties = getNamedMembers(members);
}
- return emptyArray;
+ return type.resolvedProperties;
}
function getPropertiesOfType(type: Type): Symbol[] {
@@ -4856,6 +4880,10 @@ namespace ts {
}
}
+ function getApparentTypeOfIntersectionType(type: IntersectionType) {
+ return type.resolvedIndexType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
+ }
+
/**
* Gets the default type for a type parameter.
*
@@ -4886,7 +4914,8 @@ namespace ts {
*/
function getApparentType(type: Type): Type {
const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type;
- return t.flags & TypeFlags.StringLike ? globalStringType :
+ return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t) :
+ t.flags & TypeFlags.StringLike ? globalStringType :
t.flags & TypeFlags.NumberLike ? globalNumberType :
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType() :
@@ -4962,7 +4991,7 @@ namespace ts {
// these partial properties when identifying discriminant properties, but otherwise they are filtered out
// and do not appear to be present in the union type.
function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: string): Symbol {
- const properties = type.resolvedProperties || (type.resolvedProperties = createMap());
+ const properties = type.propertyCache || (type.propertyCache = createMap());
let property = properties.get(name);
if (!property) {
property = createUnionOrIntersectionProperty(type, name);
@@ -6398,6 +6427,9 @@ namespace ts {
if (right.flags & TypeFlags.Union) {
return mapType(right, t => getSpreadType(left, t));
}
+ if (right.flags & TypeFlags.NonPrimitive) {
+ return emptyObjectType;
+ }
const members = createMap();
const skippedPrivateMembers = createMap();
@@ -11807,7 +11839,7 @@ namespace ts {
member = prop;
}
else if (memberDecl.kind === SyntaxKind.SpreadAssignment) {
- if (languageVersion < ScriptTarget.ESNext) {
+ if (languageVersion < ScriptTarget.ES2015) {
checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign);
}
if (propertiesArray.length > 0) {
@@ -11901,7 +11933,7 @@ namespace ts {
}
function isValidSpreadType(type: Type): boolean {
- return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined) ||
+ return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined | TypeFlags.NonPrimitive) ||
type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
type.flags & TypeFlags.UnionOrIntersection && !forEach((type).types, t => !isValidSpreadType(t)));
}
@@ -11965,6 +11997,16 @@ namespace ts {
function checkJsxAttribute(node: JsxAttribute, elementAttributesType: Type, nameTable: Map) {
let correspondingPropType: Type = undefined;
+ // We need to unconditionally get the expression type
+ let exprType: Type;
+ if (node.initializer) {
+ exprType = checkExpression(node.initializer);
+ }
+ else {
+ // is sugar for
+ exprType = booleanType;
+ }
+
// Look up the corresponding property for this attribute
if (elementAttributesType === emptyObjectType && isUnhyphenatedJsxName(node.name.text)) {
// If there is no 'props' property, you may not have non-"data-" attributes
@@ -11988,15 +12030,6 @@ namespace ts {
}
}
- let exprType: Type;
- if (node.initializer) {
- exprType = checkExpression(node.initializer);
- }
- else {
- // is sugar for
- exprType = booleanType;
- }
-
if (correspondingPropType) {
checkTypeAssignableTo(exprType, correspondingPropType, node);
}
@@ -12422,12 +12455,15 @@ namespace ts {
// - In a static member function or static member accessor
// where this references the constructor function object of a derived class,
// a super property access is permitted and must specify a public static member function of the base class.
- if (languageVersion < ScriptTarget.ES2015 && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) {
- // `prop` refers to a *property* declared in the super class
- // rather than a *method*, so it does not satisfy the above criteria.
+ if (languageVersion < ScriptTarget.ES2015) {
+ const propKind = getDeclarationKindFromSymbol(prop);
+ if (propKind !== SyntaxKind.MethodDeclaration && propKind !== SyntaxKind.MethodSignature) {
+ // `prop` refers to a *property* declared in the super class
+ // rather than a *method*, so it does not satisfy the above criteria.
- error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword);
- return false;
+ error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword);
+ return false;
+ }
}
if (flags & ModifierFlags.Abstract) {
@@ -18360,16 +18396,18 @@ namespace ts {
return;
}
+ const propDeclaration = prop.valueDeclaration;
+
// index is numeric and property name is not valid numeric literal
- if (indexKind === IndexKind.Number && !isNumericName(prop.valueDeclaration.name)) {
+ if (indexKind === IndexKind.Number && !(propDeclaration ? isNumericName(propDeclaration.name) : isNumericLiteralName(prop.name))) {
return;
}
// perform property check if property or indexer is declared in 'type'
// this allows to rule out cases when both property and indexer are inherited from the base class
let errorNode: Node;
- if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) {
- errorNode = prop.valueDeclaration;
+ if (propDeclaration && (propDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol)) {
+ errorNode = propDeclaration;
}
else if (indexDeclaration) {
errorNode = indexDeclaration;
@@ -18585,7 +18623,11 @@ namespace ts {
const staticType = getTypeOfSymbol(symbol);
checkTypeParameterListsIdentical(node, symbol);
checkClassForDuplicateDeclarations(node);
- checkClassForStaticPropertyNameConflicts(node);
+
+ // Only check for reserved static identifiers on non-ambient context.
+ if (!isInAmbientContext(node)) {
+ checkClassForStaticPropertyNameConflicts(node);
+ }
const baseTypeNode = getClassExtendsHeritageClauseElement(node);
if (baseTypeNode) {
@@ -18611,7 +18653,7 @@ namespace ts {
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node,
Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1);
- if (baseType.symbol.valueDeclaration &&
+ if (baseType.symbol && baseType.symbol.valueDeclaration &&
!isInAmbientContext(baseType.symbol.valueDeclaration) &&
baseType.symbol.valueDeclaration.kind === SyntaxKind.ClassDeclaration) {
if (!isBlockScopedNameDeclaredBeforeUse(baseType.symbol.valueDeclaration, node)) {
@@ -18643,8 +18685,7 @@ namespace ts {
if (produceDiagnostics) {
const t = getTypeFromTypeNode(typeRefNode);
if (t !== unknownType) {
- const declaredType = getObjectFlags(t) & ObjectFlags.Reference ? (t).target : t;
- if (getObjectFlags(declaredType) & ObjectFlags.ClassOrInterface) {
+ if (isValidBaseType(t)) {
checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(t, type.thisType), node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1);
}
else {
@@ -18684,7 +18725,7 @@ namespace ts {
return forEach(symbol.declarations, d => isClassLike(d) ? d : undefined);
}
- function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: ObjectType): void {
+ function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: BaseType): void {
// TypeScript 1.0 spec (April 2014): 8.2.3
// A derived class inherits all members from its base class it doesn't override.
@@ -18701,7 +18742,7 @@ namespace ts {
// derived class instance member variables and accessors, but not by other kinds of members.
// NOTE: assignability is checked in checkClassDeclaration
- const baseProperties = getPropertiesOfObjectType(baseType);
+ const baseProperties = getPropertiesOfType(baseType);
for (const baseProperty of baseProperties) {
const base = getTargetSymbol(baseProperty);
@@ -18796,7 +18837,7 @@ namespace ts {
let ok = true;
for (const base of baseTypes) {
- const properties = getPropertiesOfObjectType(getTypeWithThisArgument(base, type.thisType));
+ const properties = getPropertiesOfType(getTypeWithThisArgument(base, type.thisType));
for (const prop of properties) {
const existing = seen.get(prop.name);
if (!existing) {
@@ -20423,6 +20464,10 @@ namespace ts {
const links = symbol as SymbolLinks;
return [links.leftSpread, links.rightSpread];
}
+ if ((symbol as SymbolLinks).mappedTypeOrigin) {
+ return getRootSymbols((symbol as SymbolLinks).mappedTypeOrigin);
+ }
+
let target: Symbol;
let next = symbol;
while (next = getSymbolLinks(next).target) {
diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts
index b222df53630..4ee76d7b817 100644
--- a/src/compiler/commandLineParser.ts
+++ b/src/compiler/commandLineParser.ts
@@ -67,10 +67,11 @@ namespace ts {
name: "jsx",
type: createMapFromTemplate({
"preserve": JsxEmit.Preserve,
+ "react-native": JsxEmit.ReactNative,
"react": JsxEmit.React
}),
paramType: Diagnostics.KIND,
- description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_or_react,
+ description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_react_native_or_react,
},
{
name: "reactNamespace",
@@ -1257,7 +1258,6 @@ namespace ts {
const literalFiles = arrayFrom(literalFileMap.values());
const wildcardFiles = arrayFrom(wildcardFileMap.values());
- wildcardFiles.sort(host.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
return {
fileNames: literalFiles.concat(wildcardFiles),
wildcardDirectories
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index c26e04ee1f3..de3472afd88 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -204,6 +204,10 @@ namespace ts {
GreaterThan = 1
}
+ export function length(array: any[]) {
+ return array ? array.length : 0;
+ }
+
/**
* Iterates through 'array' by index and performs the callback on each element of array until the callback
* returns a truthy value, then returns that value.
@@ -256,6 +260,16 @@ namespace ts {
return undefined;
}
+ /** Works like Array.prototype.findIndex, returning `-1` if no element satisfying the predicate is found. */
+ export function findIndex(array: T[], predicate: (element: T, index: number) => boolean): number {
+ for (let i = 0; i < array.length; i++) {
+ if (predicate(array[i], i)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
/**
* Returns the first truthy result of `callback`, or else fails.
* This is like `forEach`, but never returns undefined.
@@ -1720,7 +1734,19 @@ namespace ts {
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
const singleAsteriskRegexFragmentOther = "[^/]*";
- export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude") {
+ export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
+ const patterns = getRegularExpressionsForWildcards(specs, basePath, usage);
+ if (!patterns || !patterns.length) {
+ return undefined;
+ }
+
+ const pattern = patterns.map(pattern => `(${pattern})`).join("|");
+ // If excluding, match "foo/bar/baz...", but if including, only allow "foo".
+ const terminator = usage === "exclude" ? "($|/)" : "$";
+ return `^(${pattern})${terminator}`;
+ }
+
+ function getRegularExpressionsForWildcards(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
if (specs === undefined || specs.length === 0) {
return undefined;
}
@@ -1734,33 +1760,8 @@ namespace ts {
*/
const doubleAsteriskRegexFragment = usage === "exclude" ? "(/.+?)?" : "(/[^/.][^/]*)*?";
- let pattern = "";
- let hasWrittenSubpattern = false;
- for (const spec of specs) {
- if (!spec) {
- continue;
- }
-
- const subPattern = getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter);
- if (subPattern === undefined) {
- continue;
- }
-
- if (hasWrittenSubpattern) {
- pattern += "|";
- }
-
- pattern += "(" + subPattern + ")";
- hasWrittenSubpattern = true;
- }
-
- if (!pattern) {
- return undefined;
- }
-
- // If excluding, match "foo/bar/baz...", but if including, only allow "foo".
- const terminator = usage === "exclude" ? "($|/)" : "$";
- return `^(${pattern})${terminator}`;
+ return flatMap(specs, spec =>
+ spec && getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter));
}
/**
@@ -1855,6 +1856,9 @@ namespace ts {
}
export interface FileMatcherPatterns {
+ /** One pattern for each "include" spec. */
+ includeFilePatterns: string[];
+ /** One pattern matching one of any of the "include" specs. */
includeFilePattern: string;
includeDirectoryPattern: string;
excludePattern: string;
@@ -1867,6 +1871,7 @@ namespace ts {
const absolutePath = combinePaths(currentDirectory, path);
return {
+ includeFilePatterns: map(getRegularExpressionsForWildcards(includes, absolutePath, "files"), pattern => `^${pattern}$`),
includeFilePattern: getRegularExpressionForWildcard(includes, absolutePath, "files"),
includeDirectoryPattern: getRegularExpressionForWildcard(includes, absolutePath, "directories"),
excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, "exclude"),
@@ -1881,26 +1886,39 @@ namespace ts {
const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory);
const regexFlag = useCaseSensitiveFileNames ? "" : "i";
- const includeFileRegex = patterns.includeFilePattern && new RegExp(patterns.includeFilePattern, regexFlag);
+ const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => new RegExp(pattern, regexFlag));
const includeDirectoryRegex = patterns.includeDirectoryPattern && new RegExp(patterns.includeDirectoryPattern, regexFlag);
const excludeRegex = patterns.excludePattern && new RegExp(patterns.excludePattern, regexFlag);
- const result: string[] = [];
+ // Associate an array of results with each include regex. This keeps results in order of the "include" order.
+ // If there are no "includes", then just put everything in results[0].
+ const results: string[][] = includeFileRegexes ? includeFileRegexes.map(() => []) : [[]];
+
+ const comparer = useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive;
for (const basePath of patterns.basePaths) {
visitDirectory(basePath, combinePaths(currentDirectory, basePath));
}
- return result;
+
+ return flatten(results);
function visitDirectory(path: string, absolutePath: string) {
- const { files, directories } = getFileSystemEntries(path);
+ let { files, directories } = getFileSystemEntries(path);
+ files = files.slice().sort(comparer);
+ directories = directories.slice().sort(comparer);
for (const current of files) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
- if ((!extensions || fileExtensionIsAny(name, extensions)) &&
- (!includeFileRegex || includeFileRegex.test(absoluteName)) &&
- (!excludeRegex || !excludeRegex.test(absoluteName))) {
- result.push(name);
+ if (extensions && !fileExtensionIsAny(name, extensions)) continue;
+ if (excludeRegex && excludeRegex.test(absoluteName)) continue;
+ if (!includeFileRegexes) {
+ results[0].push(name);
+ }
+ else {
+ const includeIndex = findIndex(includeFileRegexes, re => re.test(absoluteName));
+ if (includeIndex !== -1) {
+ results[includeIndex].push(name);
+ }
}
}
diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts
index a51732cc82d..bc2e967ede1 100644
--- a/src/compiler/declarationEmitter.ts
+++ b/src/compiler/declarationEmitter.ts
@@ -32,7 +32,7 @@ namespace ts {
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] {
const declarationDiagnostics = createDiagnosticCollection();
- forEachExpectedEmitFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile);
+ forEachEmittedFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile);
return declarationDiagnostics.getDiagnostics(targetSourceFile ? targetSourceFile.fileName : undefined);
function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sources: SourceFile[], isBundledEmit: boolean) {
@@ -1805,7 +1805,7 @@ namespace ts {
}
else {
// Get the declaration file path
- forEachExpectedEmitFile(host, getDeclFileName, referencedFile, emitOnlyDtsFiles);
+ forEachEmittedFile(host, getDeclFileName, referencedFile, emitOnlyDtsFiles);
}
if (declFileName) {
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index fc672f866bf..22c31b30893 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -1827,6 +1827,10 @@
"category": "Error",
"code": 2609
},
+ "Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": {
+ "category": "Error",
+ "code": 2649
+ },
"Cannot emit namespaced JSX elements in React": {
"category": "Error",
"code": 2650
@@ -2725,7 +2729,7 @@
"category": "Message",
"code": 6079
},
- "Specify JSX code generation: 'preserve' or 'react'": {
+ "Specify JSX code generation: 'preserve', 'react-native', or 'react'": {
"category": "Message",
"code": 6080
},
@@ -3275,6 +3279,10 @@
"category": "Message",
"code": 90007
},
+ "Add 'this.' to unresolved variable.": {
+ "category": "Message",
+ "code": 90008
+ },
"Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig": {
"category": "Error",
"code": 90009
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index 2ff342138c8..27285a4c2dc 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -73,7 +73,7 @@ namespace ts {
// Emit each output file
performance.mark("beforePrint");
- forEachTransformedEmitFile(host, transformed, emitFile, emitOnlyDtsFiles);
+ forEachEmittedFile(host, emitFile, transformed, emitOnlyDtsFiles);
performance.measure("printTime", "beforePrint");
// Clean up emit nodes on parse tree
@@ -88,7 +88,7 @@ namespace ts {
sourceMaps: sourceMapDataList
};
- function emitFile(jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
+ function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath }: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) {
// Make sure not to write js file and source map file if any of them cannot be written
if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) {
if (!emitOnlyDtsFiles) {
@@ -1054,9 +1054,11 @@ namespace ts {
// Also emit a dot if expression is a integer const enum value - it will appear in generated code as numeric literal
function needsDotDotForPropertyAccess(expression: Expression) {
if (expression.kind === SyntaxKind.NumericLiteral) {
- // check if numeric literal was originally written with a dot
+ // check if numeric literal is a decimal literal that was originally written with a dot
const text = getLiteralTextOfNode(expression);
- return text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0;
+ return getNumericLiteralFlags(text, /*hint*/ NumericLiteralFlags.All) === NumericLiteralFlags.None
+ && !(expression).isOctalLiteral
+ && text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0;
}
else if (isPropertyAccessExpression(expression) || isElementAccessExpression(expression)) {
// check if constant enum value is integer
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index ae61a82b9c7..7e627568fac 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -6698,10 +6698,15 @@ namespace ts {
typedefTag.fullName = parseJSDocTypeNameWithNamespace(/*flags*/ 0);
if (typedefTag.fullName) {
let rightNode = typedefTag.fullName;
- while (rightNode.kind !== SyntaxKind.Identifier) {
+ while (true) {
+ if (rightNode.kind === SyntaxKind.Identifier || !rightNode.body) {
+ // if node is identifier - use it as name
+ // otherwise use name of the rightmost part that we were able to parse
+ typedefTag.name = rightNode.kind === SyntaxKind.Identifier ? rightNode : rightNode.name;
+ break;
+ }
rightNode = rightNode.body;
}
- typedefTag.name = rightNode;
}
typedefTag.typeExpression = typeExpression;
skipWhitespace();
diff --git a/src/compiler/program.ts b/src/compiler/program.ts
index 324a21f229e..650711afc79 100644
--- a/src/compiler/program.ts
+++ b/src/compiler/program.ts
@@ -439,7 +439,7 @@ namespace ts {
function getCommonSourceDirectory() {
if (commonSourceDirectory === undefined) {
- const emittedFiles = filterSourceFilesInDirectory(files, isSourceFileFromExternalLibrary);
+ const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary));
if (options.rootDir && checkSourceFilesBelongToPath(emittedFiles, options.rootDir)) {
// If a rootDir is specified and is valid use it as the commonSourceDirectory
commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, currentDirectory);
@@ -1707,7 +1707,7 @@ namespace ts {
if (!options.noEmit && !options.suppressOutputPathCheck) {
const emitHost = getEmitHost();
const emitFilesSeen = createFileMap(!host.useCaseSensitiveFileNames() ? key => key.toLocaleLowerCase() : undefined);
- forEachExpectedEmitFile(emitHost, (emitFileNames) => {
+ forEachEmittedFile(emitHost, (emitFileNames) => {
verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen);
verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen);
});
diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts
index d1dab8eeb7a..3b8b4524aab 100644
--- a/src/compiler/transformers/es2015.ts
+++ b/src/compiler/transformers/es2015.ts
@@ -2316,7 +2316,7 @@ namespace ts {
addRange(statements, convertedLoopBodyStatements);
}
else {
- const statement = visitNode(node.statement, visitor, isStatement);
+ const statement = visitNode(node.statement, visitor, isStatement, /*optional*/ false, liftToBlock);
if (isBlock(statement)) {
addRange(statements, statement.statements);
bodyLocation = statement;
diff --git a/src/compiler/transformers/es5.ts b/src/compiler/transformers/es5.ts
index 6dd875965d9..c3b011fe36d 100644
--- a/src/compiler/transformers/es5.ts
+++ b/src/compiler/transformers/es5.ts
@@ -11,10 +11,10 @@ namespace ts {
export function transformES5(context: TransformationContext) {
const compilerOptions = context.getCompilerOptions();
- // enable emit notification only if using --jsx preserve
+ // enable emit notification only if using --jsx preserve or react-native
let previousOnEmitNode: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void;
let noSubstitution: boolean[];
- if (compilerOptions.jsx === JsxEmit.Preserve) {
+ if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) {
previousOnEmitNode = context.onEmitNode;
context.onEmitNode = onEmitNode;
context.enableEmitNotification(SyntaxKind.JsxOpeningElement);
@@ -116,4 +116,4 @@ namespace ts {
return undefined;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts
index 0a529a8e871..8b5a095a17e 100644
--- a/src/compiler/transformers/esnext.ts
+++ b/src/compiler/transformers/esnext.ts
@@ -402,6 +402,11 @@ namespace ts {
};
export function createAssignHelper(context: TransformationContext, attributesSegments: Expression[]) {
+ if (context.getCompilerOptions().target >= ScriptTarget.ES2015) {
+ return createCall(createPropertyAccess(createIdentifier("Object"), "assign"),
+ /*typeArguments*/ undefined,
+ attributesSegments);
+ }
context.requestEmitHelper(assignHelper);
return createCall(
getHelperName("__assign"),
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 6503d229bbe..bd17b844d38 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -2359,7 +2359,7 @@
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo;
getSignaturesOfType(type: Type, kind: SignatureKind): Signature[];
getIndexTypeOfType(type: Type, kind: IndexKind): Type;
- getBaseTypes(type: InterfaceType): ObjectType[];
+ getBaseTypes(type: InterfaceType): BaseType[];
getReturnTypeOfSignature(signature: Signature): Type;
/**
* Gets the type of a parameter at a given position in a signature.
@@ -2714,6 +2714,7 @@
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
leftSpread?: Symbol; // Left source for synthetic spread property
rightSpread?: Symbol; // Right source for synthetic spread property
+ mappedTypeOrigin?: Symbol; // For a property on a mapped type, points back to the orignal 'T' from 'keyof T'.
hasNonUniformType?: boolean; // True if constituents have non-uniform types
isPartial?: boolean; // True if syntheric property of union type occurs in some but not all constituents
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
@@ -2914,9 +2915,12 @@
/* @internal */
resolvedBaseConstructorType?: Type; // Resolved base constructor type of class
/* @internal */
- resolvedBaseTypes: ObjectType[]; // Resolved base types
+ resolvedBaseTypes: BaseType[]; // Resolved base types
}
+ // Object type or intersection of object types
+ export type BaseType = ObjectType | IntersectionType;
+
export interface InterfaceTypeWithDeclaredMembers extends InterfaceType {
declaredProperties: Symbol[]; // Declared members
declaredCallSignatures: Signature[]; // Declared call signatures
@@ -2949,7 +2953,9 @@
export interface UnionOrIntersectionType extends Type {
types: Type[]; // Constituent types
/* @internal */
- resolvedProperties: SymbolTable; // Cache of resolved properties
+ propertyCache: SymbolTable; // Cache of resolved properties
+ /* @internal */
+ resolvedProperties: Symbol[];
/* @internal */
resolvedIndexType: IndexType;
/* @internal */
@@ -2960,7 +2966,10 @@
export interface UnionType extends UnionOrIntersectionType { }
- export interface IntersectionType extends UnionOrIntersectionType { }
+ export interface IntersectionType extends UnionOrIntersectionType {
+ /* @internal */
+ resolvedApparentType: Type;
+ }
export type StructuredType = ObjectType | UnionType | IntersectionType;
@@ -3299,7 +3308,8 @@
export const enum JsxEmit {
None = 0,
Preserve = 1,
- React = 2
+ React = 2,
+ ReactNative = 3
}
export const enum NewLineKind {
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index 6033f4d0836..70bb652f9ca 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -355,16 +355,52 @@ namespace ts {
}
export function isBinaryOrOctalIntegerLiteral(node: LiteralLikeNode, text: string) {
- if (node.kind === SyntaxKind.NumericLiteral && text.length > 1) {
+ return node.kind === SyntaxKind.NumericLiteral
+ && (getNumericLiteralFlags(text, /*hint*/ NumericLiteralFlags.BinaryOrOctal) & NumericLiteralFlags.BinaryOrOctal) !== 0;
+ }
+
+ export const enum NumericLiteralFlags {
+ None = 0,
+ Hexadecimal = 1 << 0,
+ Binary = 1 << 1,
+ Octal = 1 << 2,
+ Scientific = 1 << 3,
+
+ BinaryOrOctal = Binary | Octal,
+ BinaryOrOctalOrHexadecimal = BinaryOrOctal | Hexadecimal,
+ All = Hexadecimal | Binary | Octal | Scientific,
+ }
+
+ /**
+ * Scans a numeric literal string to determine the form of the number.
+ * @param text Numeric literal text
+ * @param hint If `Scientific` or `All` is specified, performs a more expensive check to scan for scientific notation.
+ */
+ export function getNumericLiteralFlags(text: string, hint?: NumericLiteralFlags) {
+ if (text.length > 1) {
switch (text.charCodeAt(1)) {
case CharacterCodes.b:
case CharacterCodes.B:
+ return NumericLiteralFlags.Binary;
case CharacterCodes.o:
case CharacterCodes.O:
- return true;
+ return NumericLiteralFlags.Octal;
+ case CharacterCodes.x:
+ case CharacterCodes.X:
+ return NumericLiteralFlags.Hexadecimal;
+ }
+
+ if (hint & NumericLiteralFlags.Scientific) {
+ for (let i = text.length - 1; i >= 0; i--) {
+ switch (text.charCodeAt(i)) {
+ case CharacterCodes.e:
+ case CharacterCodes.E:
+ return NumericLiteralFlags.Scientific;
+ }
+ }
}
}
- return false;
+ return NumericLiteralFlags.None;
}
function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) {
@@ -409,7 +445,7 @@ namespace ts {
function isShorthandAmbientModule(node: Node): boolean {
// The only kind of module that can be missing a body is a shorthand ambient module.
- return node.kind === SyntaxKind.ModuleDeclaration && (!(node).body);
+ return node && node.kind === SyntaxKind.ModuleDeclaration && (!(node).body);
}
export function isBlockScopedContainerTopLevel(node: Node): boolean {
@@ -1676,11 +1712,15 @@ namespace ts {
node = parent;
break;
case SyntaxKind.ShorthandPropertyAssignment:
- if ((parent).name !== node) {
+ if ((parent as ShorthandPropertyAssignment).name !== node) {
return AssignmentKind.None;
}
- // Fall through
+ node = parent.parent;
+ break;
case SyntaxKind.PropertyAssignment:
+ if ((parent as ShorthandPropertyAssignment).name === node) {
+ return AssignmentKind.None;
+ }
node = parent.parent;
break;
default:
@@ -1692,7 +1732,8 @@ namespace ts {
// A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property
// assignment in an object literal that is an assignment target, or if it is parented by an array literal that is
- // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'.
+ // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ a }] = xxx'.
+ // (Note that `p` is not a target in the above examples, only `a`.)
export function isAssignmentTarget(node: Node): boolean {
return getAssignmentTargetKind(node) !== AssignmentKind.None;
}
@@ -2582,102 +2623,57 @@ namespace ts {
* @param host An EmitHost.
* @param targetSourceFile An optional target source file to emit.
*/
- export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFile) {
+ export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFile): SourceFile[] {
const options = host.getCompilerOptions();
+ const isSourceFileFromExternalLibrary = (file: SourceFile) => host.isSourceFileFromExternalLibrary(file);
if (options.outFile || options.out) {
const moduleKind = getEmitModuleKind(options);
const moduleEmitEnabled = moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System;
- const sourceFiles = getAllEmittableSourceFiles();
// Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified
- return filter(sourceFiles, moduleEmitEnabled ? isNonDeclarationFile : isBundleEmitNonExternalModule);
+ return filter(host.getSourceFiles(), sourceFile =>
+ (moduleEmitEnabled || !isExternalModule(sourceFile)) && sourceFileMayBeEmitted(sourceFile, options, isSourceFileFromExternalLibrary));
}
else {
- const sourceFiles = targetSourceFile === undefined ? getAllEmittableSourceFiles() : [targetSourceFile];
- return filterSourceFilesInDirectory(sourceFiles, file => host.isSourceFileFromExternalLibrary(file));
- }
-
- function getAllEmittableSourceFiles() {
- return options.noEmitForJsFiles ? filter(host.getSourceFiles(), sourceFile => !isSourceFileJavaScript(sourceFile)) : host.getSourceFiles();
+ const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile];
+ return filter(sourceFiles, sourceFile => sourceFileMayBeEmitted(sourceFile, options, isSourceFileFromExternalLibrary));
}
}
- /** Don't call this for `--outFile`, just for `--outDir` or plain emit. */
- export function filterSourceFilesInDirectory(sourceFiles: SourceFile[], isSourceFileFromExternalLibrary: (file: SourceFile) => boolean): SourceFile[] {
- return filter(sourceFiles, file => shouldEmitInDirectory(file, isSourceFileFromExternalLibrary));
- }
-
- function isNonDeclarationFile(sourceFile: SourceFile) {
- return !isDeclarationFile(sourceFile);
+ /** Don't call this for `--outFile`, just for `--outDir` or plain emit. `--outFile` needs additional checks. */
+ export function sourceFileMayBeEmitted(sourceFile: SourceFile, options: CompilerOptions, isSourceFileFromExternalLibrary: (file: SourceFile) => boolean) {
+ return !(options.noEmitForJsFiles && isSourceFileJavaScript(sourceFile)) && !isDeclarationFile(sourceFile) && !isSourceFileFromExternalLibrary(sourceFile);
}
/**
- * Whether a file should be emitted in a non-`--outFile` case.
- * Don't emit if source file is a declaration file, or was located under node_modules
- */
- function shouldEmitInDirectory(sourceFile: SourceFile, isSourceFileFromExternalLibrary: (file: SourceFile) => boolean): boolean {
- return isNonDeclarationFile(sourceFile) && !isSourceFileFromExternalLibrary(sourceFile);
- }
-
- function isBundleEmitNonExternalModule(sourceFile: SourceFile) {
- return isNonDeclarationFile(sourceFile) && !isExternalModule(sourceFile);
- }
-
- /**
- * Iterates over each source file to emit. The source files are expected to have been
- * transformed for use by the pretty printer.
- *
- * Originally part of `forEachExpectedEmitFile`, this functionality was extracted to support
- * transformations.
+ * Iterates over the source files that are expected to have an emit output.
*
* @param host An EmitHost.
- * @param sourceFiles The transformed source files to emit.
* @param action The action to execute.
+ * @param sourceFilesOrTargetSourceFile
+ * If an array, the full list of source files to emit.
+ * Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
*/
- export function forEachTransformedEmitFile(host: EmitHost, sourceFiles: SourceFile[],
- action: (jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) => void,
+ export function forEachEmittedFile(
+ host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void,
+ sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile,
emitOnlyDtsFiles?: boolean) {
+
+ const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile);
const options = host.getCompilerOptions();
- // Emit on each source file
if (options.outFile || options.out) {
- onBundledEmit(sourceFiles);
- }
- else {
- for (const sourceFile of sourceFiles) {
- // Don't emit if source file is a declaration file, or was located under node_modules
- if (!isDeclarationFile(sourceFile) && !host.isSourceFileFromExternalLibrary(sourceFile)) {
- onSingleFileEmit(host, sourceFile);
- }
- }
- }
-
- function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) {
- // JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
- // So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
- // For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
- let extension = ".js";
- if (options.jsx === JsxEmit.Preserve) {
- if (isSourceFileJavaScript(sourceFile)) {
- if (fileExtensionIs(sourceFile.fileName, ".jsx")) {
- extension = ".jsx";
- }
- }
- else if (sourceFile.languageVariant === LanguageVariant.JSX) {
- // TypeScript source file preserving JSX syntax
- extension = ".jsx";
- }
- }
- const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, extension);
- const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
- const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (options.declaration || emitOnlyDtsFiles) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
- action(jsFilePath, sourceMapFilePath, declarationFilePath, [sourceFile], /*isBundledEmit*/ false);
- }
-
- function onBundledEmit(sourceFiles: SourceFile[]) {
if (sourceFiles.length) {
const jsFilePath = options.outFile || options.out;
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined;
- action(jsFilePath, sourceMapFilePath, declarationFilePath, sourceFiles, /*isBundledEmit*/ true);
+ action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFiles, /*isBundledEmit*/true, emitOnlyDtsFiles);
+ }
+ }
+ else {
+ for (const sourceFile of sourceFiles) {
+ const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
+ const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
+ const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
+ action({ jsFilePath, sourceMapFilePath, declarationFilePath }, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles);
}
}
}
@@ -2686,77 +2682,22 @@ namespace ts {
return options.sourceMap ? jsFilePath + ".map" : undefined;
}
- /**
- * Iterates over the source files that are expected to have an emit output. This function
- * is used by the legacy emitter and the declaration emitter and should not be used by
- * the tree transforming emitter.
- *
- * @param host An EmitHost.
- * @param action The action to execute.
- * @param targetSourceFile An optional target source file to emit.
- */
- export function forEachExpectedEmitFile(host: EmitHost,
- action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void,
- targetSourceFile?: SourceFile,
- emitOnlyDtsFiles?: boolean) {
- const options = host.getCompilerOptions();
- // Emit on each source file
- if (options.outFile || options.out) {
- onBundledEmit(host);
- }
- else {
- const sourceFiles = targetSourceFile === undefined ? getSourceFilesToEmit(host) : [targetSourceFile];
- for (const sourceFile of sourceFiles) {
- if (shouldEmitInDirectory(sourceFile, file => host.isSourceFileFromExternalLibrary(file))) {
- onSingleFileEmit(host, sourceFile);
+ // JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
+ // So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
+ // For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
+ function getOutputExtension(sourceFile: SourceFile, options: CompilerOptions): string {
+ if (options.jsx === JsxEmit.Preserve) {
+ if (isSourceFileJavaScript(sourceFile)) {
+ if (fileExtensionIs(sourceFile.fileName, ".jsx")) {
+ return ".jsx";
}
}
- }
-
- function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) {
- // JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
- // So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
- // For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
- let extension = ".js";
- if (options.jsx === JsxEmit.Preserve) {
- if (isSourceFileJavaScript(sourceFile)) {
- if (fileExtensionIs(sourceFile.fileName, ".jsx")) {
- extension = ".jsx";
- }
- }
- else if (sourceFile.languageVariant === LanguageVariant.JSX) {
- // TypeScript source file preserving JSX syntax
- extension = ".jsx";
- }
- }
- const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, extension);
- const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
- const emitFileNames: EmitFileNames = {
- jsFilePath,
- sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
- declarationFilePath
- };
- action(emitFileNames, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles);
- }
-
- function onBundledEmit(host: EmitHost) {
- // Can emit only sources that are not declaration file and are either non module code or module with
- // --module or --target es6 specified. Files included by searching under node_modules are also not emitted.
- const bundledSources = filter(getSourceFilesToEmit(host),
- sourceFile => !isDeclarationFile(sourceFile) &&
- !host.isSourceFileFromExternalLibrary(sourceFile) &&
- (!isExternalModule(sourceFile) ||
- !!getEmitModuleKind(options)));
- if (bundledSources.length) {
- const jsFilePath = options.outFile || options.out;
- const emitFileNames: EmitFileNames = {
- jsFilePath,
- sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
- declarationFilePath: options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined
- };
- action(emitFileNames, bundledSources, /*isBundledEmit*/true, emitOnlyDtsFiles);
+ else if (sourceFile.languageVariant === LanguageVariant.JSX) {
+ // TypeScript source file preserving JSX syntax
+ return ".jsx";
}
}
+ return ".js";
}
export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
@@ -3218,7 +3159,11 @@ namespace ts {
}
export function getLocalSymbolForExportDefault(symbol: Symbol) {
- return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined;
+ return isExportDefaultSymbol(symbol) ? symbol.valueDeclaration.localSymbol : undefined;
+ }
+
+ export function isExportDefaultSymbol(symbol: Symbol): boolean {
+ return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default);
}
/** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */
diff --git a/src/harness/unittests/commandLineParsing.ts b/src/harness/unittests/commandLineParsing.ts
index 8c691992043..1895fe2d60e 100644
--- a/src/harness/unittests/commandLineParsing.ts
+++ b/src/harness/unittests/commandLineParsing.ts
@@ -87,7 +87,7 @@ namespace ts {
start: undefined,
length: undefined,
}, {
- messageText: "Argument for '--jsx' option must be: 'preserve', 'react'",
+ messageText: "Argument for '--jsx' option must be: 'preserve', 'react-native', 'react'",
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
diff --git a/src/harness/unittests/convertCompilerOptionsFromJson.ts b/src/harness/unittests/convertCompilerOptionsFromJson.ts
index f44dc259710..4e442173883 100644
--- a/src/harness/unittests/convertCompilerOptionsFromJson.ts
+++ b/src/harness/unittests/convertCompilerOptionsFromJson.ts
@@ -94,7 +94,7 @@ namespace ts {
file: undefined,
start: 0,
length: 0,
- messageText: "Argument for '--jsx' option must be: 'preserve', 'react'",
+ messageText: "Argument for '--jsx' option must be: 'preserve', 'react-native', 'react'",
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
}]
diff --git a/src/harness/unittests/jsDocParsing.ts b/src/harness/unittests/jsDocParsing.ts
index 3cafc9d49ae..98c32c77778 100644
--- a/src/harness/unittests/jsDocParsing.ts
+++ b/src/harness/unittests/jsDocParsing.ts
@@ -290,16 +290,21 @@ namespace ts {
});
describe("getFirstToken", () => {
it("gets jsdoc", () => {
- const first = ts.createSourceFile("foo.ts", "/** comment */var a = true;", ts.ScriptTarget.ES5, /*setParentNodes*/ true);
+ const root = ts.createSourceFile("foo.ts", "/** comment */var a = true;", ts.ScriptTarget.ES5, /*setParentNodes*/ true);
+ assert.isDefined(root);
+ assert.equal(root.kind, ts.SyntaxKind.SourceFile);
+ const first = root.getFirstToken();
assert.isDefined(first);
- assert.equal(first.kind, 263);
+ assert.equal(first.kind, ts.SyntaxKind.VarKeyword);
});
});
describe("getLastToken", () => {
it("gets jsdoc", () => {
- const last = ts.createSourceFile("foo.ts", "var a = true;/** comment */", ts.ScriptTarget.ES5, /*setParentNodes*/ true);
+ const root = ts.createSourceFile("foo.ts", "var a = true;/** comment */", ts.ScriptTarget.ES5, /*setParentNodes*/ true);
+ assert.isDefined(root);
+ const last = root.getLastToken();
assert.isDefined(last);
- assert.equal(last.kind, 263);
+ assert.equal(last.kind, ts.SyntaxKind.EndOfFileToken);
});
});
});
diff --git a/src/harness/unittests/matchFiles.ts b/src/harness/unittests/matchFiles.ts
index c562fcefe91..0a450c50151 100644
--- a/src/harness/unittests/matchFiles.ts
+++ b/src/harness/unittests/matchFiles.ts
@@ -346,9 +346,9 @@ namespace ts {
fileNames: [
"c:/dev/a.ts",
"c:/dev/b.ts",
+ "c:/dev/node_modules/a.ts",
"c:/dev/bower_components/a.ts",
- "c:/dev/jspm_packages/a.ts",
- "c:/dev/node_modules/a.ts"
+ "c:/dev/jspm_packages/a.ts"
],
wildcardDirectories: {},
};
@@ -373,9 +373,9 @@ namespace ts {
options: {},
errors: [],
fileNames: [
+ "c:/dev/node_modules/a.ts",
"c:/dev/bower_components/a.ts",
- "c:/dev/jspm_packages/a.ts",
- "c:/dev/node_modules/a.ts"
+ "c:/dev/jspm_packages/a.ts"
],
wildcardDirectories: {},
};
@@ -398,9 +398,9 @@ namespace ts {
fileNames: [
"c:/dev/a.ts",
"c:/dev/b.ts",
+ "c:/dev/node_modules/a.ts",
"c:/dev/bower_components/a.ts",
- "c:/dev/jspm_packages/a.ts",
- "c:/dev/node_modules/a.ts"
+ "c:/dev/jspm_packages/a.ts"
],
wildcardDirectories: {},
};
@@ -410,6 +410,36 @@ namespace ts {
});
describe("with wildcard include list", () => {
+ it("is sorted in include order, then in alphabetical order", () => {
+ const json = {
+ include: [
+ "z/*.ts",
+ "x/*.ts"
+ ]
+ };
+ const expected: ts.ParsedCommandLine = {
+ options: {},
+ errors: [],
+ fileNames: [
+ "c:/dev/z/a.ts",
+ "c:/dev/z/aba.ts",
+ "c:/dev/z/abz.ts",
+ "c:/dev/z/b.ts",
+ "c:/dev/z/bba.ts",
+ "c:/dev/z/bbz.ts",
+ "c:/dev/x/a.ts",
+ "c:/dev/x/aa.ts",
+ "c:/dev/x/b.ts"
+ ],
+ wildcardDirectories: {
+ "c:/dev/z": ts.WatchDirectoryFlags.None,
+ "c:/dev/x": ts.WatchDirectoryFlags.None
+ },
+ };
+ const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
+ assertParsed(actual, expected);
+ });
+
it("same named declarations are excluded", () => {
const json = {
include: [
@@ -506,8 +536,8 @@ namespace ts {
options: {},
errors: [],
fileNames: [
- "c:/dev/x/a.ts",
"c:/dev/x/y/a.ts",
+ "c:/dev/x/a.ts",
"c:/dev/z/a.ts"
],
wildcardDirectories: {
@@ -909,6 +939,31 @@ namespace ts {
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
});
+ it("with jsx=react-native, allowJs=false", () => {
+ const json = {
+ compilerOptions: {
+ jsx: "react-native",
+ allowJs: false
+ }
+ };
+ const expected: ts.ParsedCommandLine = {
+ options: {
+ jsx: ts.JsxEmit.ReactNative,
+ allowJs: false
+ },
+ errors: [],
+ fileNames: [
+ "c:/dev/a.ts",
+ "c:/dev/b.tsx",
+ "c:/dev/c.tsx",
+ ],
+ wildcardDirectories: {
+ "c:/dev": ts.WatchDirectoryFlags.Recursive
+ }
+ };
+ const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
+ assertParsed(actual, expected);
+ });
it("with jsx=none, allowJs=true", () => {
const json = {
compilerOptions: {
@@ -961,6 +1016,33 @@ namespace ts {
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
});
+ it("with jsx=react-native, allowJs=true", () => {
+ const json = {
+ compilerOptions: {
+ jsx: "react-native",
+ allowJs: true
+ }
+ };
+ const expected: ts.ParsedCommandLine = {
+ options: {
+ jsx: ts.JsxEmit.ReactNative,
+ allowJs: true
+ },
+ errors: [],
+ fileNames: [
+ "c:/dev/a.ts",
+ "c:/dev/b.tsx",
+ "c:/dev/c.tsx",
+ "c:/dev/d.js",
+ "c:/dev/e.jsx",
+ ],
+ wildcardDirectories: {
+ "c:/dev": ts.WatchDirectoryFlags.Recursive
+ }
+ };
+ const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
+ assertParsed(actual, expected);
+ });
it("exclude .min.js files using wildcards", () => {
const json = {
compilerOptions: {
@@ -1230,8 +1312,8 @@ namespace ts {
options: {},
errors: [],
fileNames: [
- "c:/dev/.z/.b.ts",
- "c:/dev/x/.y/a.ts"
+ "c:/dev/x/.y/a.ts",
+ "c:/dev/.z/.b.ts"
],
wildcardDirectories: {}
};
@@ -1271,8 +1353,8 @@ namespace ts {
options: {},
errors: [],
fileNames: [
- "c:/dev/.z/.b.ts",
- "c:/dev/x/.y/a.ts"
+ "c:/dev/x/.y/a.ts",
+ "c:/dev/.z/.b.ts"
],
wildcardDirectories: {
"c:/dev/.z": ts.WatchDirectoryFlags.Recursive,
@@ -1306,4 +1388,4 @@ namespace ts {
});
});
});
-}
\ No newline at end of file
+}
diff --git a/src/lib/es2015.collection.d.ts b/src/lib/es2015.collection.d.ts
index 75a11b5eb17..5b90333f1d5 100644
--- a/src/lib/es2015.collection.d.ts
+++ b/src/lib/es2015.collection.d.ts
@@ -22,7 +22,7 @@ interface ReadonlyMap {
readonly size: number;
}
-interface WeakMap {
+interface WeakMap {
delete(key: K): boolean;
get(key: K): V | undefined;
has(key: K): boolean;
@@ -31,7 +31,7 @@ interface WeakMap {
interface WeakMapConstructor {
new (): WeakMap;
- new (entries?: [K, V][]): WeakMap;
+ new (entries?: [K, V][]): WeakMap;
readonly prototype: WeakMap;
}
declare var WeakMap: WeakMapConstructor;
diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts
index 356512ecf58..eb23ce7901f 100644
--- a/src/lib/es2015.core.d.ts
+++ b/src/lib/es2015.core.d.ts
@@ -325,7 +325,7 @@ interface ObjectConstructor {
* @param o The object to change its prototype.
* @param proto The value of the new prototype or null.
*/
- setPrototypeOf(o: any, proto: any): any;
+ setPrototypeOf(o: any, proto: object | null): any;
/**
* Gets the own property descriptor of the specified object.
diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts
index de339e2bf2c..c8b5158bcd6 100644
--- a/src/lib/es2015.iterable.d.ts
+++ b/src/lib/es2015.iterable.d.ts
@@ -99,10 +99,10 @@ interface MapConstructor {
new (iterable: Iterable<[K, V]>): Map;
}
-interface WeakMap { }
+interface WeakMap { }
interface WeakMapConstructor {
- new (iterable: Iterable<[K, V]>): WeakMap;
+ new (iterable: Iterable<[K, V]>): WeakMap;
}
interface Set {
@@ -442,4 +442,4 @@ interface Float64ArrayConstructor {
* @param thisArg Value of 'this' used to invoke the mapfn.
*/
from(arrayLike: Iterable, mapfn?: (v: number, k: number) => number, thisArg?: any): Float64Array;
-}
\ No newline at end of file
+}
diff --git a/src/lib/es2015.proxy.d.ts b/src/lib/es2015.proxy.d.ts
index 34aedce0128..efccfd47cc5 100644
--- a/src/lib/es2015.proxy.d.ts
+++ b/src/lib/es2015.proxy.d.ts
@@ -1,5 +1,5 @@
interface ProxyHandler {
- getPrototypeOf? (target: T): {} | null;
+ getPrototypeOf? (target: T): object | null;
setPrototypeOf? (target: T, v: any): boolean;
isExtensible? (target: T): boolean;
preventExtensions? (target: T): boolean;
@@ -12,7 +12,7 @@ interface ProxyHandler {
enumerate? (target: T): PropertyKey[];
ownKeys? (target: T): PropertyKey[];
apply? (target: T, thisArg: any, argArray?: any): any;
- construct? (target: T, argArray: any, newTarget?: any): {};
+ construct? (target: T, argArray: any, newTarget?: any): object
}
interface ProxyConstructor {
diff --git a/src/lib/es2015.symbol.d.ts b/src/lib/es2015.symbol.d.ts
index cd7e45595f0..d7ea4fa0328 100644
--- a/src/lib/es2015.symbol.d.ts
+++ b/src/lib/es2015.symbol.d.ts
@@ -3,7 +3,7 @@ interface Symbol {
toString(): string;
/** Returns the primitive value of the specified object. */
- valueOf(): Object;
+ valueOf(): symbol;
}
interface SymbolConstructor {
diff --git a/src/lib/es2015.symbol.wellknown.d.ts b/src/lib/es2015.symbol.wellknown.d.ts
index 145d8af6b10..7177b78e483 100644
--- a/src/lib/es2015.symbol.wellknown.d.ts
+++ b/src/lib/es2015.symbol.wellknown.d.ts
@@ -110,7 +110,7 @@ interface Map {
readonly [Symbol.toStringTag]: "Map";
}
-interface WeakMap{
+interface WeakMap{
readonly [Symbol.toStringTag]: "WeakMap";
}
@@ -324,4 +324,4 @@ interface Float32Array {
*/
interface Float64Array {
readonly [Symbol.toStringTag]: "Float64Array";
-}
\ No newline at end of file
+}
diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts
index 2ae09022e0a..1e4f5ca06bc 100644
--- a/src/lib/es5.d.ts
+++ b/src/lib/es5.d.ts
@@ -146,14 +146,14 @@ interface ObjectConstructor {
* Creates an object that has the specified prototype, and that optionally contains specified properties.
* @param o Object to use as a prototype. May be null
*/
- create(o: T): T;
+ create(o: T): T;
/**
* Creates an object that has the specified prototype, and that optionally contains specified properties.
* @param o Object to use as a prototype. May be null
* @param properties JavaScript object that contains one or more property descriptors.
*/
- create(o: any, properties: PropertyDescriptorMap): any;
+ create(o: object | null, properties: PropertyDescriptorMap): any;
/**
* Adds a property to an object, or modifies attributes of an existing property.
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index 680b81dff99..e3fe17362d7 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -417,7 +417,7 @@ namespace ts.server.protocol {
startOffset: number;
/**
- * Position (can be specified instead of line/offset pair)
+ * Position (can be specified instead of line/offset pair)
*/
/* @internal */
startPosition?: number;
@@ -433,7 +433,7 @@ namespace ts.server.protocol {
endOffset: number;
/**
- * Position (can be specified instead of line/offset pair)
+ * Position (can be specified instead of line/offset pair)
*/
/* @internal */
endPosition?: number;
@@ -445,7 +445,7 @@ namespace ts.server.protocol {
}
/**
- * Response for GetCodeFixes request.
+ * Response for GetCodeFixes request.
*/
export interface GetCodeFixesResponse extends Response {
body?: CodeAction[];
@@ -2272,10 +2272,11 @@ namespace ts.server.protocol {
export namespace JsxEmit {
export type None = "None";
export type Preserve = "Preserve";
+ export type ReactNative = "ReactNative";
export type React = "React";
}
- export type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React;
+ export type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.ReactNative;
export namespace ModuleKind {
export type None = "None";
diff --git a/src/server/session.ts b/src/server/session.ts
index 1fa3986f66f..825ad8506d7 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -484,18 +484,20 @@ namespace ts.server {
private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.FileSpan[] | ImplementationLocation[] {
const { file, project } = this.getFileAndProject(args);
- const scriptInfo = project.getScriptInfoForNormalizedPath(file);
- const position = this.getPosition(args, scriptInfo);
+ const position = this.getPosition(args, project.getScriptInfoForNormalizedPath(file));
const implementations = project.getLanguageService().getImplementationAtPosition(file, position);
if (!implementations) {
return [];
}
if (simplifiedResult) {
- return implementations.map(impl => ({
- file: impl.fileName,
- start: scriptInfo.positionToLineOffset(impl.textSpan.start),
- end: scriptInfo.positionToLineOffset(ts.textSpanEnd(impl.textSpan))
- }));
+ return implementations.map(({ fileName, textSpan }) => {
+ const scriptInfo = project.getScriptInfo(fileName);
+ return {
+ file: fileName,
+ start: scriptInfo.positionToLineOffset(textSpan.start),
+ end: scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan))
+ };
+ });
}
else {
return implementations;
diff --git a/src/services/codefixes/fixForgottenThisPropertyAccess.ts b/src/services/codefixes/fixForgottenThisPropertyAccess.ts
new file mode 100644
index 00000000000..c9d59dd8337
--- /dev/null
+++ b/src/services/codefixes/fixForgottenThisPropertyAccess.ts
@@ -0,0 +1,16 @@
+/* @internal */
+namespace ts.codefix {
+ registerCodeFix({
+ errorCodes: [Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code],
+ getCodeActions: (context: CodeFixContext) => {
+ const sourceFile = context.sourceFile;
+ const token = getTokenAtPosition(sourceFile, context.span.start);
+ const start = token.getStart(sourceFile);
+
+ return [{
+ description: getLocaleSpecificMessage(Diagnostics.Add_this_to_unresolved_variable),
+ changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "this.", span: { start, length: 0 } }] }]
+ }];
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts
index 10d6fa50158..3bd173e04f6 100644
--- a/src/services/codefixes/fixes.ts
+++ b/src/services/codefixes/fixes.ts
@@ -3,7 +3,7 @@
///
///
///
+///
///
///
///
-
diff --git a/src/services/documentHighlights.ts b/src/services/documentHighlights.ts
index 778a007ded5..ff2b819ec26 100644
--- a/src/services/documentHighlights.ts
+++ b/src/services/documentHighlights.ts
@@ -17,7 +17,7 @@ namespace ts.DocumentHighlights {
}
function getSemanticDocumentHighlights(node: Node, typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
- const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch, /*findInStrings*/false, /*findInComments*/false, /*implementations*/false);
+ const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch);
return referencedSymbols && convertReferencedSymbols(referencedSymbols);
}
diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts
index 82a5da453b7..28474839cf3 100644
--- a/src/services/findAllReferences.ts
+++ b/src/services/findAllReferences.ts
@@ -1,49 +1,27 @@
/* @internal */
namespace ts.FindAllReferences {
- export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] | undefined {
+ export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] | undefined {
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
- return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, /*implementations*/false);
+ return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, isForRename);
}
- export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean, implementations: boolean): ReferencedSymbol[] | undefined {
+ export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings?: boolean, findInComments?: boolean, isForRename?: boolean, implementations?: boolean): ReferencedSymbol[] | undefined {
if (!implementations) {
- if (isTypeKeyword(node.kind)) {
- return getAllReferencesForKeyword(sourceFiles, node.kind, cancellationToken);
- }
-
- // Labels
- if (isLabelName(node)) {
- if (isJumpStatementTarget(node)) {
- const labelDefinition = getTargetLabel((node.parent), (node).text);
- // if we have a label definition, look within its statement for references, if not, then
- // the label is undefined and we have no results..
- return labelDefinition && getLabelReferencesInNode(labelDefinition.parent, labelDefinition, cancellationToken);
- }
- else {
- // it is a label definition and not a target, search within the parent labeledStatement
- return getLabelReferencesInNode(node.parent, node, cancellationToken);
- }
- }
-
- if (isThis(node)) {
- return getReferencesForThisKeyword(node, sourceFiles, typeChecker, cancellationToken);
- }
-
- if (node.kind === SyntaxKind.SuperKeyword) {
- return getReferencesForSuperKeyword(node, typeChecker, cancellationToken);
+ const special = getReferencedSymbolsSpecial(node, sourceFiles, typeChecker, cancellationToken);
+ if (special) {
+ return special;
}
}
// `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword,
// so we have to specify that we want the constructor symbol.
- const symbol = typeChecker.getSymbolAtLocation(node);
-
- if (!implementations && !symbol && node.kind === SyntaxKind.StringLiteral) {
- return getReferencesForStringLiteral(node, sourceFiles, typeChecker, cancellationToken);
- }
+ let symbol = typeChecker.getSymbolAtLocation(node);
// Could not find a symbol e.g. unknown identifier
if (!symbol) {
+ if (!implementations && node.kind === SyntaxKind.StringLiteral) {
+ return getReferencesForStringLiteral(node, sourceFiles, typeChecker, cancellationToken);
+ }
// Can't have references to something that we have no symbol for.
return undefined;
}
@@ -55,9 +33,23 @@ namespace ts.FindAllReferences {
return undefined;
}
+ const { symbol: aliasedSymbol, shorthandModuleSymbol } = followAliases(symbol, node, typeChecker, isForRename);
+ symbol = aliasedSymbol;
+
+ // Build the set of symbols to search for, initially it has only the current symbol
+ const searchSymbols = populateSearchSymbolSet(symbol, node, typeChecker, implementations);
+ if (shorthandModuleSymbol) {
+ searchSymbols.push(shorthandModuleSymbol);
+ }
+
// Compute the meaning from the location and the symbol it references
const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations);
+ const result: ReferencedSymbol[] = [];
+ // Maps from a symbol ID to the ReferencedSymbol entry in 'result'.
+ const symbolToIndex: number[] = [];
+ const inheritsFromCache: Map = createMap();
+
// Get the text to search for.
// Note: if this is an external module symbol, the name doesn't include quotes.
const declaredName = stripQuotes(getDeclaredName(typeChecker, symbol, node));
@@ -65,33 +57,107 @@ namespace ts.FindAllReferences {
// Try to get the smallest valid scope that we can limit our search to;
// otherwise we'll need to search globally (i.e. include each file).
const scope = getSymbolScope(symbol);
-
- // Maps from a symbol ID to the ReferencedSymbol entry in 'result'.
- const symbolToIndex: number[] = [];
-
- let result: ReferencedSymbol[];
if (scope) {
- result = [];
- getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken);
+ getRefs(scope, declaredName);
}
else {
- const internedName = getInternedName(symbol, node);
+ const isDefault = isExportDefaultSymbol(symbol);
+ const internedName = isDefault ? symbol.valueDeclaration.localSymbol.name : getInternedName(symbol, node);
for (const sourceFile of sourceFiles) {
cancellationToken.throwIfCancellationRequested();
- if (sourceFileHasName(sourceFile, internedName)) {
- result = result || [];
- getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken);
+ const searchName = (isDefault ? getDefaultImportName(symbol, sourceFile, typeChecker) : undefined) ||
+ (sourceFileHasName(sourceFile, internedName) ? declaredName : undefined);
+ if (searchName !== undefined) {
+ getRefs(sourceFile, searchName);
}
}
}
return result;
+
+ function getRefs(scope: ts.Node, searchName: string): void {
+ getReferencesInNode(scope, symbol, searchName, node, searchMeaning, findInStrings, findInComments, result,
+ symbolToIndex, implementations, typeChecker, cancellationToken, searchSymbols, inheritsFromCache);
+ }
+ }
+
+ /** getReferencedSymbols for special node kinds. */
+ function getReferencedSymbolsSpecial(node: Node, sourceFiles: SourceFile[], typeChecker: TypeChecker, cancellationToken: CancellationToken): ReferencedSymbol[] | undefined {
+ if (isTypeKeyword(node.kind)) {
+ return getAllReferencesForKeyword(sourceFiles, node.kind, cancellationToken);
+ }
+
+ // Labels
+ if (isLabelName(node)) {
+ if (isJumpStatementTarget(node)) {
+ const labelDefinition = getTargetLabel((node.parent), (node).text);
+ // if we have a label definition, look within its statement for references, if not, then
+ // the label is undefined and we have no results..
+ return labelDefinition && getLabelReferencesInNode(labelDefinition.parent, labelDefinition, cancellationToken);
+ }
+ else {
+ // it is a label definition and not a target, search within the parent labeledStatement
+ return getLabelReferencesInNode(node.parent, node, cancellationToken);
+ }
+ }
+
+ if (isThis(node)) {
+ return getReferencesForThisKeyword(node, sourceFiles, typeChecker, cancellationToken);
+ }
+
+ if (node.kind === SyntaxKind.SuperKeyword) {
+ return getReferencesForSuperKeyword(node, typeChecker, cancellationToken);
+ }
+
+ return undefined;
+ }
+
+ /**
+ * Follows aliases to get to the original declaration of a symbol.
+ * For a shorthand ambient module, we don't follow the alias to it, but we will need to add it to the set of search symbols.
+ */
+ function followAliases(symbol: Symbol, node: Node, typeChecker: TypeChecker, isForRename: boolean): { symbol: Symbol, shorthandModuleSymbol?: Symbol } {
+ while (true) {
+ // When renaming a default import, only rename in the current file
+ if (isForRename && isImportDefaultSymbol(symbol)) {
+ return { symbol };
+ }
+
+ const aliasedSymbol = getAliasSymbolForPropertyNameSymbol(symbol, node, typeChecker);
+ // Don't follow alias if it goes to unknown symbol. This can happen if it points to an untyped module.
+ if (!aliasedSymbol || !aliasedSymbol.declarations) {
+ return { symbol };
+ }
+
+ if (ts.isShorthandAmbientModuleSymbol(aliasedSymbol)) {
+ return { symbol, shorthandModuleSymbol: aliasedSymbol };
+ }
+
+ symbol = aliasedSymbol;
+ }
}
function sourceFileHasName(sourceFile: SourceFile, name: string): boolean {
return getNameTable(sourceFile).get(name) !== undefined;
}
+ /**
+ * Given a symbol, see if any of the imports in a source file reference it.
+ * Only call this if `symbol` is a default export.
+ */
+ function getDefaultImportName(symbol: Symbol, sourceFile: SourceFile, checker: ts.TypeChecker): string | undefined {
+ for (const importSpecifier of sourceFile.imports) {
+ const importDecl = importSpecifier.parent as ts.ImportDeclaration;
+ Debug.assert(importDecl.moduleSpecifier === importSpecifier);
+ const defaultName = importDecl.importClause.name;
+ const defaultReferencedSymbol = checker.getAliasedSymbol(checker.getSymbolAtLocation(defaultName));
+ if (symbol === defaultReferencedSymbol) {
+ return defaultName.text;
+ }
+ }
+ return undefined;
+ }
+
function getDefinition(symbol: Symbol, node: Node, typeChecker: TypeChecker): ReferencedSymbolDefinitionInfo {
const { displayParts, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, node.getSourceFile(), getContainerNode(node), node);
const name = displayParts.map(p => p.text).join("");
@@ -112,29 +178,30 @@ namespace ts.FindAllReferences {
}
function getAliasSymbolForPropertyNameSymbol(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol | undefined {
- if (symbol.flags & SymbolFlags.Alias) {
- // Default import get alias
- const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause);
- if (defaultImport) {
- return typeChecker.getAliasedSymbol(symbol);
- }
+ if (!(symbol.flags & SymbolFlags.Alias)) {
+ return undefined;
+ }
- const importOrExportSpecifier = forEach(symbol.declarations,
- declaration => (declaration.kind === SyntaxKind.ImportSpecifier ||
- declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined);
- if (importOrExportSpecifier &&
- // export { a }
- (!importOrExportSpecifier.propertyName ||
- // export {a as class } where a is location
- importOrExportSpecifier.propertyName === location)) {
- // If Import specifier -> get alias
- // else Export specifier -> get local target
- return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ?
- typeChecker.getAliasedSymbol(symbol) :
- typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier);
- }
+ // Default import get alias
+ const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause);
+ if (defaultImport) {
+ return typeChecker.getAliasedSymbol(symbol);
+ }
+
+ const importOrExportSpecifier = forEach(symbol.declarations,
+ declaration => (declaration.kind === SyntaxKind.ImportSpecifier ||
+ declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined);
+ if (importOrExportSpecifier &&
+ // export { a }
+ (!importOrExportSpecifier.propertyName ||
+ // export {a as class } where a is location
+ importOrExportSpecifier.propertyName === location)) {
+ // If Import specifier -> get alias
+ // else Export specifier -> get local target
+ return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ?
+ typeChecker.getAliasedSymbol(symbol) :
+ typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier);
}
- return undefined;
}
function followAliasIfNecessary(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol {
@@ -166,14 +233,9 @@ namespace ts.FindAllReferences {
// If this is an export or import specifier it could have been renamed using the 'as' syntax.
// If so we want to search for whatever under the cursor.
if (isImportOrExportSpecifierName(location)) {
- return location.getText();
+ return location.text;
}
- // Try to get the local symbol if we're dealing with an 'export default'
- // since that symbol has the "true" name.
- const localExportDefaultSymbol = getLocalSymbolForExportDefault(symbol);
- symbol = localExportDefaultSymbol || symbol;
-
return stripQuotes(symbol.name);
}
@@ -390,7 +452,9 @@ namespace ts.FindAllReferences {
symbolToIndex: number[],
implementations: boolean,
typeChecker: TypeChecker,
- cancellationToken: CancellationToken): void {
+ cancellationToken: CancellationToken,
+ searchSymbols: Symbol[],
+ inheritsFromCache: Map): void {
const sourceFile = container.getSourceFile();
@@ -398,9 +462,6 @@ namespace ts.FindAllReferences {
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, start, container.getEnd(), cancellationToken);
const parents = getParentSymbolsOfPropertyAccess();
- const inheritsFromCache: Map = createMap();
- // Build the set of symbols to search for, initially it has only the current symbol
- const searchSymbols = populateSearchSymbolSet(searchSymbol, searchLocation, typeChecker, implementations);
for (const position of possiblePositions) {
cancellationToken.throwIfCancellationRequested();
@@ -445,12 +506,12 @@ namespace ts.FindAllReferences {
addReferenceToRelatedSymbol(referenceLocation, relatedSymbol);
}
/* Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment
- * has two meaning : property name and property value. Therefore when we do findAllReference at the position where
- * an identifier is declared, the language service should return the position of the variable declaration as well as
- * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the
- * position of property accessing, the referenceEntry of such position will be handled in the first case.
- */
- else if (!(referenceSymbol.flags & SymbolFlags.Transient) && searchSymbols.indexOf(shorthandValueSymbol) >= 0) {
+ * has two meanings: property name and property value. Therefore when we do findAllReference at the position where
+ * an identifier is declared, the language service should return the position of the variable declaration as well as
+ * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the
+ * position of property accessing, the referenceEntry of such position will be handled in the first case.
+ */
+ else if (!(referenceSymbol.flags & SymbolFlags.Transient) && contains(searchSymbols, shorthandValueSymbol)) {
addReferenceToRelatedSymbol(referenceSymbolDeclaration.name, shorthandValueSymbol);
}
else if (searchLocation.kind === SyntaxKind.ConstructorKeyword) {
@@ -461,10 +522,10 @@ namespace ts.FindAllReferences {
return;
/* If we are just looking for implementations and this is a property access expression, we need to get the
- * symbol of the local type of the symbol the property is being accessed on. This is because our search
- * symbol may have a different parent symbol if the local type's symbol does not declare the property
- * being accessed (i.e. it is declared in some parent class or interface)
- */
+ * symbol of the local type of the symbol the property is being accessed on. This is because our search
+ * symbol may have a different parent symbol if the local type's symbol does not declare the property
+ * being accessed (i.e. it is declared in some parent class or interface)
+ */
function getParentSymbolsOfPropertyAccess(): Symbol[] | undefined {
if (implementations) {
const propertyAccessExpression = getPropertyAccessExpressionFromRightHandSide(searchLocation);
@@ -482,10 +543,6 @@ namespace ts.FindAllReferences {
}
}
- function getPropertyAccessExpressionFromRightHandSide(node: Node): PropertyAccessExpression {
- return isRightSideOfPropertyAccess(node) && node.parent;
- }
-
/** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */
function findAdditionalConstructorReferences(referenceSymbol: Symbol, referenceLocation: Node): void {
Debug.assert(isClassLike(searchSymbol.valueDeclaration));
@@ -494,7 +551,7 @@ namespace ts.FindAllReferences {
if (referenceSymbol === searchSymbol && isClassLike(referenceClass)) {
Debug.assert(referenceClass.name === referenceLocation);
// This is the class declaration containing the constructor.
- addReferences(findOwnConstructorCalls(searchSymbol));
+ addReferences(findOwnConstructorCalls(searchSymbol, sourceFile));
}
else {
// If this class appears in `extends C`, then the extending class' "super" calls are references.
@@ -512,58 +569,6 @@ namespace ts.FindAllReferences {
}
}
- /** `classSymbol` is the class where the constructor was defined.
- * Reference the constructor and all calls to `new this()`.
- */
- function findOwnConstructorCalls(classSymbol: Symbol): Node[] {
- const result: Node[] = [];
-
- for (const decl of classSymbol.members.get("__constructor").declarations) {
- const ctrKeyword = ts.findChildOfKind(decl, ts.SyntaxKind.ConstructorKeyword, sourceFile)!
- Debug.assert(decl.kind === SyntaxKind.Constructor && !!ctrKeyword);
- result.push(ctrKeyword);
- }
-
- classSymbol.exports.forEach(member => {
- const decl = member.valueDeclaration;
- if (decl && decl.kind === SyntaxKind.MethodDeclaration) {
- const body = (decl).body;
- if (body) {
- forEachDescendantOfKind(body, SyntaxKind.ThisKeyword, thisKeyword => {
- if (isNewExpressionTarget(thisKeyword)) {
- result.push(thisKeyword);
- }
- });
- }
- }
- });
-
- return result;
- }
-
- /** Find references to `super` in the constructor of an extending class. */
- function superConstructorAccesses(cls: ClassLikeDeclaration): Node[] {
- const symbol = cls.symbol;
- const ctr = symbol.members.get("__constructor");
- if (!ctr) {
- return [];
- }
-
- const result: Node[] = [];
- for (const decl of ctr.declarations) {
- Debug.assert(decl.kind === SyntaxKind.Constructor);
- const body = (decl).body;
- if (body) {
- forEachDescendantOfKind(body, SyntaxKind.SuperKeyword, node => {
- if (isCallExpressionTarget(node)) {
- result.push(node);
- }
- });
- }
- };
- return result;
- }
-
function getReferencedSymbol(symbol: Symbol): ReferencedSymbol {
const symbolId = getSymbolId(symbol);
let index = symbolToIndex[symbolId];
@@ -591,6 +596,62 @@ namespace ts.FindAllReferences {
}
}
+ function getPropertyAccessExpressionFromRightHandSide(node: Node): PropertyAccessExpression {
+ return isRightSideOfPropertyAccess(node) && node.parent;
+ }
+
+ /** `classSymbol` is the class where the constructor was defined.
+ * Reference the constructor and all calls to `new this()`.
+ */
+ function findOwnConstructorCalls(classSymbol: Symbol, sourceFile: SourceFile): Node[] {
+ const result: Node[] = [];
+
+ for (const decl of classSymbol.members.get("__constructor").declarations) {
+ const ctrKeyword = ts.findChildOfKind(decl, ts.SyntaxKind.ConstructorKeyword, sourceFile)!
+ Debug.assert(decl.kind === SyntaxKind.Constructor && !!ctrKeyword);
+ result.push(ctrKeyword);
+ }
+
+ classSymbol.exports.forEach(member => {
+ const decl = member.valueDeclaration;
+ if (decl && decl.kind === SyntaxKind.MethodDeclaration) {
+ const body = (decl).body;
+ if (body) {
+ forEachDescendantOfKind(body, SyntaxKind.ThisKeyword, thisKeyword => {
+ if (isNewExpressionTarget(thisKeyword)) {
+ result.push(thisKeyword);
+ }
+ });
+ }
+ }
+ });
+
+ return result;
+ }
+
+ /** Find references to `super` in the constructor of an extending class. */
+ function superConstructorAccesses(cls: ClassLikeDeclaration): Node[] {
+ const symbol = cls.symbol;
+ const ctr = symbol.members.get("__constructor");
+ if (!ctr) {
+ return [];
+ }
+
+ const result: Node[] = [];
+ for (const decl of ctr.declarations) {
+ Debug.assert(decl.kind === SyntaxKind.Constructor);
+ const body = (decl).body;
+ if (body) {
+ forEachDescendantOfKind(body, SyntaxKind.SuperKeyword, node => {
+ if (isCallExpressionTarget(node)) {
+ result.push(node);
+ }
+ });
+ }
+ };
+ return result;
+ }
+
function getImplementationReferenceEntryForNode(refNode: Node, result: ReferenceEntry[], typeChecker: TypeChecker): void {
// Check if we found a function/propertyAssignment/method with an implementation or initializer
if (isDeclarationName(refNode) && isImplementation(refNode.parent)) {
@@ -805,13 +866,13 @@ namespace ts.FindAllReferences {
const sourceFile = searchSpaceNode.getSourceFile();
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd(), cancellationToken);
- forEach(possiblePositions, position => {
+ for (const position of possiblePositions) {
cancellationToken.throwIfCancellationRequested();
const node = getTouchingWord(sourceFile, position);
if (!node || node.kind !== SyntaxKind.SuperKeyword) {
- return;
+ continue;
}
const container = getSuperContainer(node, /*stopOnFunctions*/ false);
@@ -822,7 +883,7 @@ namespace ts.FindAllReferences {
if (container && (ModifierFlags.Static & getModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) {
references.push(getReferenceEntryFromNode(node));
}
- });
+ }
const definition = getDefinition(searchSpaceNode.symbol, superKeyword, typeChecker);
return [{ definition, references }];
@@ -985,7 +1046,7 @@ namespace ts.FindAllReferences {
function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean): Symbol[] {
// The search set contains at least the current symbol
- let result = [symbol];
+ const result = [symbol];
// If the location is name of property symbol from object literal destructuring pattern
// Search the property symbol
@@ -998,22 +1059,6 @@ namespace ts.FindAllReferences {
}
}
- // If the symbol is an alias, add what it aliases to the list
- // import {a} from "mod";
- // export {a}
- // If the symbol is an alias to default declaration, add what it aliases to the list
- // declare "mod" { export default class B { } }
- // import B from "mod";
- //// For export specifiers, the exported name can be referring to a local symbol, e.g.:
- //// import {a} from "mod";
- //// export {a as somethingElse}
- //// We want the *local* declaration of 'a' as declared in the import,
- //// *not* as declared within "mod" (or farther)
- const aliasSymbol = getAliasSymbolForPropertyNameSymbol(symbol, location, typeChecker);
- if (aliasSymbol) {
- result = result.concat(populateSearchSymbolSet(aliasSymbol, location, typeChecker, implementations));
- }
-
// If the location is in a context sensitive location (i.e. in an object literal) try
// to get a contextual type for it, and add the property symbol from the contextual
// type to the search set
@@ -1045,7 +1090,7 @@ namespace ts.FindAllReferences {
// Property Declaration symbol is a member of the class, so the symbol is stored in its class Declaration.symbol.members
if (symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.Parameter &&
isParameterPropertyDeclaration(symbol.valueDeclaration)) {
- result = result.concat(typeChecker.getSymbolsOfParameterPropertyDeclaration(symbol.valueDeclaration, symbol.name));
+ addRange(result, typeChecker.getSymbolsOfParameterPropertyDeclaration(symbol.valueDeclaration, symbol.name));
}
// If this is symbol of binding element without propertyName declaration in Object binding pattern
@@ -1057,7 +1102,7 @@ namespace ts.FindAllReferences {
// If this is a union property, add all the symbols from all its source symbols in all unioned types.
// If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list
- forEach(typeChecker.getRootSymbols(symbol), rootSymbol => {
+ for (const rootSymbol of typeChecker.getRootSymbols(symbol)) {
if (rootSymbol !== symbol) {
result.push(rootSymbol);
}
@@ -1066,7 +1111,7 @@ namespace ts.FindAllReferences {
if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap(), typeChecker);
}
- });
+ }
return result;
}
@@ -1130,10 +1175,10 @@ namespace ts.FindAllReferences {
}
}
- function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map, typeChecker: TypeChecker): Symbol {
+ function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map, typeChecker: TypeChecker): Symbol | undefined {
if (contains(searchSymbols, referenceSymbol)) {
// If we are searching for constructor uses, they must be 'new' expressions.
- return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) && referenceSymbol;
+ return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) ? referenceSymbol : undefined;
}
// If the reference symbol is an alias, check if what it is aliasing is one of the search
@@ -1148,9 +1193,8 @@ namespace ts.FindAllReferences {
// compare to our searchSymbol
const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation);
if (containingObjectLiteralElement) {
- const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, typeChecker), contextualSymbol => {
- return forEach(typeChecker.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
- });
+ const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, typeChecker), contextualSymbol =>
+ find(typeChecker.getRootSymbols(contextualSymbol), symbol => contains(searchSymbols, symbol)));
if (contextualSymbol) {
return contextualSymbol;
@@ -1161,7 +1205,7 @@ namespace ts.FindAllReferences {
// In below eg. get 'property' from type of elems iterating type
// for ( { property: p2 } of elems) { }
const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, typeChecker);
- if (propertySymbol && searchSymbols.indexOf(propertySymbol) >= 0) {
+ if (propertySymbol && contains(searchSymbols, propertySymbol)) {
return propertySymbol;
}
}
@@ -1170,7 +1214,7 @@ namespace ts.FindAllReferences {
// then include the binding element in the related symbols
// let { a } : { a };
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, typeChecker);
- if (bindingElementPropertySymbol && searchSymbols.indexOf(bindingElementPropertySymbol) >= 0) {
+ if (bindingElementPropertySymbol && contains(searchSymbols, bindingElementPropertySymbol)) {
return bindingElementPropertySymbol;
}
@@ -1178,7 +1222,7 @@ namespace ts.FindAllReferences {
// Or a union property, use its underlying unioned symbols
return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => {
// if it is in the list, then we are done
- if (searchSymbols.indexOf(rootSymbol) >= 0) {
+ if (contains(searchSymbols, rootSymbol)) {
return rootSymbol;
}
@@ -1195,7 +1239,7 @@ namespace ts.FindAllReferences {
const result: Symbol[] = [];
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap(), typeChecker);
- return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
+ return find(result, symbol => contains(searchSymbols, symbol));
}
return undefined;
@@ -1214,7 +1258,8 @@ namespace ts.FindAllReferences {
return (node.name).text;
}
- function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, typeChecker: TypeChecker): Symbol[] {
+ /** Gets all symbols for one property. Does not get symbols for every property. */
+ function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, typeChecker: TypeChecker): Symbol[] | undefined {
const objectLiteral = node.parent;
const contextualType = typeChecker.getContextualType(objectLiteral);
const name = getNameFromObjectLiteralElement(node);
@@ -1420,4 +1465,8 @@ namespace ts.FindAllReferences {
return false;
}
+
+ function isImportDefaultSymbol(symbol: Symbol): boolean {
+ return symbol.declarations[0].kind === SyntaxKind.ImportClause;
+ }
}
diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts
index ab35a17fcef..73cf06d31ef 100644
--- a/src/services/goToDefinition.ts
+++ b/src/services/goToDefinition.ts
@@ -187,7 +187,15 @@ namespace ts.GoToDefinition {
}
function isSignatureDeclaration(node: Node): boolean {
- return node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature
+ switch (node.kind) {
+ case ts.SyntaxKind.Constructor:
+ case ts.SyntaxKind.FunctionDeclaration:
+ case ts.SyntaxKind.MethodDeclaration:
+ case ts.SyntaxKind.MethodSignature:
+ return true;
+ default:
+ return false;
+ }
}
/** Creates a DefinitionInfo from a Declaration, using the declaration's name if possible. */
@@ -254,6 +262,11 @@ namespace ts.GoToDefinition {
function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined {
const callLike = getAncestorCallLikeExpression(node);
- return callLike && typeChecker.getResolvedSignature(callLike).declaration;
+ const decl = callLike && typeChecker.getResolvedSignature(callLike).declaration;
+ if (decl && isSignatureDeclaration(decl)) {
+ return decl;
+ }
+ // Don't go to a function type, go to the value having that type.
+ return undefined;
}
}
diff --git a/src/services/goToImplementation.ts b/src/services/goToImplementation.ts
index 123d29630ad..9135e1fe0f0 100644
--- a/src/services/goToImplementation.ts
+++ b/src/services/goToImplementation.ts
@@ -17,7 +17,7 @@ namespace ts.GoToImplementation {
else {
// Perform "Find all References" and retrieve only those that are implementations
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken,
- node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*implementations*/true);
+ node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*isForRename*/false, /*implementations*/true);
const result = flatMap(referencedSymbols, symbol =>
map(symbol.references, ({ textSpan, fileName }) => ({ textSpan, fileName })));
diff --git a/src/services/rename.ts b/src/services/rename.ts
index 6f28e505f79..2e9396888ef 100644
--- a/src/services/rename.ts
+++ b/src/services/rename.ts
@@ -1,98 +1,92 @@
/* @internal */
namespace ts.Rename {
export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: (fileName: string) => string, sourceFile: SourceFile, position: number): RenameInfo {
- const canonicalDefaultLibName = getCanonicalFileName(ts.normalizePath(defaultLibFileName));
-
+ const getCanonicalDefaultLibName = memoize(() => getCanonicalFileName(ts.normalizePath(defaultLibFileName)));
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
-
- if (node) {
- if (node.kind === SyntaxKind.Identifier ||
- node.kind === SyntaxKind.StringLiteral ||
- isLiteralNameOfPropertyDeclarationOrIndexAccess(node) ||
- isThis(node)) {
- const symbol = typeChecker.getSymbolAtLocation(node);
-
- // Only allow a symbol to be renamed if it actually has at least one declaration.
- if (symbol) {
- const declarations = symbol.getDeclarations();
- if (declarations && declarations.length > 0) {
- // Disallow rename for elements that are defined in the standard TypeScript library.
- if (forEach(declarations, isDefinedInLibraryFile)) {
- return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library));
- }
-
- const displayName = stripQuotes(getDeclaredName(typeChecker, symbol, node));
- const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node);
- if (kind) {
- return {
- canRename: true,
- kind,
- displayName,
- localizedErrorMessage: undefined,
- fullDisplayName: typeChecker.getFullyQualifiedName(symbol),
- kindModifiers: SymbolDisplay.getSymbolModifiers(symbol),
- triggerSpan: createTriggerSpanForNode(node, sourceFile)
- };
- }
- }
- }
- else if (node.kind === SyntaxKind.StringLiteral) {
- const type = getStringLiteralTypeForNode(node, typeChecker);
- if (type) {
- if (isDefinedInLibraryFile(node)) {
- return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library));
- }
- else {
- const displayName = stripQuotes(type.text);
- return {
- canRename: true,
- kind: ScriptElementKind.variableElement,
- displayName,
- localizedErrorMessage: undefined,
- fullDisplayName: displayName,
- kindModifiers: ScriptElementKindModifier.none,
- triggerSpan: createTriggerSpanForNode(node, sourceFile)
- };
- }
- }
- }
- }
- }
-
- return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_this_element));
-
- function getRenameInfoError(localizedErrorMessage: string): RenameInfo {
- return {
- canRename: false,
- localizedErrorMessage: localizedErrorMessage,
- displayName: undefined,
- fullDisplayName: undefined,
- kind: undefined,
- kindModifiers: undefined,
- triggerSpan: undefined
- };
- }
+ const renameInfo = node && nodeIsEligibleForRename(node)
+ ? getRenameInfoForNode(node, typeChecker, sourceFile, isDefinedInLibraryFile)
+ : undefined;
+ return renameInfo || getRenameInfoError(Diagnostics.You_cannot_rename_this_element);
function isDefinedInLibraryFile(declaration: Node) {
- if (defaultLibFileName) {
- const sourceFile = declaration.getSourceFile();
- const canonicalName = getCanonicalFileName(ts.normalizePath(sourceFile.fileName));
- if (canonicalName === canonicalDefaultLibName) {
- return true;
- }
+ if (!defaultLibFileName) {
+ return false;
}
- return false;
- }
- function createTriggerSpanForNode(node: Node, sourceFile: SourceFile) {
- let start = node.getStart(sourceFile);
- let width = node.getWidth(sourceFile);
- if (node.kind === SyntaxKind.StringLiteral) {
- // Exclude the quotes
- start += 1;
- width -= 2;
- }
- return createTextSpan(start, width);
+ const sourceFile = declaration.getSourceFile();
+ const canonicalName = getCanonicalFileName(ts.normalizePath(sourceFile.fileName));
+ return canonicalName === getCanonicalDefaultLibName();
}
}
+
+ function getRenameInfoForNode(node: Node, typeChecker: TypeChecker, sourceFile: SourceFile, isDefinedInLibraryFile: (declaration: Node) => boolean): RenameInfo | undefined {
+ const symbol = typeChecker.getSymbolAtLocation(node);
+
+ // Only allow a symbol to be renamed if it actually has at least one declaration.
+ if (symbol) {
+ const declarations = symbol.getDeclarations();
+ if (declarations && declarations.length > 0) {
+ // Disallow rename for elements that are defined in the standard TypeScript library.
+ if (some(declarations, isDefinedInLibraryFile)) {
+ return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library);
+ }
+
+ const displayName = stripQuotes(getDeclaredName(typeChecker, symbol, node));
+ const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node);
+ return kind ? getRenameInfoSuccess(displayName, typeChecker.getFullyQualifiedName(symbol), kind, SymbolDisplay.getSymbolModifiers(symbol), node, sourceFile) : undefined;
+ }
+ }
+ else if (node.kind === SyntaxKind.StringLiteral) {
+ const type = getStringLiteralTypeForNode(node, typeChecker);
+ if (type) {
+ if (isDefinedInLibraryFile(node)) {
+ return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library);
+ }
+
+ const displayName = stripQuotes(type.text);
+ return getRenameInfoSuccess(displayName, displayName, ScriptElementKind.variableElement, ScriptElementKindModifier.none, node, sourceFile);
+ }
+ }
+ }
+
+ function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind: string, kindModifiers: string, node: Node, sourceFile: SourceFile): RenameInfo {
+ return {
+ canRename: true,
+ kind,
+ displayName,
+ localizedErrorMessage: undefined,
+ fullDisplayName,
+ kindModifiers,
+ triggerSpan: createTriggerSpanForNode(node, sourceFile)
+ };
+ }
+
+ function getRenameInfoError(diagnostic: DiagnosticMessage): RenameInfo {
+ return {
+ canRename: false,
+ localizedErrorMessage: getLocaleSpecificMessage(diagnostic),
+ displayName: undefined,
+ fullDisplayName: undefined,
+ kind: undefined,
+ kindModifiers: undefined,
+ triggerSpan: undefined
+ };
+ }
+
+ function createTriggerSpanForNode(node: Node, sourceFile: SourceFile) {
+ let start = node.getStart(sourceFile);
+ let width = node.getWidth(sourceFile);
+ if (node.kind === SyntaxKind.StringLiteral) {
+ // Exclude the quotes
+ start += 1;
+ width -= 2;
+ }
+ return createTextSpan(start, width);
+ }
+
+ function nodeIsEligibleForRename(node: Node) {
+ return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.StringLiteral ||
+ isLiteralNameOfPropertyDeclarationOrIndexAccess(node) ||
+ isThis(node);
+ }
}
diff --git a/src/services/services.ts b/src/services/services.ts
index dac5319d925..27453661701 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -193,8 +193,8 @@ namespace ts {
return undefined;
}
- const child = children[0];
- return child.kind < SyntaxKind.FirstNode || SyntaxKind.FirstJSDocNode <= child.kind && child.kind <= SyntaxKind.LastJSDocNode ?
+ const child = ts.find(children, kid => kid.kind < SyntaxKind.FirstJSDocNode || kid.kind > SyntaxKind.LastJSDocNode);
+ return child.kind < SyntaxKind.FirstNode ?
child :
child.getFirstToken(sourceFile);
}
@@ -207,9 +207,7 @@ namespace ts {
return undefined;
}
- return child.kind < SyntaxKind.FirstNode || SyntaxKind.FirstJSDocNode <= child.kind && child.kind <= SyntaxKind.LastJSDocNode ?
- child :
- child.getLastToken(sourceFile);
+ return child.kind < SyntaxKind.FirstNode ? child : child.getLastToken(sourceFile);
}
}
@@ -382,7 +380,7 @@ namespace ts {
getNumberIndexType(): Type {
return this.checker.getIndexTypeOfType(this, IndexKind.Number);
}
- getBaseTypes(): ObjectType[] {
+ getBaseTypes(): BaseType[] {
return this.flags & TypeFlags.Object && this.objectFlags & (ObjectFlags.Class | ObjectFlags.Interface)
? this.checker.getBaseTypes(this)
: undefined;
@@ -1407,25 +1405,25 @@ namespace ts {
}
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] {
- const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments);
+ const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments, /*isForRename*/true);
return FindAllReferences.convertReferences(referencedSymbols);
}
function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
- const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false);
+ const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
return FindAllReferences.convertReferences(referencedSymbols);
}
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
- const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false);
+ const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
// Only include referenced symbols that have a valid definition.
return filter(referencedSymbols, rs => !!rs.definition);
}
- function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] {
+ function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] {
synchronizeHostData();
- return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments);
+ return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments, isForRename);
}
/// NavigateTo
diff --git a/src/services/shims.ts b/src/services/shims.ts
index cf6bceb816c..487947ee458 100644
--- a/src/services/shims.ts
+++ b/src/services/shims.ts
@@ -385,7 +385,10 @@ namespace ts {
if (settingsJson == null || settingsJson == "") {
throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings");
}
- return JSON.parse(settingsJson);
+ const compilerOptions = JSON.parse(settingsJson);
+ // permit language service to handle all files (filtering should be performed on the host side)
+ compilerOptions.allowNonTsExtensions = true;
+ return compilerOptions;
}
public getScriptFileNames(): string[] {
@@ -1061,12 +1064,6 @@ namespace ts {
const compilerOptions = JSON.parse(compilerOptionsJson);
const result = resolveModuleName(moduleName, normalizeSlashes(fileName), compilerOptions, this.host);
const resolvedFileName = result.resolvedModule ? result.resolvedModule.resolvedFileName : undefined;
- if (resolvedFileName && !compilerOptions.allowJs && fileExtensionIs(resolvedFileName, ".js")) {
- return {
- resolvedFileName: undefined,
- failedLookupLocations: []
- };
- }
return {
resolvedFileName,
failedLookupLocations: result.failedLookupLocations
diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json
index b60e00292f5..b4e8289f367 100644
--- a/src/services/tsconfig.json
+++ b/src/services/tsconfig.json
@@ -83,6 +83,7 @@
"codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
"codefixes/fixClassSuperMustPrecedeThisAccess.ts",
"codefixes/fixConstructorForDerivedNeedSuperCall.ts",
+ "codefixes/fixForgottenThisPropertyAccess.ts",
"codefixes/fixes.ts",
"codefixes/helpers.ts",
"codefixes/importFixes.ts",
diff --git a/src/services/types.ts b/src/services/types.ts
index 42f2a7992bd..b4210538518 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -33,7 +33,7 @@ namespace ts {
getConstructSignatures(): Signature[];
getStringIndexType(): Type;
getNumberIndexType(): Type;
- getBaseTypes(): ObjectType[];
+ getBaseTypes(): BaseType[];
getNonNullableType(): Type;
}
diff --git a/src/services/utilities.ts b/src/services/utilities.ts
index a1680da69c3..f83f9ef8231 100644
--- a/src/services/utilities.ts
+++ b/src/services/utilities.ts
@@ -1319,7 +1319,7 @@ namespace ts {
return name;
}
- export function isImportOrExportSpecifierName(location: Node): boolean {
+ export function isImportOrExportSpecifierName(location: Node): location is Identifier {
return location.parent &&
(location.parent.kind === SyntaxKind.ImportSpecifier || location.parent.kind === SyntaxKind.ExportSpecifier) &&
(location.parent).propertyName === location;
diff --git a/tests/baselines/reference/augmentExportEquals7.errors.txt b/tests/baselines/reference/augmentExportEquals7.errors.txt
new file mode 100644
index 00000000000..e13cf037023
--- /dev/null
+++ b/tests/baselines/reference/augmentExportEquals7.errors.txt
@@ -0,0 +1,16 @@
+/node_modules/@types/lib-extender/index.d.ts(2,16): error TS2649: Cannot augment module 'lib' with value exports because it resolves to a non-module entity.
+
+
+==== /node_modules/lib/index.d.ts (0 errors) ====
+ declare var lib: () => void;
+ declare namespace lib {}
+ export = lib;
+
+==== /node_modules/@types/lib-extender/index.d.ts (1 errors) ====
+ import * as lib from "lib";
+ declare module "lib" {
+ ~~~~~
+!!! error TS2649: Cannot augment module 'lib' with value exports because it resolves to a non-module entity.
+ export function fn(): void;
+ }
+
\ No newline at end of file
diff --git a/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.js b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.js
new file mode 100644
index 00000000000..b2ba970ef51
--- /dev/null
+++ b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.js
@@ -0,0 +1,17 @@
+//// [destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts]
+// test for #10668
+function qux(bar: { value: number }) {
+ let foo: number;
+ ({ value: foo } = bar);
+ let x = () => bar;
+}
+
+
+
+//// [destructuringPropertyAssignmentNameIsNotAssignmentTarget.js]
+// test for #10668
+function qux(bar) {
+ var foo;
+ (foo = bar.value);
+ var x = function () { return bar; };
+}
diff --git a/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.symbols b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.symbols
new file mode 100644
index 00000000000..b9ebe219f65
--- /dev/null
+++ b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.symbols
@@ -0,0 +1,21 @@
+=== tests/cases/compiler/destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts ===
+// test for #10668
+function qux(bar: { value: number }) {
+>qux : Symbol(qux, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 0, 0))
+>bar : Symbol(bar, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 1, 13))
+>value : Symbol(value, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 1, 19))
+
+ let foo: number;
+>foo : Symbol(foo, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 2, 7))
+
+ ({ value: foo } = bar);
+>value : Symbol(value, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 3, 6))
+>foo : Symbol(foo, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 2, 7))
+>bar : Symbol(bar, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 1, 13))
+
+ let x = () => bar;
+>x : Symbol(x, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 4, 7))
+>bar : Symbol(bar, Decl(destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts, 1, 13))
+}
+
+
diff --git a/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.types b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.types
new file mode 100644
index 00000000000..e0428fc959f
--- /dev/null
+++ b/tests/baselines/reference/destructuringPropertyAssignmentNameIsNotAssignmentTarget.types
@@ -0,0 +1,25 @@
+=== tests/cases/compiler/destructuringPropertyAssignmentNameIsNotAssignmentTarget.ts ===
+// test for #10668
+function qux(bar: { value: number }) {
+>qux : (bar: { value: number; }) => void
+>bar : { value: number; }
+>value : number
+
+ let foo: number;
+>foo : number
+
+ ({ value: foo } = bar);
+>({ value: foo } = bar) : { value: number; }
+>{ value: foo } = bar : { value: number; }
+>{ value: foo } : { value: number; }
+>value : number
+>foo : number
+>bar : { value: number; }
+
+ let x = () => bar;
+>x : () => { value: number; }
+>() => bar : () => { value: number; }
+>bar : { value: number; }
+}
+
+
diff --git a/tests/baselines/reference/es3-jsx-preserve.js b/tests/baselines/reference/es3-jsx-preserve.js
new file mode 100644
index 00000000000..cb1ba2a887d
--- /dev/null
+++ b/tests/baselines/reference/es3-jsx-preserve.js
@@ -0,0 +1,11 @@
+//// [es3-jsx-preserve.tsx]
+
+const React: any = null;
+
+const elem = ;
+
+
+
+//// [es3-jsx-preserve.jsx]
+var React = null;
+var elem = ;
diff --git a/tests/baselines/reference/es3-jsx-preserve.symbols b/tests/baselines/reference/es3-jsx-preserve.symbols
new file mode 100644
index 00000000000..61c9260223f
--- /dev/null
+++ b/tests/baselines/reference/es3-jsx-preserve.symbols
@@ -0,0 +1,11 @@
+=== tests/cases/compiler/es3-jsx-preserve.tsx ===
+
+const React: any = null;
+>React : Symbol(React, Decl(es3-jsx-preserve.tsx, 1, 5))
+
+const elem = ;
+>elem : Symbol(elem, Decl(es3-jsx-preserve.tsx, 3, 5))
+>div : Symbol(unknown)
+>div : Symbol(unknown)
+
+
diff --git a/tests/baselines/reference/es3-jsx-preserve.types b/tests/baselines/reference/es3-jsx-preserve.types
new file mode 100644
index 00000000000..b37fe8af567
--- /dev/null
+++ b/tests/baselines/reference/es3-jsx-preserve.types
@@ -0,0 +1,13 @@
+=== tests/cases/compiler/es3-jsx-preserve.tsx ===
+
+const React: any = null;
+>React : any
+>null : null
+
+const elem = ;
+>elem : any
+> : any
+>div : any
+>div : any
+
+
diff --git a/tests/baselines/reference/es3-jsx-react-native.js b/tests/baselines/reference/es3-jsx-react-native.js
new file mode 100644
index 00000000000..08e6e25502b
--- /dev/null
+++ b/tests/baselines/reference/es3-jsx-react-native.js
@@ -0,0 +1,11 @@
+//// [es3-jsx-react-native.tsx]
+
+const React: any = null;
+
+const elem = ;
+
+
+
+//// [es3-jsx-react-native.js]
+var React = null;
+var elem = ;
diff --git a/tests/baselines/reference/es3-jsx-react-native.symbols b/tests/baselines/reference/es3-jsx-react-native.symbols
new file mode 100644
index 00000000000..e7f010bd2ea
--- /dev/null
+++ b/tests/baselines/reference/es3-jsx-react-native.symbols
@@ -0,0 +1,11 @@
+=== tests/cases/compiler/es3-jsx-react-native.tsx ===
+
+const React: any = null;
+>React : Symbol(React, Decl(es3-jsx-react-native.tsx, 1, 5))
+
+const elem = ;
+>elem : Symbol(elem, Decl(es3-jsx-react-native.tsx, 3, 5))
+>div : Symbol(unknown)
+>div : Symbol(unknown)
+
+
diff --git a/tests/baselines/reference/es3-jsx-react-native.types b/tests/baselines/reference/es3-jsx-react-native.types
new file mode 100644
index 00000000000..1bf199606f2
--- /dev/null
+++ b/tests/baselines/reference/es3-jsx-react-native.types
@@ -0,0 +1,13 @@
+=== tests/cases/compiler/es3-jsx-react-native.tsx ===
+
+const React: any = null;
+>React : any
+>null : null
+
+const elem = ;
+>elem : any
+> : any
+>div : any
+>div : any
+
+
diff --git a/tests/baselines/reference/es3-jsx-react.js b/tests/baselines/reference/es3-jsx-react.js
new file mode 100644
index 00000000000..861dde74c86
--- /dev/null
+++ b/tests/baselines/reference/es3-jsx-react.js
@@ -0,0 +1,11 @@
+//// [es3-jsx-react.tsx]
+
+const React: any = null;
+
+const elem = ;
+
+
+
+//// [es3-jsx-react.js]
+var React = null;
+var elem = React.createElement("div", null);
diff --git a/tests/baselines/reference/es3-jsx-react.symbols b/tests/baselines/reference/es3-jsx-react.symbols
new file mode 100644
index 00000000000..465cfab7ea9
--- /dev/null
+++ b/tests/baselines/reference/es3-jsx-react.symbols
@@ -0,0 +1,11 @@
+=== tests/cases/compiler/es3-jsx-react.tsx ===
+
+const React: any = null;
+>React : Symbol(React, Decl(es3-jsx-react.tsx, 1, 5))
+
+const elem = ;
+>elem : Symbol(elem, Decl(es3-jsx-react.tsx, 3, 5))
+>div : Symbol(unknown)
+>div : Symbol(unknown)
+
+
diff --git a/tests/baselines/reference/es3-jsx-react.types b/tests/baselines/reference/es3-jsx-react.types
new file mode 100644
index 00000000000..b7734ffc1f0
--- /dev/null
+++ b/tests/baselines/reference/es3-jsx-react.types
@@ -0,0 +1,13 @@
+=== tests/cases/compiler/es3-jsx-react.tsx ===
+
+const React: any = null;
+>React : any
+>null : null
+
+const elem = ;
+>elem : any
+> : any
+>div : any
+>div : any
+
+
diff --git a/tests/baselines/reference/globalAugmentationModuleResolution.types b/tests/baselines/reference/globalAugmentationModuleResolution.types
index c057ea2943d..75f23b0cd6b 100644
--- a/tests/baselines/reference/globalAugmentationModuleResolution.types
+++ b/tests/baselines/reference/globalAugmentationModuleResolution.types
@@ -3,7 +3,7 @@
export { };
declare global {
->global : any
+>global : typeof global
var x: number;
>x : number
diff --git a/tests/baselines/reference/importHelpersES6.js b/tests/baselines/reference/importHelpersES6.js
index 209f3c34588..bc17939e2cc 100644
--- a/tests/baselines/reference/importHelpersES6.js
+++ b/tests/baselines/reference/importHelpersES6.js
@@ -5,10 +5,12 @@ declare var dec: any;
@dec export class A {
}
+
+const o = { a: 1 };
+const y = { ...o };
//// [tslib.d.ts]
export declare function __extends(d: Function, b: Function): void;
-export declare function __assign(t: any, ...sources: any[]): any;
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
export declare function __param(paramIndex: number, decorator: Function): Function;
export declare function __metadata(metadataKey: any, metadataValue: any): Function;
@@ -23,3 +25,5 @@ A = tslib_1.__decorate([
dec
], A);
export { A };
+const o = { a: 1 };
+const y = Object.assign({}, o);
diff --git a/tests/baselines/reference/importHelpersES6.symbols b/tests/baselines/reference/importHelpersES6.symbols
index 284a2251a6b..66a8b131aec 100644
--- a/tests/baselines/reference/importHelpersES6.symbols
+++ b/tests/baselines/reference/importHelpersES6.symbols
@@ -8,6 +8,14 @@ declare var dec: any;
}
+const o = { a: 1 };
+>o : Symbol(o, Decl(a.ts, 5, 5))
+>a : Symbol(a, Decl(a.ts, 5, 11))
+
+const y = { ...o };
+>y : Symbol(y, Decl(a.ts, 6, 5))
+>o : Symbol(o, Decl(a.ts, 5, 5))
+
=== tests/cases/compiler/tslib.d.ts ===
export declare function __extends(d: Function, b: Function): void;
>__extends : Symbol(__extends, Decl(tslib.d.ts, --, --))
@@ -16,11 +24,6 @@ export declare function __extends(d: Function, b: Function): void;
>b : Symbol(b, Decl(tslib.d.ts, --, --))
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
-export declare function __assign(t: any, ...sources: any[]): any;
->__assign : Symbol(__assign, Decl(tslib.d.ts, --, --))
->t : Symbol(t, Decl(tslib.d.ts, --, --))
->sources : Symbol(sources, Decl(tslib.d.ts, --, --))
-
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
>__decorate : Symbol(__decorate, Decl(tslib.d.ts, --, --))
>decorators : Symbol(decorators, Decl(tslib.d.ts, --, --))
diff --git a/tests/baselines/reference/importHelpersES6.types b/tests/baselines/reference/importHelpersES6.types
index ebfd5a5a2a5..26f30e32e58 100644
--- a/tests/baselines/reference/importHelpersES6.types
+++ b/tests/baselines/reference/importHelpersES6.types
@@ -8,6 +8,17 @@ declare var dec: any;
}
+const o = { a: 1 };
+>o : { a: number; }
+>{ a: 1 } : { a: number; }
+>a : number
+>1 : 1
+
+const y = { ...o };
+>y : { a: number; }
+>{ ...o } : { a: number; }
+>o : { a: number; }
+
=== tests/cases/compiler/tslib.d.ts ===
export declare function __extends(d: Function, b: Function): void;
>__extends : (d: Function, b: Function) => void
@@ -16,11 +27,6 @@ export declare function __extends(d: Function, b: Function): void;
>b : Function
>Function : Function
-export declare function __assign(t: any, ...sources: any[]): any;
->__assign : (t: any, ...sources: any[]) => any
->t : any
->sources : any[]
-
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
>__decorate : (decorators: Function[], target: any, key?: string | symbol, desc?: any) => any
>decorators : Function[]
diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersection.js b/tests/baselines/reference/interfaceExtendsObjectIntersection.js
new file mode 100644
index 00000000000..a6fb62f5070
--- /dev/null
+++ b/tests/baselines/reference/interfaceExtendsObjectIntersection.js
@@ -0,0 +1,145 @@
+//// [interfaceExtendsObjectIntersection.ts]
+
+type T1 = { a: number };
+type T2 = T1 & { b: number };
+type T3 = () => void;
+type T4 = new () => { a: number };
+type T5 = number[];
+type T6 = [string, number];
+type T7 = { [P in 'a' | 'b' | 'c']: string };
+
+interface I1 extends T1 { x: string }
+interface I2 extends T2 { x: string }
+interface I3 extends T3 { x: string }
+interface I4 extends T4 { x: string }
+interface I5 extends T5 { x: string }
+interface I6 extends T6 { x: string }
+interface I7 extends T7 { x: string }
+
+type Constructor = new () => T;
+declare function Constructor(): Constructor;
+
+class C1 extends Constructor() { x: string }
+class C2 extends Constructor() { x: string }
+class C3 extends Constructor() { x: string }
+class C4 extends Constructor() { x: string }
+class C5 extends Constructor() { x: string }
+class C6 extends Constructor() { x: string }
+class C7 extends Constructor() { x: string }
+
+declare function fx(x: string): string;
+declare class CX { a: number }
+declare enum EX { A, B, C }
+declare namespace NX { export const a = 1 }
+
+type T10 = typeof fx;
+type T11 = typeof CX;
+type T12 = typeof EX;
+type T13 = typeof NX;
+
+interface I10 extends T10 { x: string }
+interface I11 extends T11 { x: string }
+interface I12 extends T12 { x: string }
+interface I13 extends T13 { x: string }
+
+type Identifiable = { _id: string } & T;
+
+interface I20 extends Partial { x: string }
+interface I21 extends Readonly { x: string }
+interface I22 extends Identifiable { x: string }
+interface I23 extends Identifiable { x: string }
+
+class C20 extends Constructor>() { x: string }
+class C21 extends Constructor>() { x: string }
+class C22 extends Constructor>() { x: string }
+class C23 extends Constructor>() { x: string }
+
+
+//// [interfaceExtendsObjectIntersection.js]
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+var C1 = (function (_super) {
+ __extends(C1, _super);
+ function C1() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C1;
+}(Constructor()));
+var C2 = (function (_super) {
+ __extends(C2, _super);
+ function C2() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C2;
+}(Constructor()));
+var C3 = (function (_super) {
+ __extends(C3, _super);
+ function C3() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C3;
+}(Constructor()));
+var C4 = (function (_super) {
+ __extends(C4, _super);
+ function C4() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C4;
+}(Constructor()));
+var C5 = (function (_super) {
+ __extends(C5, _super);
+ function C5() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C5;
+}(Constructor()));
+var C6 = (function (_super) {
+ __extends(C6, _super);
+ function C6() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C6;
+}(Constructor()));
+var C7 = (function (_super) {
+ __extends(C7, _super);
+ function C7() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C7;
+}(Constructor()));
+var C20 = (function (_super) {
+ __extends(C20, _super);
+ function C20() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C20;
+}(Constructor()));
+var C21 = (function (_super) {
+ __extends(C21, _super);
+ function C21() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C21;
+}(Constructor()));
+var C22 = (function (_super) {
+ __extends(C22, _super);
+ function C22() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C22;
+}(Constructor()));
+var C23 = (function (_super) {
+ __extends(C23, _super);
+ function C23() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C23;
+}(Constructor()));
diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersection.symbols b/tests/baselines/reference/interfaceExtendsObjectIntersection.symbols
new file mode 100644
index 00000000000..16c8c51cf47
--- /dev/null
+++ b/tests/baselines/reference/interfaceExtendsObjectIntersection.symbols
@@ -0,0 +1,230 @@
+=== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersection.ts ===
+
+type T1 = { a: number };
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>a : Symbol(a, Decl(interfaceExtendsObjectIntersection.ts, 1, 11))
+
+type T2 = T1 & { b: number };
+>T2 : Symbol(T2, Decl(interfaceExtendsObjectIntersection.ts, 1, 24))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>b : Symbol(b, Decl(interfaceExtendsObjectIntersection.ts, 2, 16))
+
+type T3 = () => void;
+>T3 : Symbol(T3, Decl(interfaceExtendsObjectIntersection.ts, 2, 29))
+
+type T4 = new () => { a: number };
+>T4 : Symbol(T4, Decl(interfaceExtendsObjectIntersection.ts, 3, 21))
+>a : Symbol(a, Decl(interfaceExtendsObjectIntersection.ts, 4, 21))
+
+type T5 = number[];
+>T5 : Symbol(T5, Decl(interfaceExtendsObjectIntersection.ts, 4, 34))
+
+type T6 = [string, number];
+>T6 : Symbol(T6, Decl(interfaceExtendsObjectIntersection.ts, 5, 19))
+
+type T7 = { [P in 'a' | 'b' | 'c']: string };
+>T7 : Symbol(T7, Decl(interfaceExtendsObjectIntersection.ts, 6, 27))
+>P : Symbol(P, Decl(interfaceExtendsObjectIntersection.ts, 7, 13))
+
+interface I1 extends T1 { x: string }
+>I1 : Symbol(I1, Decl(interfaceExtendsObjectIntersection.ts, 7, 45))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>x : Symbol(I1.x, Decl(interfaceExtendsObjectIntersection.ts, 9, 25))
+
+interface I2 extends T2 { x: string }
+>I2 : Symbol(I2, Decl(interfaceExtendsObjectIntersection.ts, 9, 37))
+>T2 : Symbol(T2, Decl(interfaceExtendsObjectIntersection.ts, 1, 24))
+>x : Symbol(I2.x, Decl(interfaceExtendsObjectIntersection.ts, 10, 25))
+
+interface I3 extends T3 { x: string }
+>I3 : Symbol(I3, Decl(interfaceExtendsObjectIntersection.ts, 10, 37))
+>T3 : Symbol(T3, Decl(interfaceExtendsObjectIntersection.ts, 2, 29))
+>x : Symbol(I3.x, Decl(interfaceExtendsObjectIntersection.ts, 11, 25))
+
+interface I4 extends T4 { x: string }
+>I4 : Symbol(I4, Decl(interfaceExtendsObjectIntersection.ts, 11, 37))
+>T4 : Symbol(T4, Decl(interfaceExtendsObjectIntersection.ts, 3, 21))
+>x : Symbol(I4.x, Decl(interfaceExtendsObjectIntersection.ts, 12, 25))
+
+interface I5 extends T5 { x: string }
+>I5 : Symbol(I5, Decl(interfaceExtendsObjectIntersection.ts, 12, 37))
+>T5 : Symbol(T5, Decl(interfaceExtendsObjectIntersection.ts, 4, 34))
+>x : Symbol(I5.x, Decl(interfaceExtendsObjectIntersection.ts, 13, 25))
+
+interface I6 extends T6 { x: string }
+>I6 : Symbol(I6, Decl(interfaceExtendsObjectIntersection.ts, 13, 37))
+>T6 : Symbol(T6, Decl(interfaceExtendsObjectIntersection.ts, 5, 19))
+>x : Symbol(I6.x, Decl(interfaceExtendsObjectIntersection.ts, 14, 25))
+
+interface I7 extends T7 { x: string }
+>I7 : Symbol(I7, Decl(interfaceExtendsObjectIntersection.ts, 14, 37))
+>T7 : Symbol(T7, Decl(interfaceExtendsObjectIntersection.ts, 6, 27))
+>x : Symbol(I7.x, Decl(interfaceExtendsObjectIntersection.ts, 15, 25))
+
+type Constructor = new () => T;
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 17, 17))
+>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 17, 17))
+
+declare function Constructor(): Constructor;
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 18, 29))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 18, 29))
+
+class C1 extends Constructor() { x: string }
+>C1 : Symbol(C1, Decl(interfaceExtendsObjectIntersection.ts, 18, 50))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>I1 : Symbol(I1, Decl(interfaceExtendsObjectIntersection.ts, 7, 45))
+>x : Symbol(C1.x, Decl(interfaceExtendsObjectIntersection.ts, 20, 36))
+
+class C2 extends Constructor() { x: string }
+>C2 : Symbol(C2, Decl(interfaceExtendsObjectIntersection.ts, 20, 48))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>I2 : Symbol(I2, Decl(interfaceExtendsObjectIntersection.ts, 9, 37))
+>x : Symbol(C2.x, Decl(interfaceExtendsObjectIntersection.ts, 21, 36))
+
+class C3 extends Constructor() { x: string }
+>C3 : Symbol(C3, Decl(interfaceExtendsObjectIntersection.ts, 21, 48))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>I3 : Symbol(I3, Decl(interfaceExtendsObjectIntersection.ts, 10, 37))
+>x : Symbol(C3.x, Decl(interfaceExtendsObjectIntersection.ts, 22, 36))
+
+class C4 extends Constructor() { x: string }
+>C4 : Symbol(C4, Decl(interfaceExtendsObjectIntersection.ts, 22, 48))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>I4 : Symbol(I4, Decl(interfaceExtendsObjectIntersection.ts, 11, 37))
+>x : Symbol(C4.x, Decl(interfaceExtendsObjectIntersection.ts, 23, 36))
+
+class C5 extends Constructor() { x: string }
+>C5 : Symbol(C5, Decl(interfaceExtendsObjectIntersection.ts, 23, 48))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>I5 : Symbol(I5, Decl(interfaceExtendsObjectIntersection.ts, 12, 37))
+>x : Symbol(C5.x, Decl(interfaceExtendsObjectIntersection.ts, 24, 36))
+
+class C6 extends Constructor() { x: string }
+>C6 : Symbol(C6, Decl(interfaceExtendsObjectIntersection.ts, 24, 48))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>I6 : Symbol(I6, Decl(interfaceExtendsObjectIntersection.ts, 13, 37))
+>x : Symbol(C6.x, Decl(interfaceExtendsObjectIntersection.ts, 25, 36))
+
+class C7 extends Constructor() { x: string }
+>C7 : Symbol(C7, Decl(interfaceExtendsObjectIntersection.ts, 25, 48))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>I7 : Symbol(I7, Decl(interfaceExtendsObjectIntersection.ts, 14, 37))
+>x : Symbol(C7.x, Decl(interfaceExtendsObjectIntersection.ts, 26, 36))
+
+declare function fx(x: string): string;
+>fx : Symbol(fx, Decl(interfaceExtendsObjectIntersection.ts, 26, 48))
+>x : Symbol(x, Decl(interfaceExtendsObjectIntersection.ts, 28, 20))
+
+declare class CX { a: number }
+>CX : Symbol(CX, Decl(interfaceExtendsObjectIntersection.ts, 28, 39))
+>a : Symbol(CX.a, Decl(interfaceExtendsObjectIntersection.ts, 29, 18))
+
+declare enum EX { A, B, C }
+>EX : Symbol(EX, Decl(interfaceExtendsObjectIntersection.ts, 29, 30))
+>A : Symbol(EX.A, Decl(interfaceExtendsObjectIntersection.ts, 30, 17))
+>B : Symbol(EX.B, Decl(interfaceExtendsObjectIntersection.ts, 30, 20))
+>C : Symbol(EX.C, Decl(interfaceExtendsObjectIntersection.ts, 30, 23))
+
+declare namespace NX { export const a = 1 }
+>NX : Symbol(NX, Decl(interfaceExtendsObjectIntersection.ts, 30, 27))
+>a : Symbol(a, Decl(interfaceExtendsObjectIntersection.ts, 31, 35))
+
+type T10 = typeof fx;
+>T10 : Symbol(T10, Decl(interfaceExtendsObjectIntersection.ts, 31, 43))
+>fx : Symbol(fx, Decl(interfaceExtendsObjectIntersection.ts, 26, 48))
+
+type T11 = typeof CX;
+>T11 : Symbol(T11, Decl(interfaceExtendsObjectIntersection.ts, 33, 21))
+>CX : Symbol(CX, Decl(interfaceExtendsObjectIntersection.ts, 28, 39))
+
+type T12 = typeof EX;
+>T12 : Symbol(T12, Decl(interfaceExtendsObjectIntersection.ts, 34, 21))
+>EX : Symbol(EX, Decl(interfaceExtendsObjectIntersection.ts, 29, 30))
+
+type T13 = typeof NX;
+>T13 : Symbol(T13, Decl(interfaceExtendsObjectIntersection.ts, 35, 21))
+>NX : Symbol(NX, Decl(interfaceExtendsObjectIntersection.ts, 30, 27))
+
+interface I10 extends T10 { x: string }
+>I10 : Symbol(I10, Decl(interfaceExtendsObjectIntersection.ts, 36, 21))
+>T10 : Symbol(T10, Decl(interfaceExtendsObjectIntersection.ts, 31, 43))
+>x : Symbol(I10.x, Decl(interfaceExtendsObjectIntersection.ts, 38, 27))
+
+interface I11 extends T11 { x: string }
+>I11 : Symbol(I11, Decl(interfaceExtendsObjectIntersection.ts, 38, 39))
+>T11 : Symbol(T11, Decl(interfaceExtendsObjectIntersection.ts, 33, 21))
+>x : Symbol(I11.x, Decl(interfaceExtendsObjectIntersection.ts, 39, 27))
+
+interface I12 extends T12 { x: string }
+>I12 : Symbol(I12, Decl(interfaceExtendsObjectIntersection.ts, 39, 39))
+>T12 : Symbol(T12, Decl(interfaceExtendsObjectIntersection.ts, 34, 21))
+>x : Symbol(I12.x, Decl(interfaceExtendsObjectIntersection.ts, 40, 27))
+
+interface I13 extends T13 { x: string }
+>I13 : Symbol(I13, Decl(interfaceExtendsObjectIntersection.ts, 40, 39))
+>T13 : Symbol(T13, Decl(interfaceExtendsObjectIntersection.ts, 35, 21))
+>x : Symbol(I13.x, Decl(interfaceExtendsObjectIntersection.ts, 41, 27))
+
+type Identifiable = { _id: string } & T;
+>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39))
+>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 43, 18))
+>_id : Symbol(_id, Decl(interfaceExtendsObjectIntersection.ts, 43, 24))
+>T : Symbol(T, Decl(interfaceExtendsObjectIntersection.ts, 43, 18))
+
+interface I20 extends Partial { x: string }
+>I20 : Symbol(I20, Decl(interfaceExtendsObjectIntersection.ts, 43, 43))
+>Partial : Symbol(Partial, Decl(lib.d.ts, --, --))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>x : Symbol(I20.x, Decl(interfaceExtendsObjectIntersection.ts, 45, 35))
+
+interface I21 extends Readonly { x: string }
+>I21 : Symbol(I21, Decl(interfaceExtendsObjectIntersection.ts, 45, 47))
+>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>x : Symbol(I21.x, Decl(interfaceExtendsObjectIntersection.ts, 46, 36))
+
+interface I22 extends Identifiable { x: string }
+>I22 : Symbol(I22, Decl(interfaceExtendsObjectIntersection.ts, 46, 48))
+>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>x : Symbol(I22.x, Decl(interfaceExtendsObjectIntersection.ts, 47, 40))
+
+interface I23 extends Identifiable { x: string }
+>I23 : Symbol(I23, Decl(interfaceExtendsObjectIntersection.ts, 47, 52))
+>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>b : Symbol(b, Decl(interfaceExtendsObjectIntersection.ts, 48, 41))
+>x : Symbol(I23.x, Decl(interfaceExtendsObjectIntersection.ts, 48, 55))
+
+class C20 extends Constructor>() { x: string }
+>C20 : Symbol(C20, Decl(interfaceExtendsObjectIntersection.ts, 48, 67))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>Partial : Symbol(Partial, Decl(lib.d.ts, --, --))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>x : Symbol(C20.x, Decl(interfaceExtendsObjectIntersection.ts, 50, 46))
+
+class C21 extends Constructor>() { x: string }
+>C21 : Symbol(C21, Decl(interfaceExtendsObjectIntersection.ts, 50, 58))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>x : Symbol(C21.x, Decl(interfaceExtendsObjectIntersection.ts, 51, 47))
+
+class C22 extends Constructor>() { x: string }
+>C22 : Symbol(C22, Decl(interfaceExtendsObjectIntersection.ts, 51, 59))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>x : Symbol(C22.x, Decl(interfaceExtendsObjectIntersection.ts, 52, 51))
+
+class C23 extends Constructor>() { x: string }
+>C23 : Symbol(C23, Decl(interfaceExtendsObjectIntersection.ts, 52, 63))
+>Constructor : Symbol(Constructor, Decl(interfaceExtendsObjectIntersection.ts, 15, 37), Decl(interfaceExtendsObjectIntersection.ts, 17, 34))
+>Identifiable : Symbol(Identifiable, Decl(interfaceExtendsObjectIntersection.ts, 41, 39))
+>T1 : Symbol(T1, Decl(interfaceExtendsObjectIntersection.ts, 0, 0))
+>b : Symbol(b, Decl(interfaceExtendsObjectIntersection.ts, 53, 49))
+>x : Symbol(C23.x, Decl(interfaceExtendsObjectIntersection.ts, 53, 66))
+
diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersection.types b/tests/baselines/reference/interfaceExtendsObjectIntersection.types
new file mode 100644
index 00000000000..1ff550df7b4
--- /dev/null
+++ b/tests/baselines/reference/interfaceExtendsObjectIntersection.types
@@ -0,0 +1,242 @@
+=== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersection.ts ===
+
+type T1 = { a: number };
+>T1 : T1
+>a : number
+
+type T2 = T1 & { b: number };
+>T2 : T2
+>T1 : T1
+>b : number
+
+type T3 = () => void;
+>T3 : T3
+
+type T4 = new () => { a: number };
+>T4 : T4
+>a : number
+
+type T5 = number[];
+>T5 : number[]
+
+type T6 = [string, number];
+>T6 : [string, number]
+
+type T7 = { [P in 'a' | 'b' | 'c']: string };
+>T7 : T7
+>P : P
+
+interface I1 extends T1 { x: string }
+>I1 : I1
+>T1 : T1
+>x : string
+
+interface I2 extends T2 { x: string }
+>I2 : I2
+>T2 : T2
+>x : string
+
+interface I3 extends T3 { x: string }
+>I3 : I3
+>T3 : T3
+>x : string
+
+interface I4 extends T4 { x: string }
+>I4 : I4
+>T4 : T4
+>x : string
+
+interface I5 extends T5 { x: string }
+>I5 : I5
+>T5 : number[]
+>x : string
+
+interface I6 extends T6 { x: string }
+>I6 : I6
+>T6 : [string, number]
+>x : string
+
+interface I7 extends T7 { x: string }
+>I7 : I7
+>T7 : T7
+>x : string
+
+type Constructor = new () => T;
+>Constructor : Constructor
+>T : T
+>T : T
+
+declare function Constructor(): Constructor;
+>Constructor : () => Constructor
+>T : T
+>Constructor : Constructor
+>T : T
+
+class C1 extends Constructor() { x: string }
+>C1 : C1
+>Constructor() : I1
+>Constructor : () => Constructor
+>I1 : I1
+>x : string
+
+class C2 extends Constructor() { x: string }
+>C2 : C2
+>Constructor() : I2
+>Constructor : () => Constructor
+>I2 : I2
+>x : string
+
+class C3 extends Constructor() { x: string }
+>C3 : C3
+>Constructor() : I3
+>Constructor : () => Constructor
+>I3 : I3
+>x : string
+
+class C4 extends Constructor() { x: string }
+>C4 : C4
+>Constructor() : I4
+>Constructor : () => Constructor
+>I4 : I4
+>x : string
+
+class C5 extends Constructor() { x: string }
+>C5 : C5
+>Constructor() : I5
+>Constructor : () => Constructor
+>I5 : I5
+>x : string
+
+class C6 extends Constructor() { x: string }
+>C6 : C6
+>Constructor() : I6
+>Constructor : () => Constructor
+>I6 : I6
+>x : string
+
+class C7 extends Constructor() { x: string }
+>C7 : C7
+>Constructor() : I7
+>Constructor : () => Constructor
+>I7 : I7
+>x : string
+
+declare function fx(x: string): string;
+>fx : (x: string) => string
+>x : string
+
+declare class CX { a: number }
+>CX : CX
+>a : number
+
+declare enum EX { A, B, C }
+>EX : EX
+>A : EX
+>B : EX
+>C : EX
+
+declare namespace NX { export const a = 1 }
+>NX : typeof NX
+>a : 1
+>1 : 1
+
+type T10 = typeof fx;
+>T10 : (x: string) => string
+>fx : (x: string) => string
+
+type T11 = typeof CX;
+>T11 : typeof CX
+>CX : typeof CX
+
+type T12 = typeof EX;
+>T12 : typeof EX
+>EX : typeof EX
+
+type T13 = typeof NX;
+>T13 : typeof NX
+>NX : typeof NX
+
+interface I10 extends T10 { x: string }
+>I10 : I10
+>T10 : (x: string) => string
+>x : string
+
+interface I11 extends T11 { x: string }
+>I11 : I11
+>T11 : typeof CX
+>x : string
+
+interface I12 extends T12 { x: string }
+>I12 : I12
+>T12 : typeof EX
+>x : string
+
+interface I13 extends T13 { x: string }
+>I13 : I13
+>T13 : typeof NX
+>x : string
+
+type Identifiable = { _id: string } & T;
+>Identifiable : Identifiable
+>T : T
+>_id : string
+>T : T
+
+interface I20 extends Partial { x: string }
+>I20 : I20
+>Partial : Partial
+>T1 : T1
+>x : string
+
+interface I21 extends Readonly { x: string }
+>I21 : I21
+>Readonly : Readonly
+>T1 : T1
+>x : string
+
+interface I22 extends Identifiable { x: string }
+>I22 : I22
+>Identifiable : Identifiable
+>T1 : T1
+>x : string
+
+interface I23 extends Identifiable { x: string }
+>I23 : I23
+>Identifiable : Identifiable
+>T1 : T1
+>b : number
+>x : string
+
+class C20 extends Constructor>() { x: string }
+>C20 : C20
+>Constructor>() : Partial
+>Constructor : () => Constructor
+>Partial : Partial
+>T1 : T1
+>x : string
+
+class C21 extends Constructor>() { x: string }
+>C21 : C21
+>Constructor>() : Readonly
+>Constructor : () => Constructor
+>Readonly : Readonly
+>T1 : T1
+>x : string
+
+class C22 extends Constructor>() { x: string }
+>C22 : C22
+>Constructor>() : Identifiable
+>Constructor : () => Constructor
+>Identifiable : Identifiable
+>T1 : T1
+>x : string
+
+class C23 extends Constructor>() { x: string }
+>C23 : C23
+>Constructor>() : Identifiable
+>Constructor : () => Constructor
+>Identifiable : Identifiable
+>T1 : T1
+>b : number
+>x : string
+
diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.errors.txt b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.errors.txt
new file mode 100644
index 00000000000..839474b3bdc
--- /dev/null
+++ b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.errors.txt
@@ -0,0 +1,197 @@
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(8,11): error TS2430: Interface 'I1' incorrectly extends interface 'T1'.
+ Types of property 'a' are incompatible.
+ Type 'string' is not assignable to type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(9,11): error TS2430: Interface 'I2' incorrectly extends interface 'T2'.
+ Type 'I2' is not assignable to type '{ b: number; }'.
+ Types of property 'b' are incompatible.
+ Type 'string' is not assignable to type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(10,11): error TS2430: Interface 'I3' incorrectly extends interface 'number[]'.
+ Types of property 'length' are incompatible.
+ Type 'string' is not assignable to type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(11,11): error TS2430: Interface 'I4' incorrectly extends interface '[string, number]'.
+ Types of property '0' are incompatible.
+ Type 'number' is not assignable to type 'string'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(12,11): error TS2430: Interface 'I5' incorrectly extends interface 'T5'.
+ Types of property 'c' are incompatible.
+ Type 'number' is not assignable to type 'string'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(17,7): error TS2415: Class 'C1' incorrectly extends base class 'T1'.
+ Types of property 'a' are incompatible.
+ Type 'string' is not assignable to type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(18,7): error TS2415: Class 'C2' incorrectly extends base class 'T2'.
+ Type 'C2' is not assignable to type '{ b: number; }'.
+ Types of property 'b' are incompatible.
+ Type 'string' is not assignable to type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(19,7): error TS2415: Class 'C3' incorrectly extends base class 'number[]'.
+ Types of property 'length' are incompatible.
+ Type 'string' is not assignable to type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(20,7): error TS2415: Class 'C4' incorrectly extends base class '[string, number]'.
+ Types of property '0' are incompatible.
+ Type 'number' is not assignable to type 'string'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(21,7): error TS2415: Class 'C5' incorrectly extends base class 'T5'.
+ Types of property 'c' are incompatible.
+ Type 'number' is not assignable to type 'string'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(31,11): error TS2430: Interface 'I10' incorrectly extends interface 'typeof CX'.
+ Types of property 'a' are incompatible.
+ Type 'number' is not assignable to type 'string'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(32,11): error TS2430: Interface 'I11' incorrectly extends interface 'typeof EX'.
+ Types of property 'C' are incompatible.
+ Type 'string' is not assignable to type 'EX'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(33,11): error TS2430: Interface 'I12' incorrectly extends interface 'typeof NX'.
+ Types of property 'a' are incompatible.
+ Type 'number' is not assignable to type '"hello"'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(34,29): error TS2411: Property 'a' of type 'string' is not assignable to string index type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(34,29): error TS2411: Property 'prototype' of type 'CX' is not assignable to string index type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(35,29): error TS2413: Numeric index type 'string' is not assignable to string index type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(36,29): error TS2411: Property 'a' of type '"hello"' is not assignable to string index type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(40,11): error TS2430: Interface 'I20' incorrectly extends interface 'Partial'.
+ Types of property 'a' are incompatible.
+ Type 'string' is not assignable to type 'number | undefined'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(41,11): error TS2430: Interface 'I21' incorrectly extends interface 'Readonly'.
+ Types of property 'a' are incompatible.
+ Type 'string' is not assignable to type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(42,11): error TS2430: Interface 'I22' incorrectly extends interface 'Identifiable'.
+ Type 'I22' is not assignable to type 'T1'.
+ Types of property 'a' are incompatible.
+ Type 'string' is not assignable to type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(43,11): error TS2430: Interface 'I23' incorrectly extends interface 'Identifiable'.
+ Type 'I23' is not assignable to type 'T1'.
+ Types of property 'a' are incompatible.
+ Type 'string' is not assignable to type 'number'.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(47,23): error TS2312: An interface may only extend a class or another interface.
+tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts(48,26): error TS2312: An interface may only extend a class or another interface.
+
+
+==== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts (23 errors) ====
+
+ type T1 = { a: number };
+ type T2 = T1 & { b: number };
+ type T3 = number[];
+ type T4 = [string, number];
+ type T5 = { [P in 'a' | 'b' | 'c']: string };
+
+ interface I1 extends T1 { a: string }
+ ~~
+!!! error TS2430: Interface 'I1' incorrectly extends interface 'T1'.
+!!! error TS2430: Types of property 'a' are incompatible.
+!!! error TS2430: Type 'string' is not assignable to type 'number'.
+ interface I2 extends T2 { b: string }
+ ~~
+!!! error TS2430: Interface 'I2' incorrectly extends interface 'T2'.
+!!! error TS2430: Type 'I2' is not assignable to type '{ b: number; }'.
+!!! error TS2430: Types of property 'b' are incompatible.
+!!! error TS2430: Type 'string' is not assignable to type 'number'.
+ interface I3 extends T3 { length: string }
+ ~~
+!!! error TS2430: Interface 'I3' incorrectly extends interface 'number[]'.
+!!! error TS2430: Types of property 'length' are incompatible.
+!!! error TS2430: Type 'string' is not assignable to type 'number'.
+ interface I4 extends T4 { 0: number }
+ ~~
+!!! error TS2430: Interface 'I4' incorrectly extends interface '[string, number]'.
+!!! error TS2430: Types of property '0' are incompatible.
+!!! error TS2430: Type 'number' is not assignable to type 'string'.
+ interface I5 extends T5 { c: number }
+ ~~
+!!! error TS2430: Interface 'I5' incorrectly extends interface 'T5'.
+!!! error TS2430: Types of property 'c' are incompatible.
+!!! error TS2430: Type 'number' is not assignable to type 'string'.
+
+ type Constructor = new () => T;
+ declare function Constructor(): Constructor;
+
+ class C1 extends Constructor() { a: string }
+ ~~
+!!! error TS2415: Class 'C1' incorrectly extends base class 'T1'.
+!!! error TS2415: Types of property 'a' are incompatible.
+!!! error TS2415: Type 'string' is not assignable to type 'number'.
+ class C2 extends Constructor() { b: string }
+ ~~
+!!! error TS2415: Class 'C2' incorrectly extends base class 'T2'.
+!!! error TS2415: Type 'C2' is not assignable to type '{ b: number; }'.
+!!! error TS2415: Types of property 'b' are incompatible.
+!!! error TS2415: Type 'string' is not assignable to type 'number'.
+ class C3 extends Constructor() { length: string }
+ ~~
+!!! error TS2415: Class 'C3' incorrectly extends base class 'number[]'.
+!!! error TS2415: Types of property 'length' are incompatible.
+!!! error TS2415: Type 'string' is not assignable to type 'number'.
+ class C4 extends Constructor() { 0: number }
+ ~~
+!!! error TS2415: Class 'C4' incorrectly extends base class '[string, number]'.
+!!! error TS2415: Types of property '0' are incompatible.
+!!! error TS2415: Type 'number' is not assignable to type 'string'.
+ class C5 extends Constructor() { c: number }
+ ~~
+!!! error TS2415: Class 'C5' incorrectly extends base class 'T5'.
+!!! error TS2415: Types of property 'c' are incompatible.
+!!! error TS2415: Type 'number' is not assignable to type 'string'.
+
+ declare class CX { static a: string }
+ declare enum EX { A, B, C }
+ declare namespace NX { export const a = "hello" }
+
+ type TCX = typeof CX;
+ type TEX = typeof EX;
+ type TNX = typeof NX;
+
+ interface I10 extends TCX { a: number }
+ ~~~
+!!! error TS2430: Interface 'I10' incorrectly extends interface 'typeof CX'.
+!!! error TS2430: Types of property 'a' are incompatible.
+!!! error TS2430: Type 'number' is not assignable to type 'string'.
+ interface I11 extends TEX { C: string }
+ ~~~
+!!! error TS2430: Interface 'I11' incorrectly extends interface 'typeof EX'.
+!!! error TS2430: Types of property 'C' are incompatible.
+!!! error TS2430: Type 'string' is not assignable to type 'EX'.
+ interface I12 extends TNX { a: number }
+ ~~~
+!!! error TS2430: Interface 'I12' incorrectly extends interface 'typeof NX'.
+!!! error TS2430: Types of property 'a' are incompatible.
+!!! error TS2430: Type 'number' is not assignable to type '"hello"'.
+ interface I14 extends TCX { [x: string]: number }
+ ~~~~~~~~~~~~~~~~~~~
+!!! error TS2411: Property 'a' of type 'string' is not assignable to string index type 'number'.
+ ~~~~~~~~~~~~~~~~~~~
+!!! error TS2411: Property 'prototype' of type 'CX' is not assignable to string index type 'number'.
+ interface I15 extends TEX { [x: string]: number }
+ ~~~~~~~~~~~~~~~~~~~
+!!! error TS2413: Numeric index type 'string' is not assignable to string index type 'number'.
+ interface I16 extends TNX { [x: string]: number }
+ ~~~~~~~~~~~~~~~~~~~
+!!! error TS2411: Property 'a' of type '"hello"' is not assignable to string index type 'number'.
+
+ type Identifiable = { _id: string } & T;
+
+ interface I20 extends Partial { a: string }
+ ~~~
+!!! error TS2430: Interface 'I20' incorrectly extends interface 'Partial'.
+!!! error TS2430: Types of property 'a' are incompatible.
+!!! error TS2430: Type 'string' is not assignable to type 'number | undefined'.
+ interface I21 extends Readonly { a: string }
+ ~~~
+!!! error TS2430: Interface 'I21' incorrectly extends interface 'Readonly'.
+!!! error TS2430: Types of property 'a' are incompatible.
+!!! error TS2430: Type 'string' is not assignable to type 'number'.
+ interface I22 extends Identifiable { a: string }
+ ~~~
+!!! error TS2430: Interface 'I22' incorrectly extends interface 'Identifiable'.
+!!! error TS2430: Type 'I22' is not assignable to type 'T1'.
+!!! error TS2430: Types of property 'a' are incompatible.
+!!! error TS2430: Type 'string' is not assignable to type 'number'.
+ interface I23 extends Identifiable { a: string }
+ ~~~
+!!! error TS2430: Interface 'I23' incorrectly extends interface 'Identifiable'.
+!!! error TS2430: Type 'I23' is not assignable to type 'T1'.
+!!! error TS2430: Types of property 'a' are incompatible.
+!!! error TS2430: Type 'string' is not assignable to type 'number'.
+
+ type U = { a: number } | { b: string };
+
+ interface I30 extends U { x: string }
+ ~
+!!! error TS2312: An interface may only extend a class or another interface.
+ interface I31 extends T { x: string }
+ ~
+!!! error TS2312: An interface may only extend a class or another interface.
+
\ No newline at end of file
diff --git a/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.js b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.js
new file mode 100644
index 00000000000..61f84b2f7fe
--- /dev/null
+++ b/tests/baselines/reference/interfaceExtendsObjectIntersectionErrors.js
@@ -0,0 +1,97 @@
+//// [interfaceExtendsObjectIntersectionErrors.ts]
+
+type T1 = { a: number };
+type T2 = T1 & { b: number };
+type T3 = number[];
+type T4 = [string, number];
+type T5 = { [P in 'a' | 'b' | 'c']: string };
+
+interface I1 extends T1 { a: string }
+interface I2 extends T2 { b: string }
+interface I3 extends T3 { length: string }
+interface I4 extends T4 { 0: number }
+interface I5 extends T5 { c: number }
+
+type Constructor = new () => T;
+declare function Constructor(): Constructor;
+
+class C1 extends Constructor() { a: string }
+class C2 extends Constructor() { b: string }
+class C3 extends Constructor() { length: string }
+class C4 extends Constructor() { 0: number }
+class C5 extends Constructor() { c: number }
+
+declare class CX { static a: string }
+declare enum EX { A, B, C }
+declare namespace NX { export const a = "hello" }
+
+type TCX = typeof CX;
+type TEX = typeof EX;
+type TNX = typeof NX;
+
+interface I10 extends TCX { a: number }
+interface I11 extends TEX { C: string }
+interface I12 extends TNX { a: number }
+interface I14 extends TCX { [x: string]: number }
+interface I15 extends TEX { [x: string]: number }
+interface I16 extends TNX { [x: string]: number }
+
+type Identifiable = { _id: string } & T;
+
+interface I20 extends Partial { a: string }
+interface I21 extends Readonly { a: string }
+interface I22 extends Identifiable { a: string }
+interface I23 extends Identifiable { a: string }
+
+type U = { a: number } | { b: string };
+
+interface I30 extends U { x: string }
+interface I31 extends T { x: string }
+
+
+//// [interfaceExtendsObjectIntersectionErrors.js]
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+var C1 = (function (_super) {
+ __extends(C1, _super);
+ function C1() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C1;
+}(Constructor()));
+var C2 = (function (_super) {
+ __extends(C2, _super);
+ function C2() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C2;
+}(Constructor()));
+var C3 = (function (_super) {
+ __extends(C3, _super);
+ function C3() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C3;
+}(Constructor()));
+var C4 = (function (_super) {
+ __extends(C4, _super);
+ function C4() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C4;
+}(Constructor()));
+var C5 = (function (_super) {
+ __extends(C5, _super);
+ function C5() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ return C5;
+}(Constructor()));
diff --git a/tests/baselines/reference/intersectionThisTypes.js b/tests/baselines/reference/intersectionThisTypes.js
new file mode 100644
index 00000000000..9c7be09eeb8
--- /dev/null
+++ b/tests/baselines/reference/intersectionThisTypes.js
@@ -0,0 +1,57 @@
+//// [intersectionThisTypes.ts]
+interface Thing1 {
+ a: number;
+ self(): this;
+}
+
+interface Thing2 {
+ b: number;
+ me(): this;
+}
+
+type Thing3 = Thing1 & Thing2;
+type Thing4 = Thing3 & string[];
+
+function f1(t: Thing3) {
+ t = t.self();
+ t = t.me().self().me();
+}
+
+interface Thing5 extends Thing4 {
+ c: string;
+}
+
+function f2(t: Thing5) {
+ t = t.self();
+ t = t.me().self().me();
+}
+
+interface Component {
+ extend(props: T): this & T;
+}
+
+interface Label extends Component {
+ title: string;
+}
+
+function test(label: Label) {
+ const extended = label.extend({ id: 67 }).extend({ tag: "hello" });
+ extended.id; // Ok
+ extended.tag; // Ok
+}
+
+
+//// [intersectionThisTypes.js]
+function f1(t) {
+ t = t.self();
+ t = t.me().self().me();
+}
+function f2(t) {
+ t = t.self();
+ t = t.me().self().me();
+}
+function test(label) {
+ var extended = label.extend({ id: 67 }).extend({ tag: "hello" });
+ extended.id; // Ok
+ extended.tag; // Ok
+}
diff --git a/tests/baselines/reference/intersectionThisTypes.symbols b/tests/baselines/reference/intersectionThisTypes.symbols
new file mode 100644
index 00000000000..8a8a6cd5496
--- /dev/null
+++ b/tests/baselines/reference/intersectionThisTypes.symbols
@@ -0,0 +1,127 @@
+=== tests/cases/conformance/types/intersection/intersectionThisTypes.ts ===
+interface Thing1 {
+>Thing1 : Symbol(Thing1, Decl(intersectionThisTypes.ts, 0, 0))
+
+ a: number;
+>a : Symbol(Thing1.a, Decl(intersectionThisTypes.ts, 0, 18))
+
+ self(): this;
+>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14))
+}
+
+interface Thing2 {
+>Thing2 : Symbol(Thing2, Decl(intersectionThisTypes.ts, 3, 1))
+
+ b: number;
+>b : Symbol(Thing2.b, Decl(intersectionThisTypes.ts, 5, 18))
+
+ me(): this;
+>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14))
+}
+
+type Thing3 = Thing1 & Thing2;
+>Thing3 : Symbol(Thing3, Decl(intersectionThisTypes.ts, 8, 1))
+>Thing1 : Symbol(Thing1, Decl(intersectionThisTypes.ts, 0, 0))
+>Thing2 : Symbol(Thing2, Decl(intersectionThisTypes.ts, 3, 1))
+
+type Thing4 = Thing3 & string[];
+>Thing4 : Symbol(Thing4, Decl(intersectionThisTypes.ts, 10, 30))
+>Thing3 : Symbol(Thing3, Decl(intersectionThisTypes.ts, 8, 1))
+
+function f1(t: Thing3) {
+>f1 : Symbol(f1, Decl(intersectionThisTypes.ts, 11, 32))
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12))
+>Thing3 : Symbol(Thing3, Decl(intersectionThisTypes.ts, 8, 1))
+
+ t = t.self();
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12))
+>t.self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14))
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12))
+>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14))
+
+ t = t.me().self().me();
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12))
+>t.me().self().me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14))
+>t.me().self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14))
+>t.me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14))
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 13, 12))
+>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14))
+>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14))
+>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14))
+}
+
+interface Thing5 extends Thing4 {
+>Thing5 : Symbol(Thing5, Decl(intersectionThisTypes.ts, 16, 1))
+>Thing4 : Symbol(Thing4, Decl(intersectionThisTypes.ts, 10, 30))
+
+ c: string;
+>c : Symbol(Thing5.c, Decl(intersectionThisTypes.ts, 18, 33))
+}
+
+function f2(t: Thing5) {
+>f2 : Symbol(f2, Decl(intersectionThisTypes.ts, 20, 1))
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12))
+>Thing5 : Symbol(Thing5, Decl(intersectionThisTypes.ts, 16, 1))
+
+ t = t.self();
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12))
+>t.self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14))
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12))
+>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14))
+
+ t = t.me().self().me();
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12))
+>t.me().self().me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14))
+>t.me().self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14))
+>t.me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14))
+>t : Symbol(t, Decl(intersectionThisTypes.ts, 22, 12))
+>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14))
+>self : Symbol(Thing1.self, Decl(intersectionThisTypes.ts, 1, 14))
+>me : Symbol(Thing2.me, Decl(intersectionThisTypes.ts, 6, 14))
+}
+
+interface Component {
+>Component : Symbol(Component, Decl(intersectionThisTypes.ts, 25, 1))
+
+ extend(props: T): this & T;
+>extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21))
+>T : Symbol(T, Decl(intersectionThisTypes.ts, 28, 11))
+>props : Symbol(props, Decl(intersectionThisTypes.ts, 28, 14))
+>T : Symbol(T, Decl(intersectionThisTypes.ts, 28, 11))
+>T : Symbol(T, Decl(intersectionThisTypes.ts, 28, 11))
+}
+
+interface Label extends Component {
+>Label : Symbol(Label, Decl(intersectionThisTypes.ts, 29, 1))
+>Component : Symbol(Component, Decl(intersectionThisTypes.ts, 25, 1))
+
+ title: string;
+>title : Symbol(Label.title, Decl(intersectionThisTypes.ts, 31, 35))
+}
+
+function test(label: Label) {
+>test : Symbol(test, Decl(intersectionThisTypes.ts, 33, 1))
+>label : Symbol(label, Decl(intersectionThisTypes.ts, 35, 14))
+>Label : Symbol(Label, Decl(intersectionThisTypes.ts, 29, 1))
+
+ const extended = label.extend({ id: 67 }).extend({ tag: "hello" });
+>extended : Symbol(extended, Decl(intersectionThisTypes.ts, 36, 9))
+>label.extend({ id: 67 }).extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21))
+>label.extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21))
+>label : Symbol(label, Decl(intersectionThisTypes.ts, 35, 14))
+>extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21))
+>id : Symbol(id, Decl(intersectionThisTypes.ts, 36, 35))
+>extend : Symbol(Component.extend, Decl(intersectionThisTypes.ts, 27, 21))
+>tag : Symbol(tag, Decl(intersectionThisTypes.ts, 36, 54))
+
+ extended.id; // Ok
+>extended.id : Symbol(id, Decl(intersectionThisTypes.ts, 36, 35))
+>extended : Symbol(extended, Decl(intersectionThisTypes.ts, 36, 9))
+>id : Symbol(id, Decl(intersectionThisTypes.ts, 36, 35))
+
+ extended.tag; // Ok
+>extended.tag : Symbol(tag, Decl(intersectionThisTypes.ts, 36, 54))
+>extended : Symbol(extended, Decl(intersectionThisTypes.ts, 36, 9))
+>tag : Symbol(tag, Decl(intersectionThisTypes.ts, 36, 54))
+}
+
diff --git a/tests/baselines/reference/intersectionThisTypes.types b/tests/baselines/reference/intersectionThisTypes.types
new file mode 100644
index 00000000000..285609cdfdc
--- /dev/null
+++ b/tests/baselines/reference/intersectionThisTypes.types
@@ -0,0 +1,145 @@
+=== tests/cases/conformance/types/intersection/intersectionThisTypes.ts ===
+interface Thing1 {
+>Thing1 : Thing1
+
+ a: number;
+>a : number
+
+ self(): this;
+>self : () => this
+}
+
+interface Thing2 {
+>Thing2 : Thing2
+
+ b: number;
+>b : number
+
+ me(): this;
+>me : () => this
+}
+
+type Thing3 = Thing1 & Thing2;
+>Thing3 : Thing3
+>Thing1 : Thing1
+>Thing2 : Thing2
+
+type Thing4 = Thing3 & string[];
+>Thing4 : Thing4
+>Thing3 : Thing3
+
+function f1(t: Thing3) {
+>f1 : (t: Thing3) => void
+>t : Thing3
+>Thing3 : Thing3
+
+ t = t.self();
+>t = t.self() : Thing3
+>t : Thing3
+>t.self() : Thing3
+>t.self : () => Thing3
+>t : Thing3
+>self : () => Thing3
+
+ t = t.me().self().me();
+>t = t.me().self().me() : Thing3
+>t : Thing3
+>t.me().self().me() : Thing3
+>t.me().self().me : () => Thing3
+>t.me().self() : Thing3
+>t.me().self : () => Thing3
+>t.me() : Thing3
+>t.me : () => Thing3
+>t : Thing3
+>me : () => Thing3
+>self : () => Thing3
+>me : () => Thing3
+}
+
+interface Thing5 extends Thing4 {
+>Thing5 : Thing5
+>Thing4 : Thing4
+
+ c: string;
+>c : string
+}
+
+function f2(t: Thing5) {
+>f2 : (t: Thing5) => void
+>t : Thing5
+>Thing5 : Thing5
+
+ t = t.self();
+>t = t.self() : Thing5
+>t : Thing5
+>t.self() : Thing5
+>t.self : () => Thing5
+>t : Thing5
+>self : () => Thing5
+
+ t = t.me().self().me();
+>t = t.me().self().me() : Thing5
+>t : Thing5
+>t.me().self().me() : Thing5
+>t.me().self().me : () => Thing5
+>t.me().self() : Thing5
+>t.me().self : () => Thing5
+>t.me() : Thing5
+>t.me : () => Thing5
+>t : Thing5
+>me : () => Thing5
+>self : () => Thing5
+>me : () => Thing5
+}
+
+interface Component {
+>Component : Component
+
+ extend(props: T): this & T;
+>extend : (props: T) => this & T
+>T : T
+>props : T
+>T : T
+>T : T
+}
+
+interface Label extends Component {
+>Label : Label
+>Component : Component
+
+ title: string;
+>title : string
+}
+
+function test(label: Label) {
+>test : (label: Label) => void
+>label : Label
+>Label : Label
+
+ const extended = label.extend({ id: 67 }).extend({ tag: "hello" });
+>extended : Label & { id: number; } & { tag: string; }
+>label.extend({ id: 67 }).extend({ tag: "hello" }) : Label & { id: number; } & { tag: string; }
+>label.extend({ id: 67 }).extend : (props: T) => Label & { id: number; } & T
+>label.extend({ id: 67 }) : Label & { id: number; }
+>label.extend : (props: T) => Label & T
+>label : Label
+>extend :