From 503fc0642e21a765942c0b9a2408d51887f46241 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 3 Feb 2018 14:45:01 -0800 Subject: [PATCH 01/20] Fix unintended sharing of typeParameters property in SymbolLinks --- src/compiler/checker.ts | 4 ++-- src/compiler/types.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 05da314a816..95af6b94747 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8705,7 +8705,7 @@ namespace ts { const target = type.objectFlags & ObjectFlags.Instantiated ? type.target : type; const symbol = target.symbol; const links = getSymbolLinks(symbol); - let typeParameters = links.typeParameters; + let typeParameters = links.outerTypeParameters; if (!typeParameters) { // The first time an anonymous type is instantiated we compute and store a list of the type // parameters that are in scope (and therefore potentially referenced). For type literals that @@ -8716,7 +8716,7 @@ namespace ts { typeParameters = symbol.flags & SymbolFlags.TypeLiteral && !target.aliasTypeArguments ? filter(outerTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, declaration)) : outerTypeParameters; - links.typeParameters = typeParameters; + links.outerTypeParameters = typeParameters; if (typeParameters.length) { links.instantiations = createMap(); links.instantiations.set(getTypeListId(typeParameters), target); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0a1c49a93c3..829f45900d4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3312,6 +3312,7 @@ namespace ts { type?: Type; // Type of value symbol declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic) + outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type inferredClassType?: Type; // Type of an inferred ES5 class instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) mapper?: TypeMapper; // Type mapper for instantiation alias From 21c397dd5a7a22b3fddbf21ec4168b343d58ab44 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 3 Feb 2018 14:45:16 -0800 Subject: [PATCH 02/20] Add regression test --- .../compiler/typeAliasFunctionTypeSharedSymbol.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/cases/compiler/typeAliasFunctionTypeSharedSymbol.ts diff --git a/tests/cases/compiler/typeAliasFunctionTypeSharedSymbol.ts b/tests/cases/compiler/typeAliasFunctionTypeSharedSymbol.ts new file mode 100644 index 00000000000..de430c18bfe --- /dev/null +++ b/tests/cases/compiler/typeAliasFunctionTypeSharedSymbol.ts @@ -0,0 +1,12 @@ +// Repro from comment in #21496 + +function Mixin(Base: TBase) { + return class extends Base { + }; +} + +type Mixin = ReturnTypeOf + +type ReturnTypeOf = V extends (...args: any[])=>infer R ? R : never; + +type Crashes = number & Mixin; From 8ae5f630d483e48bcca6189d1e4215023d9eb132 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 3 Feb 2018 14:45:25 -0800 Subject: [PATCH 03/20] Accept new baselines --- .../typeAliasFunctionTypeSharedSymbol.js | 36 +++++++++++++++++++ .../typeAliasFunctionTypeSharedSymbol.symbols | 33 +++++++++++++++++ .../typeAliasFunctionTypeSharedSymbol.types | 34 ++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.js create mode 100644 tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.symbols create mode 100644 tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.types diff --git a/tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.js b/tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.js new file mode 100644 index 00000000000..1de017c0ea2 --- /dev/null +++ b/tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.js @@ -0,0 +1,36 @@ +//// [typeAliasFunctionTypeSharedSymbol.ts] +// Repro from comment in #21496 + +function Mixin(Base: TBase) { + return class extends Base { + }; +} + +type Mixin = ReturnTypeOf + +type ReturnTypeOf = V extends (...args: any[])=>infer R ? R : never; + +type Crashes = number & Mixin; + + +//// [typeAliasFunctionTypeSharedSymbol.js] +// Repro from comment in #21496 +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 __()); + }; +})(); +function Mixin(Base) { + return /** @class */ (function (_super) { + __extends(class_1, _super); + function class_1() { + return _super !== null && _super.apply(this, arguments) || this; + } + return class_1; + }(Base)); +} diff --git a/tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.symbols b/tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.symbols new file mode 100644 index 00000000000..b3e176f72ab --- /dev/null +++ b/tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.symbols @@ -0,0 +1,33 @@ +=== tests/cases/compiler/typeAliasFunctionTypeSharedSymbol.ts === +// Repro from comment in #21496 + +function Mixin(Base: TBase) { +>Mixin : Symbol(Mixin, Decl(typeAliasFunctionTypeSharedSymbol.ts, 0, 0), Decl(typeAliasFunctionTypeSharedSymbol.ts, 5, 1)) +>TBase : Symbol(TBase, Decl(typeAliasFunctionTypeSharedSymbol.ts, 2, 15)) +>args : Symbol(args, Decl(typeAliasFunctionTypeSharedSymbol.ts, 2, 35)) +>Base : Symbol(Base, Decl(typeAliasFunctionTypeSharedSymbol.ts, 2, 57)) +>TBase : Symbol(TBase, Decl(typeAliasFunctionTypeSharedSymbol.ts, 2, 15)) + + return class extends Base { +>Base : Symbol(Base, Decl(typeAliasFunctionTypeSharedSymbol.ts, 2, 57)) + + }; +} + +type Mixin = ReturnTypeOf +>Mixin : Symbol(Mixin, Decl(typeAliasFunctionTypeSharedSymbol.ts, 0, 0), Decl(typeAliasFunctionTypeSharedSymbol.ts, 5, 1)) +>ReturnTypeOf : Symbol(ReturnTypeOf, Decl(typeAliasFunctionTypeSharedSymbol.ts, 7, 39)) +>Mixin : Symbol(Mixin, Decl(typeAliasFunctionTypeSharedSymbol.ts, 0, 0), Decl(typeAliasFunctionTypeSharedSymbol.ts, 5, 1)) + +type ReturnTypeOf = V extends (...args: any[])=>infer R ? R : never; +>ReturnTypeOf : Symbol(ReturnTypeOf, Decl(typeAliasFunctionTypeSharedSymbol.ts, 7, 39)) +>V : Symbol(V, Decl(typeAliasFunctionTypeSharedSymbol.ts, 9, 18)) +>V : Symbol(V, Decl(typeAliasFunctionTypeSharedSymbol.ts, 9, 18)) +>args : Symbol(args, Decl(typeAliasFunctionTypeSharedSymbol.ts, 9, 34)) +>R : Symbol(R, Decl(typeAliasFunctionTypeSharedSymbol.ts, 9, 56)) +>R : Symbol(R, Decl(typeAliasFunctionTypeSharedSymbol.ts, 9, 56)) + +type Crashes = number & Mixin; +>Crashes : Symbol(Crashes, Decl(typeAliasFunctionTypeSharedSymbol.ts, 9, 71)) +>Mixin : Symbol(Mixin, Decl(typeAliasFunctionTypeSharedSymbol.ts, 0, 0), Decl(typeAliasFunctionTypeSharedSymbol.ts, 5, 1)) + diff --git a/tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.types b/tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.types new file mode 100644 index 00000000000..9f69ad8f864 --- /dev/null +++ b/tests/baselines/reference/typeAliasFunctionTypeSharedSymbol.types @@ -0,0 +1,34 @@ +=== tests/cases/compiler/typeAliasFunctionTypeSharedSymbol.ts === +// Repro from comment in #21496 + +function Mixin(Base: TBase) { +>Mixin : {}>(Base: TBase) => { new (...args: any[]): (Anonymous class); prototype: Mixin.(Anonymous class); } & TBase +>TBase : TBase +>args : any[] +>Base : TBase +>TBase : TBase + + return class extends Base { +>class extends Base { } : { new (...args: any[]): (Anonymous class); prototype: Mixin.(Anonymous class); } & TBase +>Base : {} + + }; +} + +type Mixin = ReturnTypeOf +>Mixin : { new (...args: any[]): Mixin {}>.(Anonymous class); prototype: Mixin.(Anonymous class); } & (new (...args: any[]) => {}) +>ReturnTypeOf : ReturnTypeOf +>Mixin : {}>(Base: TBase) => { new (...args: any[]): (Anonymous class); prototype: Mixin.(Anonymous class); } & TBase + +type ReturnTypeOf = V extends (...args: any[])=>infer R ? R : never; +>ReturnTypeOf : ReturnTypeOf +>V : V +>V : V +>args : any[] +>R : R +>R : R + +type Crashes = number & Mixin; +>Crashes : Crashes +>Mixin : { new (...args: any[]): Mixin {}>.(Anonymous class); prototype: Mixin.(Anonymous class); } & (new (...args: any[]) => {}) + From b8f3c6169bd23c338bb098da18dc55c50618152a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Feb 2018 06:48:29 -0800 Subject: [PATCH 04/20] Use more permissive wildcard type in definitely false check --- src/compiler/checker.ts | 18 ++++++++++-------- src/compiler/types.ts | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 05da314a816..7f75f234e52 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -315,6 +315,7 @@ namespace ts { const anyType = createIntrinsicType(TypeFlags.Any, "any"); const autoType = createIntrinsicType(TypeFlags.Any, "any"); + const wildcardType = createIntrinsicType(TypeFlags.Any, "any"); const unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined"); const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined"); @@ -8150,9 +8151,10 @@ namespace ts { // Instantiate extends type without instantiating any 'infer T' type parameters const extendsType = instantiateType(baseExtendsType, mapper); // Return falseType for a definitely false extends check. We check an instantations of the two - // types with type parameters mapped to any, the most permissive instantiations possible. If those - // are not related, then no instatiations will be and we can just return the false branch type. - if (!isTypeAssignableTo(getAnyInstantiation(checkType), getAnyInstantiation(extendsType))) { + // types with type parameters mapped to the wildcard type, the most permissive instantiations + // possible (the wildcard type is assignable to and from all types). If those are not related, + // then no instatiations will be and we can just return the false branch type. + if (!isTypeAssignableTo(getWildcardInstantiation(checkType), getWildcardInstantiation(extendsType))) { return instantiateType(baseFalseType, mapper); } // The check could be true for some instantiation @@ -8615,8 +8617,8 @@ namespace ts { return t => t === source ? target : baseMapper(t); } - function anyMapper(type: Type) { - return type.flags & TypeFlags.TypeParameter ? anyType : type; + function wildcardMapper(type: Type) { + return type.flags & TypeFlags.TypeParameter ? wildcardType : type; } function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter { @@ -8873,9 +8875,9 @@ namespace ts { return type; } - function getAnyInstantiation(type: Type) { + function getWildcardInstantiation(type: Type) { return type.flags & (TypeFlags.Primitive | TypeFlags.Any | TypeFlags.Never) ? type : - type.resolvedAnyInstantiation || (type.resolvedAnyInstantiation = instantiateType(type, anyMapper)); + type.wildcardInstantiation || (type.wildcardInstantiation = instantiateType(type, wildcardMapper)); } function instantiateIndexInfo(info: IndexInfo, mapper: TypeMapper): IndexInfo { @@ -9282,7 +9284,7 @@ namespace ts { function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map, errorReporter?: ErrorReporter) { const s = source.flags; const t = target.flags; - if (t & TypeFlags.Any || s & TypeFlags.Never) return true; + if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) return true; if (t & TypeFlags.Never) return false; if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0a1c49a93c3..4bf7148278c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3564,7 +3564,7 @@ namespace ts { aliasSymbol?: Symbol; // Alias associated with type aliasTypeArguments?: Type[]; // Alias type arguments (if any) /* @internal */ - resolvedAnyInstantiation?: Type; // Instantiation with type parameters mapped to any + wildcardInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type } /* @internal */ From 4c9e6499d5f8136c576af956d36e836c26b9227f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Feb 2018 06:48:38 -0800 Subject: [PATCH 05/20] Add tests --- .../types/conditional/conditionalTypes1.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/cases/conformance/types/conditional/conditionalTypes1.ts b/tests/cases/conformance/types/conditional/conditionalTypes1.ts index 6f4e7dc4188..a6169d428ff 100644 --- a/tests/cases/conformance/types/conditional/conditionalTypes1.ts +++ b/tests/cases/conformance/types/conditional/conditionalTypes1.ts @@ -166,12 +166,12 @@ type Not = If; type And = If; type Or = If; -type isString = Extends; +type IsString = Extends; -type Q1 = isString; // false -type Q2 = isString<"abc">; // true -type Q3 = isString; // boolean -type Q4 = isString; // boolean +type Q1 = IsString; // false +type Q2 = IsString<"abc">; // true +type Q3 = IsString; // boolean +type Q4 = IsString; // boolean type N1 = Not; // true type N2 = Not; // false @@ -200,3 +200,9 @@ type O9 = Or; // boolean type T40 = never extends never ? true : false; // true type T41 = number extends never ? true : false; // false type T42 = never extends number ? true : false; // boolean + +type IsNever = T extends never ? true : false; + +type T50 = IsNever; // true +type T51 = IsNever; // false +type T52 = IsNever; // false From d5e2f49eeefd889f1a2911ab668d2a631b17b972 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Feb 2018 06:48:45 -0800 Subject: [PATCH 06/20] Accept new baselines --- .../reference/conditionalTypes1.errors.txt | 16 +++++--- .../baselines/reference/conditionalTypes1.js | 30 +++++++++----- .../reference/conditionalTypes1.symbols | 37 +++++++++++++----- .../reference/conditionalTypes1.types | 39 ++++++++++++++----- 4 files changed, 87 insertions(+), 35 deletions(-) diff --git a/tests/baselines/reference/conditionalTypes1.errors.txt b/tests/baselines/reference/conditionalTypes1.errors.txt index 8016c4449d3..a7717d18263 100644 --- a/tests/baselines/reference/conditionalTypes1.errors.txt +++ b/tests/baselines/reference/conditionalTypes1.errors.txt @@ -304,12 +304,12 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(157,5): error TS2 type And = If; type Or = If; - type isString = Extends; + type IsString = Extends; - type Q1 = isString; // false - type Q2 = isString<"abc">; // true - type Q3 = isString; // boolean - type Q4 = isString; // boolean + type Q1 = IsString; // false + type Q2 = IsString<"abc">; // true + type Q3 = IsString; // boolean + type Q4 = IsString; // boolean type N1 = Not; // true type N2 = Not; // false @@ -338,4 +338,10 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(157,5): error TS2 type T40 = never extends never ? true : false; // true type T41 = number extends never ? true : false; // false type T42 = never extends number ? true : false; // boolean + + type IsNever = T extends never ? true : false; + + type T50 = IsNever; // true + type T51 = IsNever; // false + type T52 = IsNever; // false \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypes1.js b/tests/baselines/reference/conditionalTypes1.js index 088181b3b12..0da7794a762 100644 --- a/tests/baselines/reference/conditionalTypes1.js +++ b/tests/baselines/reference/conditionalTypes1.js @@ -164,12 +164,12 @@ type Not = If; type And = If; type Or = If; -type isString = Extends; +type IsString = Extends; -type Q1 = isString; // false -type Q2 = isString<"abc">; // true -type Q3 = isString; // boolean -type Q4 = isString; // boolean +type Q1 = IsString; // false +type Q2 = IsString<"abc">; // true +type Q3 = IsString; // boolean +type Q4 = IsString; // boolean type N1 = Not; // true type N2 = Not; // false @@ -198,6 +198,12 @@ type O9 = Or; // boolean type T40 = never extends never ? true : false; // true type T41 = number extends never ? true : false; // false type T42 = never extends number ? true : false; // boolean + +type IsNever = T extends never ? true : false; + +type T50 = IsNever; // true +type T51 = IsNever; // false +type T52 = IsNever; // false //// [conditionalTypes1.js] @@ -376,11 +382,11 @@ declare type If = C extends true ? T : F; declare type Not = If; declare type And = If; declare type Or = If; -declare type isString = Extends; -declare type Q1 = isString; -declare type Q2 = isString<"abc">; -declare type Q3 = isString; -declare type Q4 = isString; +declare type IsString = Extends; +declare type Q1 = IsString; +declare type Q2 = IsString<"abc">; +declare type Q3 = IsString; +declare type Q4 = IsString; declare type N1 = Not; declare type N2 = Not; declare type N3 = Not; @@ -405,3 +411,7 @@ declare type O9 = Or; declare type T40 = never extends never ? true : false; declare type T41 = number extends never ? true : false; declare type T42 = never extends number ? true : false; +declare type IsNever = T extends never ? true : false; +declare type T50 = IsNever; +declare type T51 = IsNever; +declare type T52 = IsNever; diff --git a/tests/baselines/reference/conditionalTypes1.symbols b/tests/baselines/reference/conditionalTypes1.symbols index ab0426f67d5..9d3b79d5c30 100644 --- a/tests/baselines/reference/conditionalTypes1.symbols +++ b/tests/baselines/reference/conditionalTypes1.symbols @@ -645,27 +645,27 @@ type Or = If; >A : Symbol(A, Decl(conditionalTypes1.ts, 163, 8)) >B : Symbol(B, Decl(conditionalTypes1.ts, 163, 26)) -type isString = Extends; ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +type IsString = Extends; +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) >T : Symbol(T, Decl(conditionalTypes1.ts, 165, 14)) >Extends : Symbol(Extends, Decl(conditionalTypes1.ts, 157, 1)) >T : Symbol(T, Decl(conditionalTypes1.ts, 165, 14)) -type Q1 = isString; // false +type Q1 = IsString; // false >Q1 : Symbol(Q1, Decl(conditionalTypes1.ts, 165, 38)) ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) -type Q2 = isString<"abc">; // true +type Q2 = IsString<"abc">; // true >Q2 : Symbol(Q2, Decl(conditionalTypes1.ts, 167, 27)) ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) -type Q3 = isString; // boolean +type Q3 = IsString; // boolean >Q3 : Symbol(Q3, Decl(conditionalTypes1.ts, 168, 26)) ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) -type Q4 = isString; // boolean +type Q4 = IsString; // boolean >Q4 : Symbol(Q4, Decl(conditionalTypes1.ts, 169, 24)) ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) type N1 = Not; // true >N1 : Symbol(N1, Decl(conditionalTypes1.ts, 170, 26)) @@ -760,3 +760,20 @@ type T41 = number extends never ? true : false; // false type T42 = never extends number ? true : false; // boolean >T42 : Symbol(T42, Decl(conditionalTypes1.ts, 197, 47)) +type IsNever = T extends never ? true : false; +>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 200, 13)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 200, 13)) + +type T50 = IsNever; // true +>T50 : Symbol(T50, Decl(conditionalTypes1.ts, 200, 49)) +>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47)) + +type T51 = IsNever; // false +>T51 : Symbol(T51, Decl(conditionalTypes1.ts, 202, 26)) +>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47)) + +type T52 = IsNever; // false +>T52 : Symbol(T52, Decl(conditionalTypes1.ts, 203, 27)) +>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47)) + diff --git a/tests/baselines/reference/conditionalTypes1.types b/tests/baselines/reference/conditionalTypes1.types index 9fc72f368d5..df825ecd40b 100644 --- a/tests/baselines/reference/conditionalTypes1.types +++ b/tests/baselines/reference/conditionalTypes1.types @@ -717,27 +717,27 @@ type Or = If; >true : true >B : B -type isString = Extends; ->isString : Extends +type IsString = Extends; +>IsString : Extends >T : T >Extends : Extends >T : T -type Q1 = isString; // false +type Q1 = IsString; // false >Q1 : false ->isString : Extends +>IsString : Extends -type Q2 = isString<"abc">; // true +type Q2 = IsString<"abc">; // true >Q2 : true ->isString : Extends +>IsString : Extends -type Q3 = isString; // boolean +type Q3 = IsString; // boolean >Q3 : boolean ->isString : Extends +>IsString : Extends -type Q4 = isString; // boolean +type Q4 = IsString; // boolean >Q4 : boolean ->isString : Extends +>IsString : Extends type N1 = Not; // true >N1 : true @@ -864,3 +864,22 @@ type T42 = never extends number ? true : false; // boolean >true : true >false : false +type IsNever = T extends never ? true : false; +>IsNever : IsNever +>T : T +>T : T +>true : true +>false : false + +type T50 = IsNever; // true +>T50 : true +>IsNever : IsNever + +type T51 = IsNever; // false +>T51 : false +>IsNever : IsNever + +type T52 = IsNever; // false +>T52 : false +>IsNever : IsNever + From 120af861f7d74529a62ff4f7cccc1878d59e2f25 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 5 Feb 2018 11:20:22 -0800 Subject: [PATCH 07/20] Fix bug: replacmentSpan for completion shouldn't include property name that doesn't start with completion name (#21587) --- src/services/completions.ts | 5 ++++- ...etionListInvalidMemberNames_withExistingIdentifier.ts | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/services/completions.ts b/src/services/completions.ts index 8a28ae88bb6..6f4cadec7e1 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -185,7 +185,10 @@ namespace ts.Completions { else if (needsConvertPropertyAccess) { // TODO: GH#20619 Use configured quote style insertText = `["${name}"]`; - replacementSpan = createTextSpanFromBounds(findChildOfKind(propertyAccessToConvert!, SyntaxKind.DotToken, sourceFile)!.getStart(sourceFile), propertyAccessToConvert!.name.end); + const dot = findChildOfKind(propertyAccessToConvert!, SyntaxKind.DotToken, sourceFile)!; + // If the text after the '.' starts with this name, write over it. Else, add new text. + const end = startsWith(name, propertyAccessToConvert!.name.text) ? propertyAccessToConvert!.name.end : dot.end; + replacementSpan = createTextSpanFromBounds(dot.getStart(sourceFile), end); } if (isJsxInitializer) { diff --git a/tests/cases/fourslash/completionListInvalidMemberNames_withExistingIdentifier.ts b/tests/cases/fourslash/completionListInvalidMemberNames_withExistingIdentifier.ts index 8463a710b01..3c06692293e 100644 --- a/tests/cases/fourslash/completionListInvalidMemberNames_withExistingIdentifier.ts +++ b/tests/cases/fourslash/completionListInvalidMemberNames_withExistingIdentifier.ts @@ -1,7 +1,10 @@ /// ////declare const x: { "foo ": "space in the name", }; -////x[|.fo/**/|]; +////x[|.fo/*0*/|]; +////x[|./*1*/|] +////unrelatedIdentifier; -const replacementSpan = test.ranges()[0]; -verify.completionsAt("", [{ name: "foo ", insertText: '["foo "]', replacementSpan }], { includeInsertTextCompletions: true }); +const [r0, r1] = test.ranges(); +verify.completionsAt("0", [{ name: "foo ", insertText: '["foo "]', replacementSpan: r0 }], { includeInsertTextCompletions: true }); +verify.completionsAt("1", [{ name: "foo ", insertText: '["foo "]', replacementSpan: r1 }], { includeInsertTextCompletions: true }); From c1a2adcea4d469236c82f28d34c05aa412acb3f7 Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Mon, 5 Feb 2018 20:34:28 +0100 Subject: [PATCH 08/20] Fix return types of NodeBuilder methods (#21619) --- src/compiler/types.ts | 12 ++++++------ tests/baselines/reference/api/tsserverlibrary.d.ts | 14 ++++++++------ tests/baselines/reference/api/typescript.d.ts | 14 ++++++++------ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9735a64bb7a..3f03c1431e5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2779,19 +2779,19 @@ namespace ts { /** Note that the resulting nodes cannot be checked. */ typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode; /** Note that the resulting nodes cannot be checked. */ - signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration; + signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration & {typeArguments?: NodeArray} | undefined; /** Note that the resulting nodes cannot be checked. */ - indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration; + indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToEntityName(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): EntityName; + symbolToEntityName(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): EntityName | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToExpression(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): Expression; + symbolToExpression(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): Expression | undefined; /** Note that the resulting nodes cannot be checked. */ symbolToTypeParameterDeclarations(symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): NodeArray | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToParameterDeclaration(symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): ParameterDeclaration; + symbolToParameterDeclaration(symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): ParameterDeclaration | undefined; /** Note that the resulting nodes cannot be checked. */ - typeParameterToDeclaration(parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeParameterDeclaration; + typeParameterToDeclaration(parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeParameterDeclaration | undefined; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolAtLocation(node: Node): Symbol | undefined; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 9d3000d6b60..95d6a70607c 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1740,19 +1740,21 @@ declare namespace ts { /** Note that the resulting nodes cannot be checked. */ typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode; /** Note that the resulting nodes cannot be checked. */ - signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration; + signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration & { + typeArguments?: NodeArray; + } | undefined; /** Note that the resulting nodes cannot be checked. */ - indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration; + indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToEntityName(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): EntityName; + symbolToEntityName(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): EntityName | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToExpression(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): Expression; + symbolToExpression(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): Expression | undefined; /** Note that the resulting nodes cannot be checked. */ symbolToTypeParameterDeclarations(symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): NodeArray | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToParameterDeclaration(symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): ParameterDeclaration; + symbolToParameterDeclaration(symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): ParameterDeclaration | undefined; /** Note that the resulting nodes cannot be checked. */ - typeParameterToDeclaration(parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeParameterDeclaration; + typeParameterToDeclaration(parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeParameterDeclaration | undefined; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolAtLocation(node: Node): Symbol | undefined; getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[]; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 65fcacaa5aa..f9a6bdd55e8 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1740,19 +1740,21 @@ declare namespace ts { /** Note that the resulting nodes cannot be checked. */ typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode; /** Note that the resulting nodes cannot be checked. */ - signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration; + signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration & { + typeArguments?: NodeArray; + } | undefined; /** Note that the resulting nodes cannot be checked. */ - indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration; + indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToEntityName(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): EntityName; + symbolToEntityName(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): EntityName | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToExpression(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): Expression; + symbolToExpression(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): Expression | undefined; /** Note that the resulting nodes cannot be checked. */ symbolToTypeParameterDeclarations(symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): NodeArray | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToParameterDeclaration(symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): ParameterDeclaration; + symbolToParameterDeclaration(symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): ParameterDeclaration | undefined; /** Note that the resulting nodes cannot be checked. */ - typeParameterToDeclaration(parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeParameterDeclaration; + typeParameterToDeclaration(parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeParameterDeclaration | undefined; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolAtLocation(node: Node): Symbol | undefined; getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[]; From d11c7aeeaf27e077d42d4092ebdac117aa2123d9 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 5 Feb 2018 11:42:03 -0800 Subject: [PATCH 09/20] class Project: implement `log` and `error` from `LanguageServiceHost` (#21635) * class Project: implement `log` and `error` from `LanguageServiceHost` * Update API baseline --- src/server/project.ts | 8 ++++++++ tests/baselines/reference/api/tsserverlibrary.d.ts | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/server/project.ts b/src/server/project.ts index 140bab4fc06..47365547479 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -428,6 +428,14 @@ namespace ts.server { this.projectService.logger.info(s); } + log(s: string) { + this.writeLog(s); + } + + error(s: string) { + this.projectService.logger.msg(s, Msg.Err); + } + private setInternalCompilerOptionsForEmittingJsFiles() { if (this.projectKind === ProjectKind.Inferred || this.projectKind === ProjectKind.External) { this.compilerOptions.noEmitForJsFiles = true; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 95d6a70607c..fcd9d04d06d 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -7500,6 +7500,8 @@ declare namespace ts.server { resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[]; directoryExists(path: string): boolean; getDirectories(path: string): string[]; + log(s: string): void; + error(s: string): void; private setInternalCompilerOptionsForEmittingJsFiles(); /** * Get the errors that dont have any file name associated From d584f4d97bdce05e11f9347a671f6b464078d616 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 5 Feb 2018 13:24:08 -0800 Subject: [PATCH 10/20] Fix assertion: class reference location may be 'default' keyword instead of class name (#21630) * Fix assertion: class reference location may be 'default' keyword instead of class name * Update API baselines --- src/compiler/types.ts | 1 + src/services/findAllReferences.ts | 2 +- tests/baselines/reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + .../fourslash/findAllRefsExportDefaultClassConstructor.ts | 5 +++++ 5 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/findAllRefsExportDefaultClassConstructor.ts diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3f03c1431e5..ff13a447275 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2027,6 +2027,7 @@ namespace ts { export interface ClassDeclaration extends ClassLikeDeclarationBase, DeclarationStatement { kind: SyntaxKind.ClassDeclaration; + /** May be undefined in `export default class { ... }`. */ name?: Identifier; } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 6869e7331c3..07cd2c683a9 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -990,7 +990,7 @@ namespace ts.FindAllReferences.Core { const pusher = () => state.referenceAdder(search.symbol, search.location); if (isClassLike(referenceLocation.parent)) { - Debug.assert(referenceLocation.parent.name === referenceLocation); + Debug.assert(referenceLocation.kind === SyntaxKind.DefaultKeyword || referenceLocation.parent.name === referenceLocation); // This is the class declaration containing the constructor. findOwnConstructorReferences(search.symbol, sourceFile, pusher()); } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index fcd9d04d06d..60c38f22243 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1266,6 +1266,7 @@ declare namespace ts { } interface ClassDeclaration extends ClassLikeDeclarationBase, DeclarationStatement { kind: SyntaxKind.ClassDeclaration; + /** May be undefined in `export default class { ... }`. */ name?: Identifier; } interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpression { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index f9a6bdd55e8..8014017d0c0 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1266,6 +1266,7 @@ declare namespace ts { } interface ClassDeclaration extends ClassLikeDeclarationBase, DeclarationStatement { kind: SyntaxKind.ClassDeclaration; + /** May be undefined in `export default class { ... }`. */ name?: Identifier; } interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpression { diff --git a/tests/cases/fourslash/findAllRefsExportDefaultClassConstructor.ts b/tests/cases/fourslash/findAllRefsExportDefaultClassConstructor.ts new file mode 100644 index 00000000000..4cd0ab1ce3d --- /dev/null +++ b/tests/cases/fourslash/findAllRefsExportDefaultClassConstructor.ts @@ -0,0 +1,5 @@ +////export default class { +//// [|constructor|]() {} +////} + +verify.singleReferenceGroup("constructor default(): default"); From 0d3f2166e32f9e7260d307b49002962fc2245091 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Feb 2018 13:56:10 -0800 Subject: [PATCH 11/20] Automatic semicolon insertion before 'extends' in conditional type --- src/compiler/parser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5b8504eb6dc..3209f234f85 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2986,7 +2986,7 @@ namespace ts { return parseFunctionOrConstructorType(SyntaxKind.ConstructorType); } const type = parseUnionTypeOrHigher(); - if (!noConditionalTypes && parseOptional(SyntaxKind.ExtendsKeyword)) { + if (!noConditionalTypes && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { const node = createNode(SyntaxKind.ConditionalType, type.pos); node.checkType = type; // The type following 'extends' is not permitted to be another conditional type From 6cf640ed3bb3d5c3f23993c2375c8fa8b71c763f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Feb 2018 13:56:22 -0800 Subject: [PATCH 12/20] Add regression test --- tests/cases/compiler/conditionalTypesASI.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/cases/compiler/conditionalTypesASI.ts diff --git a/tests/cases/compiler/conditionalTypesASI.ts b/tests/cases/compiler/conditionalTypesASI.ts new file mode 100644 index 00000000000..44d6d816851 --- /dev/null +++ b/tests/cases/compiler/conditionalTypesASI.ts @@ -0,0 +1,8 @@ +// @declaration: true + +// Repro from #21637 + +interface JSONSchema4 { + a?: number + extends?: string | string[] +} From d4d54d61a658d8d5dc3c56950d8bec3ca3d5a66b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Feb 2018 13:56:29 -0800 Subject: [PATCH 13/20] Accept new baselines --- .../baselines/reference/conditionalTypesASI.js | 18 ++++++++++++++++++ .../reference/conditionalTypesASI.symbols | 13 +++++++++++++ .../reference/conditionalTypesASI.types | 13 +++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 tests/baselines/reference/conditionalTypesASI.js create mode 100644 tests/baselines/reference/conditionalTypesASI.symbols create mode 100644 tests/baselines/reference/conditionalTypesASI.types diff --git a/tests/baselines/reference/conditionalTypesASI.js b/tests/baselines/reference/conditionalTypesASI.js new file mode 100644 index 00000000000..0399d30f153 --- /dev/null +++ b/tests/baselines/reference/conditionalTypesASI.js @@ -0,0 +1,18 @@ +//// [conditionalTypesASI.ts] +// Repro from #21637 + +interface JSONSchema4 { + a?: number + extends?: string | string[] +} + + +//// [conditionalTypesASI.js] +// Repro from #21637 + + +//// [conditionalTypesASI.d.ts] +interface JSONSchema4 { + a?: number; + extends?: string | string[]; +} diff --git a/tests/baselines/reference/conditionalTypesASI.symbols b/tests/baselines/reference/conditionalTypesASI.symbols new file mode 100644 index 00000000000..00480cba82b --- /dev/null +++ b/tests/baselines/reference/conditionalTypesASI.symbols @@ -0,0 +1,13 @@ +=== tests/cases/compiler/conditionalTypesASI.ts === +// Repro from #21637 + +interface JSONSchema4 { +>JSONSchema4 : Symbol(JSONSchema4, Decl(conditionalTypesASI.ts, 0, 0)) + + a?: number +>a : Symbol(JSONSchema4.a, Decl(conditionalTypesASI.ts, 2, 23)) + + extends?: string | string[] +>extends : Symbol(JSONSchema4.extends, Decl(conditionalTypesASI.ts, 3, 12)) +} + diff --git a/tests/baselines/reference/conditionalTypesASI.types b/tests/baselines/reference/conditionalTypesASI.types new file mode 100644 index 00000000000..b0ee4502cfc --- /dev/null +++ b/tests/baselines/reference/conditionalTypesASI.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/conditionalTypesASI.ts === +// Repro from #21637 + +interface JSONSchema4 { +>JSONSchema4 : JSONSchema4 + + a?: number +>a : number + + extends?: string | string[] +>extends : string | string[] +} + From 48c0af5d43da4adcb2ccc7da0390c68eb86c8bc1 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 5 Feb 2018 14:02:50 -0800 Subject: [PATCH 14/20] Support testing document highlights with "filesToSearch" (#21640) * Support testing document highlights with "filesToSearch" * Fix lint --- src/harness/fourslash.ts | 22 +++++++++++----------- src/services/services.ts | 2 +- tests/cases/fourslash/fourslash.ts | 4 +++- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 79dd86ccb09..4b9816f9fcb 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2819,7 +2819,7 @@ Actual: ${stringify(fullActual)}`); } } - private getDocumentHighlightsAtCurrentPosition(fileNamesToSearch: string[]) { + private getDocumentHighlightsAtCurrentPosition(fileNamesToSearch: ReadonlyArray) { const filesToSearch = fileNamesToSearch.map(name => ts.combinePaths(this.basePath, name)); return this.languageService.getDocumentHighlights(this.activeFile.fileName, this.currentCaretPosition, filesToSearch); } @@ -2843,9 +2843,8 @@ Actual: ${stringify(fullActual)}`); this.rangesByText().forEach(ranges => this.verifyRangesAreDocumentHighlights(ranges)); } - public verifyDocumentHighlightsOf(startRange: Range, ranges: Range[]) { - ts.Debug.assert(ts.contains(ranges, startRange)); - const fileNames = unique(ranges, range => range.fileName); + public verifyDocumentHighlightsOf(startRange: Range, ranges: Range[], options: FourSlashInterface.VerifyDocumentHighlightsOptions | undefined) { + const fileNames = options && options.filesToSearch || unique(ranges, range => range.fileName); this.goToRangeStart(startRange); this.verifyDocumentHighlights(ranges, fileNames); } @@ -2868,7 +2867,7 @@ Actual: ${stringify(fullActual)}`); } } - private verifyDocumentHighlights(expectedRanges: Range[], fileNames: string[] = [this.activeFile.fileName]) { + private verifyDocumentHighlights(expectedRanges: Range[], fileNames: ReadonlyArray = [this.activeFile.fileName]) { const documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNames) || []; for (const dh of documentHighlights) { @@ -2880,10 +2879,7 @@ Actual: ${stringify(fullActual)}`); for (const fileName of fileNames) { const expectedRangesInFile = expectedRanges.filter(r => r.fileName === fileName); const highlights = ts.find(documentHighlights, dh => dh.fileName === fileName); - if (!highlights) { - this.raiseError(`verifyDocumentHighlights failed - found no highlights in ${fileName}`); - } - const spansInFile = highlights.highlightSpans.sort((s1, s2) => s1.textSpan.start - s2.textSpan.start); + const spansInFile = highlights ? highlights.highlightSpans.sort((s1, s2) => s1.textSpan.start - s2.textSpan.start) : []; if (expectedRangesInFile.length !== spansInFile.length) { this.raiseError(`verifyDocumentHighlights failed - In ${fileName}, expected ${expectedRangesInFile.length} highlights, got ${spansInFile.length}`); @@ -4272,8 +4268,8 @@ namespace FourSlashInterface { this.state.verifyRangesWithSameTextAreDocumentHighlights(); } - public documentHighlightsOf(startRange: FourSlash.Range, ranges: FourSlash.Range[]) { - this.state.verifyDocumentHighlightsOf(startRange, ranges); + public documentHighlightsOf(startRange: FourSlash.Range, ranges: FourSlash.Range[], options?: VerifyDocumentHighlightsOptions) { + this.state.verifyDocumentHighlightsOf(startRange, ranges, options); } public noDocumentHighlights(startRange: FourSlash.Range) { @@ -4622,6 +4618,10 @@ namespace FourSlashInterface { insertText?: string; } + export interface VerifyDocumentHighlightsOptions { + filesToSearch?: ReadonlyArray; + } + export interface NewContentOptions { // Exactly one of these should be defined. newFileContent?: string; diff --git a/src/services/services.ts b/src/services/services.ts index ddb869624a8..422248465c9 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1582,7 +1582,7 @@ namespace ts { function getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] { synchronizeHostData(); - const sourceFilesToSearch = map(filesToSearch, f => program.getSourceFile(f)); + const sourceFilesToSearch = map(filesToSearch, f => Debug.assertDefined(program.getSourceFile(f))); const sourceFile = getValidSourceFile(fileName); return DocumentHighlights.getDocumentHighlights(program, cancellationToken, sourceFile, position, sourceFilesToSearch); } diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 774c2191fd0..1d7cb0810f4 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -310,7 +310,9 @@ declare namespace FourSlashInterface { occurrencesAtPositionCount(expectedCount: number): void; rangesAreDocumentHighlights(ranges?: Range[]): void; rangesWithSameTextAreDocumentHighlights(): void; - documentHighlightsOf(startRange: Range, ranges: Range[]): void; + documentHighlightsOf(startRange: Range, ranges: Range[], options?: { + filesToSearch?: ReadonlyArray; + }): void; completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string, tags?: ts.JSDocTagInfo[]): void; /** * This method *requires* a contiguous, complete, and ordered stream of classifications for a file. From c7b86e824f7342f5c8013ec1fe3db4abcff1e134 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 5 Feb 2018 14:22:03 -0800 Subject: [PATCH 15/20] EntityNameExpression doesn't need to include ParenthesizedExpression (#21588) --- src/compiler/checker.ts | 20 +++++-------------- src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 2 +- .../reference/api/tsserverlibrary.d.ts | 2 +- tests/baselines/reference/api/typescript.d.ts | 2 +- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fbb752aec78..fcae225a432 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1983,8 +1983,7 @@ namespace ts { if (name.kind === SyntaxKind.QualifiedName) { left = (name).left; } - else if (name.kind === SyntaxKind.PropertyAccessExpression && - (name.expression.kind === SyntaxKind.ParenthesizedExpression || isEntityNameExpression(name.expression))) { + else if (name.kind === SyntaxKind.PropertyAccessExpression) { left = name.expression; } else { @@ -2013,15 +2012,6 @@ namespace ts { return undefined; } } - else if (name.kind === SyntaxKind.ParenthesizedExpression) { - // If the expression in parenthesizedExpression is not an entity-name (e.g. it is a call expression), it won't be able to successfully resolve the name. - // This is the case when we are trying to do any language service operation in heritage clauses. - // By return undefined, the getSymbolOfEntityNameOrPropertyAccessExpression will attempt to checkPropertyAccessExpression to resolve symbol. - // i.e class C extends foo()./*do language service operation here*/B {} - return isEntityNameExpression(name.expression) ? - resolveEntityName(name.expression as EntityNameOrEntityNameExpression, meaning, ignoreErrors, dontResolveAlias, location) : - undefined; - } else { Debug.assertNever(name, "Unknown entity name kind."); } @@ -24477,8 +24467,8 @@ namespace ts { } } - if (entityName.parent.kind === SyntaxKind.ExportAssignment && isEntityNameExpression(entityName)) { - return resolveEntityName(entityName, + if (entityName.parent.kind === SyntaxKind.ExportAssignment && isEntityNameExpression(entityName)) { + return resolveEntityName(entityName, /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); } @@ -24493,7 +24483,7 @@ namespace ts { entityName = entityName.parent; } - if (isHeritageClauseElementIdentifier(entityName)) { + if (isHeritageClauseElementIdentifier(entityName)) { let meaning = SymbolFlags.None; // In an interface or class, we're definitely interested in a type. if (entityName.parent.kind === SyntaxKind.ExpressionWithTypeArguments) { @@ -24509,7 +24499,7 @@ namespace ts { } meaning |= SymbolFlags.Alias; - const entityNameSymbol = resolveEntityName(entityName, meaning); + const entityNameSymbol = isEntityNameExpression(entityName) ? resolveEntityName(entityName, meaning) : undefined; if (entityNameSymbol) { return entityNameSymbol; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ff13a447275..5a31abb5e6c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1638,7 +1638,7 @@ namespace ts { multiLine?: boolean; } - export type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression | ParenthesizedExpression; + export type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression; export type EntityNameOrEntityNameExpression = EntityName | EntityNameExpression; export interface PropertyAccessExpression extends MemberExpression, NamedDeclaration { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0e1d3be1b98..388ce814cc3 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3286,7 +3286,7 @@ namespace ts { && isClassLike(node.parent.parent); } - export function isEntityNameExpression(node: Expression): node is EntityNameExpression { + export function isEntityNameExpression(node: Node): node is EntityNameExpression { return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression && isEntityNameExpression((node).expression); } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 60c38f22243..d6081ff72ac 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -983,7 +983,7 @@ declare namespace ts { interface ObjectLiteralExpression extends ObjectLiteralExpressionBase { kind: SyntaxKind.ObjectLiteralExpression; } - type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression | ParenthesizedExpression; + type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression; type EntityNameOrEntityNameExpression = EntityName | EntityNameExpression; interface PropertyAccessExpression extends MemberExpression, NamedDeclaration { kind: SyntaxKind.PropertyAccessExpression; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 8014017d0c0..07445d1a168 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -983,7 +983,7 @@ declare namespace ts { interface ObjectLiteralExpression extends ObjectLiteralExpressionBase { kind: SyntaxKind.ObjectLiteralExpression; } - type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression | ParenthesizedExpression; + type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression; type EntityNameOrEntityNameExpression = EntityName | EntityNameExpression; interface PropertyAccessExpression extends MemberExpression, NamedDeclaration { kind: SyntaxKind.PropertyAccessExpression; From 8f8fec433eb1e47aa9d0ac7459ee06edfb3ef326 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 5 Feb 2018 14:48:50 -0800 Subject: [PATCH 16/20] Rename switch `--emitDeclarationsOnly` to `--emitDeclarationOnly` (#21651) * Rename `--emitDeclarationsOnly` to `--renameDeclarationOnly` * Rename test files --- src/compiler/commandLineParser.ts | 2 +- src/compiler/emitter.ts | 2 +- src/compiler/program.ts | 8 ++++---- src/compiler/types.ts | 2 +- src/harness/harness.ts | 6 +++--- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 +- tests/baselines/reference/api/typescript.d.ts | 2 +- ...eclarationsOnly.js => declFileEmitDeclarationOnly.js} | 0 ...sOnly.symbols => declFileEmitDeclarationOnly.symbols} | 0 ...tionsOnly.types => declFileEmitDeclarationOnly.types} | 0 .../declFileEmitDeclarationOnlyError1.errors.txt | 7 +++++++ ...symbols => declFileEmitDeclarationOnlyError1.symbols} | 0 ...or1.types => declFileEmitDeclarationOnlyError1.types} | 0 .../declFileEmitDeclarationOnlyError2.errors.txt | 9 +++++++++ ...symbols => declFileEmitDeclarationOnlyError2.symbols} | 0 ...or2.types => declFileEmitDeclarationOnlyError2.types} | 0 .../declFileEmitDeclarationsOnlyError1.errors.txt | 7 ------- .../declFileEmitDeclarationsOnlyError2.errors.txt | 9 --------- ...eclarationsOnly.ts => declFileEmitDeclarationOnly.ts} | 2 +- ...nlyError1.ts => declFileEmitDeclarationOnlyError1.ts} | 2 +- ...nlyError2.ts => declFileEmitDeclarationOnlyError2.ts} | 2 +- 21 files changed, 31 insertions(+), 31 deletions(-) rename tests/baselines/reference/{declFileEmitDeclarationsOnly.js => declFileEmitDeclarationOnly.js} (100%) rename tests/baselines/reference/{declFileEmitDeclarationsOnly.symbols => declFileEmitDeclarationOnly.symbols} (100%) rename tests/baselines/reference/{declFileEmitDeclarationsOnly.types => declFileEmitDeclarationOnly.types} (100%) create mode 100644 tests/baselines/reference/declFileEmitDeclarationOnlyError1.errors.txt rename tests/baselines/reference/{declFileEmitDeclarationsOnlyError1.symbols => declFileEmitDeclarationOnlyError1.symbols} (100%) rename tests/baselines/reference/{declFileEmitDeclarationsOnlyError1.types => declFileEmitDeclarationOnlyError1.types} (100%) create mode 100644 tests/baselines/reference/declFileEmitDeclarationOnlyError2.errors.txt rename tests/baselines/reference/{declFileEmitDeclarationsOnlyError2.symbols => declFileEmitDeclarationOnlyError2.symbols} (100%) rename tests/baselines/reference/{declFileEmitDeclarationsOnlyError2.types => declFileEmitDeclarationOnlyError2.types} (100%) delete mode 100644 tests/baselines/reference/declFileEmitDeclarationsOnlyError1.errors.txt delete mode 100644 tests/baselines/reference/declFileEmitDeclarationsOnlyError2.errors.txt rename tests/cases/compiler/{declFileEmitDeclarationsOnly.ts => declFileEmitDeclarationOnly.ts} (87%) rename tests/cases/compiler/{declFileEmitDeclarationsOnlyError1.ts => declFileEmitDeclarationOnlyError1.ts} (58%) rename tests/cases/compiler/{declFileEmitDeclarationsOnlyError2.ts => declFileEmitDeclarationOnlyError2.ts} (65%) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index b6921253f57..825f2c632e7 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -187,7 +187,7 @@ namespace ts { description: Diagnostics.Generates_corresponding_d_ts_file, }, { - name: "emitDeclarationsOnly", + name: "emitDeclarationOnly", type: "boolean", category: Diagnostics.Advanced_Options, description: Diagnostics.Only_emit_d_ts_declaration_files, diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 58aa2c7a563..3c9866b3536 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -135,7 +135,7 @@ namespace ts { function emitSourceFileOrBundle({ jsFilePath, sourceMapFilePath, declarationFilePath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle) { // Make sure not to write js file and source map file if any of them cannot be written - if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit && !compilerOptions.emitDeclarationsOnly) { + if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit && !compilerOptions.emitDeclarationOnly) { if (!emitOnlyDtsFiles) { printSourceFileOrBundle(jsFilePath, sourceMapFilePath, sourceFileOrBundle); } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 24a1a0eb106..1f2a3bfcd5d 100755 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -2201,13 +2201,13 @@ namespace ts { programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "checkJs", "allowJs")); } - if (options.emitDeclarationsOnly) { + if (options.emitDeclarationOnly) { if (!options.declaration) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDeclarationsOnly", "declarations"); + createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDeclarationOnly", "declarations"); } if (options.noEmit) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "emitDeclarationsOnly", "noEmit"); + createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "emitDeclarationOnly", "noEmit"); } } @@ -2233,7 +2233,7 @@ namespace ts { const emitHost = getEmitHost(); const emitFilesSeen = createMap(); forEachEmittedFile(emitHost, (emitFileNames) => { - if (!options.emitDeclarationsOnly) { + if (!options.emitDeclarationOnly) { verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen); } verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5a31abb5e6c..e235c953ac5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4025,7 +4025,7 @@ namespace ts { /** configFile is set as non enumerable property so as to avoid checking of json source files */ /* @internal */ readonly configFile?: JsonSourceFile; declaration?: boolean; - emitDeclarationsOnly?: boolean; + emitDeclarationOnly?: boolean; declarationDir?: string; /* @internal */ diagnostics?: boolean; /* @internal */ extendedDiagnostics?: boolean; diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 3e6f4cfa163..53f8133b8e5 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1255,9 +1255,9 @@ namespace Harness { if (result.errors.length === 0) { if (options.declaration) { - if (options.emitDeclarationsOnly) { + if (options.emitDeclarationOnly) { if (result.files.length > 0 || result.declFilesCode.length === 0) { - throw new Error("Only declaration files should be generated when emitDeclarationsOnly:true"); + throw new Error("Only declaration files should be generated when emitDeclarationOnly:true"); } } else if (result.declFilesCode.length !== result.files.length) { @@ -1664,7 +1664,7 @@ namespace Harness { } export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, tsConfigFiles: Harness.Compiler.TestFile[], toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) { - if (!options.noEmit && !options.emitDeclarationsOnly && result.files.length === 0 && result.errors.length === 0) { + if (!options.noEmit && !options.emitDeclarationOnly && result.files.length === 0 && result.errors.length === 0) { throw new Error("Expected at least one js file to be emitted or at least one error to be created."); } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index d6081ff72ac..4f31edd8884 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2301,7 +2301,7 @@ declare namespace ts { charset?: string; checkJs?: boolean; declaration?: boolean; - emitDeclarationsOnly?: boolean; + emitDeclarationOnly?: boolean; declarationDir?: string; disableSizeLimit?: boolean; downlevelIteration?: boolean; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 07445d1a168..82025291379 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2301,7 +2301,7 @@ declare namespace ts { charset?: string; checkJs?: boolean; declaration?: boolean; - emitDeclarationsOnly?: boolean; + emitDeclarationOnly?: boolean; declarationDir?: string; disableSizeLimit?: boolean; downlevelIteration?: boolean; diff --git a/tests/baselines/reference/declFileEmitDeclarationsOnly.js b/tests/baselines/reference/declFileEmitDeclarationOnly.js similarity index 100% rename from tests/baselines/reference/declFileEmitDeclarationsOnly.js rename to tests/baselines/reference/declFileEmitDeclarationOnly.js diff --git a/tests/baselines/reference/declFileEmitDeclarationsOnly.symbols b/tests/baselines/reference/declFileEmitDeclarationOnly.symbols similarity index 100% rename from tests/baselines/reference/declFileEmitDeclarationsOnly.symbols rename to tests/baselines/reference/declFileEmitDeclarationOnly.symbols diff --git a/tests/baselines/reference/declFileEmitDeclarationsOnly.types b/tests/baselines/reference/declFileEmitDeclarationOnly.types similarity index 100% rename from tests/baselines/reference/declFileEmitDeclarationsOnly.types rename to tests/baselines/reference/declFileEmitDeclarationOnly.types diff --git a/tests/baselines/reference/declFileEmitDeclarationOnlyError1.errors.txt b/tests/baselines/reference/declFileEmitDeclarationOnlyError1.errors.txt new file mode 100644 index 00000000000..9c4455f773a --- /dev/null +++ b/tests/baselines/reference/declFileEmitDeclarationOnlyError1.errors.txt @@ -0,0 +1,7 @@ +error TS5052: Option 'emitDeclarationOnly' cannot be specified without specifying option 'declarations'. + + +!!! error TS5052: Option 'emitDeclarationOnly' cannot be specified without specifying option 'declarations'. +==== tests/cases/compiler/hello.ts (0 errors) ==== + var hello = "yo!"; + \ No newline at end of file diff --git a/tests/baselines/reference/declFileEmitDeclarationsOnlyError1.symbols b/tests/baselines/reference/declFileEmitDeclarationOnlyError1.symbols similarity index 100% rename from tests/baselines/reference/declFileEmitDeclarationsOnlyError1.symbols rename to tests/baselines/reference/declFileEmitDeclarationOnlyError1.symbols diff --git a/tests/baselines/reference/declFileEmitDeclarationsOnlyError1.types b/tests/baselines/reference/declFileEmitDeclarationOnlyError1.types similarity index 100% rename from tests/baselines/reference/declFileEmitDeclarationsOnlyError1.types rename to tests/baselines/reference/declFileEmitDeclarationOnlyError1.types diff --git a/tests/baselines/reference/declFileEmitDeclarationOnlyError2.errors.txt b/tests/baselines/reference/declFileEmitDeclarationOnlyError2.errors.txt new file mode 100644 index 00000000000..03db2ae409b --- /dev/null +++ b/tests/baselines/reference/declFileEmitDeclarationOnlyError2.errors.txt @@ -0,0 +1,9 @@ +error TS5052: Option 'emitDeclarationOnly' cannot be specified without specifying option 'declarations'. +error TS5053: Option 'emitDeclarationOnly' cannot be specified with option 'noEmit'. + + +!!! error TS5052: Option 'emitDeclarationOnly' cannot be specified without specifying option 'declarations'. +!!! error TS5053: Option 'emitDeclarationOnly' cannot be specified with option 'noEmit'. +==== tests/cases/compiler/hello.ts (0 errors) ==== + var hello = "yo!"; + \ No newline at end of file diff --git a/tests/baselines/reference/declFileEmitDeclarationsOnlyError2.symbols b/tests/baselines/reference/declFileEmitDeclarationOnlyError2.symbols similarity index 100% rename from tests/baselines/reference/declFileEmitDeclarationsOnlyError2.symbols rename to tests/baselines/reference/declFileEmitDeclarationOnlyError2.symbols diff --git a/tests/baselines/reference/declFileEmitDeclarationsOnlyError2.types b/tests/baselines/reference/declFileEmitDeclarationOnlyError2.types similarity index 100% rename from tests/baselines/reference/declFileEmitDeclarationsOnlyError2.types rename to tests/baselines/reference/declFileEmitDeclarationOnlyError2.types diff --git a/tests/baselines/reference/declFileEmitDeclarationsOnlyError1.errors.txt b/tests/baselines/reference/declFileEmitDeclarationsOnlyError1.errors.txt deleted file mode 100644 index 88a154cc508..00000000000 --- a/tests/baselines/reference/declFileEmitDeclarationsOnlyError1.errors.txt +++ /dev/null @@ -1,7 +0,0 @@ -error TS5052: Option 'emitDeclarationsOnly' cannot be specified without specifying option 'declarations'. - - -!!! error TS5052: Option 'emitDeclarationsOnly' cannot be specified without specifying option 'declarations'. -==== tests/cases/compiler/hello.ts (0 errors) ==== - var hello = "yo!"; - \ No newline at end of file diff --git a/tests/baselines/reference/declFileEmitDeclarationsOnlyError2.errors.txt b/tests/baselines/reference/declFileEmitDeclarationsOnlyError2.errors.txt deleted file mode 100644 index 7c067d83ba2..00000000000 --- a/tests/baselines/reference/declFileEmitDeclarationsOnlyError2.errors.txt +++ /dev/null @@ -1,9 +0,0 @@ -error TS5052: Option 'emitDeclarationsOnly' cannot be specified without specifying option 'declarations'. -error TS5053: Option 'emitDeclarationsOnly' cannot be specified with option 'noEmit'. - - -!!! error TS5052: Option 'emitDeclarationsOnly' cannot be specified without specifying option 'declarations'. -!!! error TS5053: Option 'emitDeclarationsOnly' cannot be specified with option 'noEmit'. -==== tests/cases/compiler/hello.ts (0 errors) ==== - var hello = "yo!"; - \ No newline at end of file diff --git a/tests/cases/compiler/declFileEmitDeclarationsOnly.ts b/tests/cases/compiler/declFileEmitDeclarationOnly.ts similarity index 87% rename from tests/cases/compiler/declFileEmitDeclarationsOnly.ts rename to tests/cases/compiler/declFileEmitDeclarationOnly.ts index e55496e4ca3..bc6f88ea364 100644 --- a/tests/cases/compiler/declFileEmitDeclarationsOnly.ts +++ b/tests/cases/compiler/declFileEmitDeclarationOnly.ts @@ -1,5 +1,5 @@ // @declaration: true -// @emitDeclarationsOnly: true +// @emitDeclarationOnly: true // @filename: helloworld.ts const Log = { diff --git a/tests/cases/compiler/declFileEmitDeclarationsOnlyError1.ts b/tests/cases/compiler/declFileEmitDeclarationOnlyError1.ts similarity index 58% rename from tests/cases/compiler/declFileEmitDeclarationsOnlyError1.ts rename to tests/cases/compiler/declFileEmitDeclarationOnlyError1.ts index 477934a7b2a..c98edc2483b 100644 --- a/tests/cases/compiler/declFileEmitDeclarationsOnlyError1.ts +++ b/tests/cases/compiler/declFileEmitDeclarationOnlyError1.ts @@ -1,4 +1,4 @@ -// @emitDeclarationsOnly: true +// @emitDeclarationOnly: true // @filename: hello.ts var hello = "yo!"; diff --git a/tests/cases/compiler/declFileEmitDeclarationsOnlyError2.ts b/tests/cases/compiler/declFileEmitDeclarationOnlyError2.ts similarity index 65% rename from tests/cases/compiler/declFileEmitDeclarationsOnlyError2.ts rename to tests/cases/compiler/declFileEmitDeclarationOnlyError2.ts index 994a6a5dbd8..ea782402a6f 100644 --- a/tests/cases/compiler/declFileEmitDeclarationsOnlyError2.ts +++ b/tests/cases/compiler/declFileEmitDeclarationOnlyError2.ts @@ -1,5 +1,5 @@ // @noEmit: true -// @emitDeclarationsOnly: true +// @emitDeclarationOnly: true // @filename: hello.ts var hello = "yo!"; From b803a268a3aa7c587b9a7491529191e49d07f620 Mon Sep 17 00:00:00 2001 From: csigs Date: Mon, 5 Feb 2018 23:11:03 +0000 Subject: [PATCH 17/20] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 9b7661ee541..3de4abb5ce7 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -8753,6 +8753,15 @@ + + + + + + + + + From 17554ff285338ba906ea1f8796c334a0a2f5fa84 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 5 Feb 2018 16:33:39 -0800 Subject: [PATCH 18/20] Fix JSX contextual types to not eagerly become apparent, use 2-pass inference for JSX (#21383) * Fix JSX contextual types to not eagerly become apparent * Apply changes from code review, unify common code * Fix jsx children contextual typing * Light code review feedback * Use fillMissingTypeArguments * Accept nonliteral jsx child type * Add test for the fillMissingTypeArguments case --- src/compiler/checker.ts | 351 +++++++++++------- src/compiler/types.ts | 1 + .../reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + .../checkJsxChildrenProperty2.errors.txt | 20 +- ...xGenericTagHasCorrectInferences.errors.txt | 27 ++ .../checkJsxGenericTagHasCorrectInferences.js | 23 ++ ...kJsxGenericTagHasCorrectInferences.symbols | 74 ++++ ...eckJsxGenericTagHasCorrectInferences.types | 91 +++++ ...xChildrenGenericContextualTypes.errors.txt | 68 ++++ .../jsxChildrenGenericContextualTypes.js | 38 ++ .../jsxChildrenGenericContextualTypes.symbols | 119 ++++++ .../jsxChildrenGenericContextualTypes.types | 165 ++++++++ .../reference/jsxElementClassTooManyParams.js | 27 ++ .../jsxElementClassTooManyParams.symbols | 58 +++ .../jsxElementClassTooManyParams.types | 61 +++ .../jsxChildrenGenericContextualTypes.tsx | 24 ++ .../compiler/jsxElementClassTooManyParams.tsx | 18 + ...checkJsxGenericTagHasCorrectInferences.tsx | 18 + 19 files changed, 1033 insertions(+), 152 deletions(-) create mode 100644 tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt create mode 100644 tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.js create mode 100644 tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.symbols create mode 100644 tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.types create mode 100644 tests/baselines/reference/jsxChildrenGenericContextualTypes.errors.txt create mode 100644 tests/baselines/reference/jsxChildrenGenericContextualTypes.js create mode 100644 tests/baselines/reference/jsxChildrenGenericContextualTypes.symbols create mode 100644 tests/baselines/reference/jsxChildrenGenericContextualTypes.types create mode 100644 tests/baselines/reference/jsxElementClassTooManyParams.js create mode 100644 tests/baselines/reference/jsxElementClassTooManyParams.symbols create mode 100644 tests/baselines/reference/jsxElementClassTooManyParams.types create mode 100644 tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx create mode 100644 tests/cases/compiler/jsxElementClassTooManyParams.tsx create mode 100644 tests/cases/conformance/jsx/checkJsxGenericTagHasCorrectInferences.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fcae225a432..365e09050b5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14196,56 +14196,35 @@ namespace ts { return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined; } + function getContextualTypeForChildJsxExpression(node: JsxElement) { + const attributesType = getApparentTypeOfContextualType(node.openingElement.tagName); + // JSX expression is in children of JSX Element, we will look for an "children" atttribute (we get the name from JSX.ElementAttributesProperty) + const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(); + return attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "" ? getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName) : undefined; + } + function getContextualTypeForJsxExpression(node: JsxExpression): Type { - // JSX expression can appear in two position : JSX Element's children or JSX attribute - const jsxAttributes = isJsxAttributeLike(node.parent) ? - node.parent.parent : - isJsxElement(node.parent) ? - node.parent.openingElement.attributes : - undefined; // node.parent is JsxFragment with no attributes - - if (!jsxAttributes) { - return undefined; // don't check children of a fragment - } - - // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type - // which is a type of the parameter of the signature we are trying out. - // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName - const attributesType = getContextualType(jsxAttributes); - - if (!attributesType || isTypeAny(attributesType)) { - return undefined; - } - - if (isJsxAttribute(node.parent)) { - // JSX expression is in JSX attribute - return getTypeOfPropertyOfContextualType(attributesType, node.parent.name.escapedText); - } - else if (node.parent.kind === SyntaxKind.JsxElement) { - // JSX expression is in children of JSX Element, we will look for an "children" atttribute (we get the name from JSX.ElementAttributesProperty) - const jsxChildrenPropertyName = getJsxElementChildrenPropertyname(); - return jsxChildrenPropertyName && jsxChildrenPropertyName !== "" ? getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName) : anyType; - } - else { - // JSX expression is in JSX spread attribute - return attributesType; - } + const exprParent = node.parent; + return isJsxAttributeLike(exprParent) + ? getContextualType(node) + : isJsxElement(exprParent) + ? getContextualTypeForChildJsxExpression(exprParent) + : undefined; } function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute) { // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type // which is a type of the parameter of the signature we are trying out. // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName - const attributesType = getContextualType(attribute.parent); - if (isJsxAttribute(attribute)) { + const attributesType = getApparentTypeOfContextualType(attribute.parent); if (!attributesType || isTypeAny(attributesType)) { return undefined; } return getTypeOfPropertyOfContextualType(attributesType, attribute.name.escapedText); } else { - return attributesType; + return getContextualType(attribute.parent); } } @@ -14353,7 +14332,7 @@ namespace ts { return getContextualTypeForJsxAttribute(parent); case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxSelfClosingElement: - return getAttributesTypeFromJsxOpeningLikeElement(parent); + return getContextualJsxElementAttributesType(parent); } return undefined; } @@ -14363,6 +14342,145 @@ namespace ts { return node ? node.contextualMapper : identityMapper; } + function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement) { + if (isJsxIntrinsicIdentifier(node.tagName)) { + return getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node); + } + const valueType = checkExpression(node.tagName); + if (isTypeAny(valueType)) { + // Short-circuit if the class tag is using an element type 'any' + return anyType; + } + + const isJs = isInJavaScriptFile(node); + return mapType(valueType, isJs ? getJsxSignaturesParameterTypesJs : getJsxSignaturesParameterTypes); + } + + function getJsxSignaturesParameterTypes(valueType: Type) { + return getJsxSignaturesParameterTypesInternal(valueType, /*isJs*/ false); + } + + function getJsxSignaturesParameterTypesJs(valueType: Type) { + return getJsxSignaturesParameterTypesInternal(valueType, /*isJs*/ true); + } + + function getJsxSignaturesParameterTypesInternal(valueType: Type, isJs: boolean) { + // If the elemType is a string type, we have to return anyType to prevent an error downstream as we will try to find construct or call signature of the type + if (valueType.flags & TypeFlags.String) { + return anyType; + } + else if (valueType.flags & TypeFlags.StringLiteral) { + // If the elemType is a stringLiteral type, we can then provide a check to make sure that the string literal type is one of the Jsx intrinsic element type + // For example: + // var CustomTag: "h1" = "h1"; + // Hello World + const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements); + if (intrinsicElementsType !== unknownType) { + const stringLiteralTypeName = (valueType).value; + const intrinsicProp = getPropertyOfType(intrinsicElementsType, escapeLeadingUnderscores(stringLiteralTypeName)); + if (intrinsicProp) { + return getTypeOfSymbol(intrinsicProp); + } + const indexSignatureType = getIndexTypeOfType(intrinsicElementsType, IndexKind.String); + if (indexSignatureType) { + return indexSignatureType; + } + } + return anyType; + } + + // Resolve the signatures, preferring constructor + let signatures = getSignaturesOfType(valueType, SignatureKind.Construct); + let ctor = true; + if (signatures.length === 0) { + // No construct signatures, try call signatures + signatures = getSignaturesOfType(valueType, SignatureKind.Call); + ctor = false; + if (signatures.length === 0) { + // We found no signatures at all, which is an error + return unknownType; + } + } + + return getUnionType(map(signatures, ctor ? isJs ? getJsxPropsTypeFromConstructSignatureJs : getJsxPropsTypeFromConstructSignature : getJsxPropsTypeFromCallSignature), UnionReduction.None); + } + + function getJsxPropsTypeFromCallSignature(sig: Signature) { + let propsType = getTypeOfFirstParameterOfSignature(sig); + const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes); + if (intrinsicAttribs !== unknownType) { + propsType = intersectTypes(intrinsicAttribs, propsType); + } + return propsType; + } + + function getJsxPropsTypeFromClassType(hostClassType: Type, isJs: boolean) { + if (isTypeAny(hostClassType)) { + return hostClassType; + } + + const propsName = getJsxElementPropertiesName(); + if (propsName === undefined) { + // There is no type ElementAttributesProperty, return 'any' + return anyType; + } + else if (propsName === "") { + // If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead + return hostClassType; + } + else { + const attributesType = getTypeOfPropertyOfType(hostClassType, propsName); + + if (!attributesType) { + // There is no property named 'props' on this instance type + return emptyObjectType; + } + else if (isTypeAny(attributesType)) { + // Props is of type 'any' or unknown + return attributesType; + } + else { + // Normal case -- add in IntrinsicClassElements and IntrinsicElements + let apparentAttributesType = attributesType; + const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes); + if (intrinsicClassAttribs !== unknownType) { + const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol); + apparentAttributesType = intersectTypes( + typeParams + ? createTypeReference(intrinsicClassAttribs, fillMissingTypeArguments([hostClassType], typeParams, getMinTypeArgumentCount(typeParams), isJs)) + : intrinsicClassAttribs, + apparentAttributesType + ); + } + + const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes); + if (intrinsicAttribs !== unknownType) { + apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType); + } + + return apparentAttributesType; + } + } + } + + function getJsxPropsTypeFromConstructSignatureJs(sig: Signature) { + return getJsxPropsTypeFromConstructSignatureInternal(sig, /*isJs*/ true); + } + + function getJsxPropsTypeFromConstructSignature(sig: Signature) { + return getJsxPropsTypeFromConstructSignatureInternal(sig, /*isJs*/ false); + } + + function getJsxPropsTypeFromConstructSignatureInternal(sig: Signature, isJs: boolean) { + const hostClassType = getReturnTypeOfSignature(sig); + if (hostClassType) { + return getJsxPropsTypeFromClassType(hostClassType, isJs); + } + return getJsxPropsTypeFromCallSignature(sig); + } + + + // If the given type is an object or union type with a single signature, and if that signature has at // least as many parameters as the given function, return the signature. Otherwise return undefined. function getContextualCallSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature { @@ -14887,7 +15005,7 @@ namespace ts { let hasSpreadAnyType = false; let typeToIntersect: Type; let explicitlySpecifyChildrenAttribute = false; - const jsxChildrenPropertyName = getJsxElementChildrenPropertyname(); + const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(); for (const attributeDecl of attributes.properties) { const member = attributeDecl.symbol; @@ -14988,7 +15106,7 @@ namespace ts { } } else { - childrenTypes.push(checkExpression(child, checkMode)); + childrenTypes.push(checkExpressionForMutableLocation(child, checkMode)); } } return childrenTypes; @@ -15056,7 +15174,7 @@ namespace ts { * element is not a class element, or the class element type cannot be determined, returns 'undefined'. * For example, in the element , the element instance type is `MyClass` (not `typeof MyClass`). */ - function getJsxElementInstanceType(node: JsxOpeningLikeElement, valueType: Type, sourceAttributesType: Type | undefined) { + function getJsxElementInstanceType(node: JsxOpeningLikeElement, valueType: Type) { Debug.assert(!(valueType.flags & TypeFlags.Union)); if (isTypeAny(valueType)) { // Short-circuit if the class tag is using an element type 'any' @@ -15075,27 +15193,21 @@ namespace ts { } } - if (sourceAttributesType) { - // Instantiate in context of source type - const instantiatedSignatures = []; - for (const signature of signatures) { - if (signature.typeParameters) { - const isJavascript = isInJavaScriptFile(node); - const inferenceContext = createInferenceContext(signature, /*flags*/ isJavascript ? InferenceFlags.AnyDefault : 0); - const typeArguments = inferJsxTypeArguments(signature, sourceAttributesType, inferenceContext); - instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments, isJavascript)); - } - else { - instantiatedSignatures.push(signature); - } + // Instantiate in context of source type + const instantiatedSignatures = []; + for (const signature of signatures) { + if (signature.typeParameters) { + const isJavascript = isInJavaScriptFile(node); + const inferenceContext = createInferenceContext(signature, /*flags*/ isJavascript ? InferenceFlags.AnyDefault : InferenceFlags.None); + const typeArguments = inferJsxTypeArguments(signature, node, inferenceContext); + instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments, isJavascript)); } + else { + instantiatedSignatures.push(signature); + } + } - return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype); - } - else { - // Do not instantiate if no source type is provided - type parameters and their constraints will be used by contextual typing - return getUnionType(map(signatures, getReturnTypeOfSignature), UnionReduction.Subtype); - } + return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype); } /** @@ -15146,7 +15258,7 @@ namespace ts { return _jsxElementPropertiesName; } - function getJsxElementChildrenPropertyname(): __String { + function getJsxElementChildrenPropertyName(): __String { if (!_hasComputedJsxElementChildrenPropertyName) { _hasComputedJsxElementChildrenPropertyName = true; _jsxElementChildrenPropertyName = getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer); @@ -15281,14 +15393,13 @@ namespace ts { */ function resolveCustomJsxElementAttributesType(openingLikeElement: JsxOpeningLikeElement, shouldIncludeAllStatelessAttributesType: boolean, - sourceAttributesType: Type | undefined, elementType: Type, elementClassType?: Type): Type { if (elementType.flags & TypeFlags.Union) { const types = (elementType as UnionType).types; return getUnionType(types.map(type => { - return resolveCustomJsxElementAttributesType(openingLikeElement, shouldIncludeAllStatelessAttributesType, sourceAttributesType, type, elementClassType); + return resolveCustomJsxElementAttributesType(openingLikeElement, shouldIncludeAllStatelessAttributesType, type, elementClassType); }), UnionReduction.Subtype); } @@ -15319,7 +15430,7 @@ namespace ts { } // Get the element instance type (the result of newing or invoking this tag) - const elemInstanceType = getJsxElementInstanceType(openingLikeElement, elementType, sourceAttributesType); + const elemInstanceType = getJsxElementInstanceType(openingLikeElement, elementType); // If we should include all stateless attributes type, then get all attributes type from all stateless function signature. // Otherwise get only attributes type from the signature picked by choose-overload logic. @@ -15332,58 +15443,11 @@ namespace ts { } // Issue an error if this return type isn't assignable to JSX.ElementClass - if (elementClassType && sourceAttributesType) { + if (elementClassType) { checkTypeRelatedTo(elemInstanceType, elementClassType, assignableRelation, openingLikeElement, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements); } - if (isTypeAny(elemInstanceType)) { - return elemInstanceType; - } - - const propsName = getJsxElementPropertiesName(); - if (propsName === undefined) { - // There is no type ElementAttributesProperty, return 'any' - return anyType; - } - else if (propsName === "") { - // If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead - return elemInstanceType; - } - else { - const attributesType = getTypeOfPropertyOfType(elemInstanceType, propsName); - - if (!attributesType) { - // There is no property named 'props' on this instance type - return emptyObjectType; - } - else if (isTypeAny(attributesType) || (attributesType === unknownType)) { - // Props is of type 'any' or unknown - return attributesType; - } - else { - // Normal case -- add in IntrinsicClassElements and IntrinsicElements - let apparentAttributesType = attributesType; - const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes); - if (intrinsicClassAttribs !== unknownType) { - const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol); - if (typeParams) { - if (typeParams.length === 1) { - apparentAttributesType = intersectTypes(createTypeReference(intrinsicClassAttribs, [elemInstanceType]), apparentAttributesType); - } - } - else { - apparentAttributesType = intersectTypes(attributesType, intrinsicClassAttribs); - } - } - - const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes); - if (intrinsicAttribs !== unknownType) { - apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType); - } - - return apparentAttributesType; - } - } + return getJsxPropsTypeFromClassType(elemInstanceType, isInJavaScriptFile(openingLikeElement)); } /** @@ -15415,20 +15479,8 @@ namespace ts { * @param node a custom JSX opening-like element * @param shouldIncludeAllStatelessAttributesType a boolean value used by language service to get all possible attributes type from an overload stateless function component */ - function getCustomJsxElementAttributesType(node: JsxOpeningLikeElement, sourceAttributesType: Type, shouldIncludeAllStatelessAttributesType: boolean): Type { - if (!sourceAttributesType) { - // This ensures we cache non-inference uses of this calculation (ie, contextual types or services) - const links = getNodeLinks(node); - const linkLocation = shouldIncludeAllStatelessAttributesType ? "resolvedJsxElementAllAttributesType" : "resolvedJsxElementAttributesType"; - if (!links[linkLocation]) { - const elemClassType = getJsxGlobalElementClassType(); - return links[linkLocation] = resolveCustomJsxElementAttributesType(node, shouldIncludeAllStatelessAttributesType, sourceAttributesType, checkExpression(node.tagName), elemClassType); - } - return links[linkLocation]; - } - else { - return resolveCustomJsxElementAttributesType(node, shouldIncludeAllStatelessAttributesType, sourceAttributesType, checkExpression(node.tagName), getJsxGlobalElementClassType()); - } + function getCustomJsxElementAttributesType(node: JsxOpeningLikeElement, shouldIncludeAllStatelessAttributesType: boolean): Type { + return resolveCustomJsxElementAttributesType(node, shouldIncludeAllStatelessAttributesType, checkExpression(node.tagName), getJsxGlobalElementClassType()); } /** @@ -15443,7 +15495,7 @@ namespace ts { else { // Because in language service, the given JSX opening-like element may be incomplete and therefore, // we can't resolve to exact signature if the element is a stateless function component so the best thing to do is return all attributes type from all overloads. - return getCustomJsxElementAttributesType(node, /*sourceAttributesType*/ undefined, /*shouldIncludeAllStatelessAttributesType*/ true); + return getCustomJsxElementAttributesType(node, /*shouldIncludeAllStatelessAttributesType*/ true); } } @@ -15457,7 +15509,7 @@ namespace ts { return getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node); } else { - return getCustomJsxElementAttributesType(node, /*sourceAttributesType*/ undefined, /*shouldIncludeAllStatelessAttributesType*/ false); + return getCustomJsxElementAttributesType(node, /*shouldIncludeAllStatelessAttributesType*/ false); } } @@ -15597,16 +15649,16 @@ namespace ts { // 3. Check if the two are assignable to each other + // targetAttributesType is a type of an attribute from resolving tagName of an opening-like JSX element. + const targetAttributesType = isJsxIntrinsicIdentifier(openingLikeElement.tagName) ? + getIntrinsicAttributesTypeFromJsxOpeningLikeElement(openingLikeElement) : + getCustomJsxElementAttributesType(openingLikeElement, /*shouldIncludeAllStatelessAttributesType*/ false); + // sourceAttributesType is a type of an attributes properties. // i.e
// attr1 and attr2 are treated as JSXAttributes attached in the JsxOpeningLikeElement as "attributes". const sourceAttributesType = createJsxAttributesTypeFromAttributesProperty(openingLikeElement, checkMode); - // targetAttributesType is a type of an attributes from resolving tagName of an opening-like JSX element. - const targetAttributesType = isJsxIntrinsicIdentifier(openingLikeElement.tagName) ? - getIntrinsicAttributesTypeFromJsxOpeningLikeElement(openingLikeElement) : - getCustomJsxElementAttributesType(openingLikeElement, sourceAttributesType, /*shouldIncludeAllStatelessAttributesType*/ false); - // If the targetAttributesType is an emptyObjectType, indicating that there is no property named 'props' on this instance type. // but there exists a sourceAttributesType, we need to explicitly give an error as normal assignability check allow excess properties and will pass. if (targetAttributesType === emptyObjectType && (isTypeAny(sourceAttributesType) || getPropertiesOfType(sourceAttributesType).length > 0)) { @@ -16482,9 +16534,16 @@ namespace ts { return getSignatureInstantiation(signature, getInferredTypes(context), isInJavaScriptFile(contextualSignature.declaration)); } - function inferJsxTypeArguments(signature: Signature, sourceAttributesType: Type, context: InferenceContext): Type[] { + function inferJsxTypeArguments(signature: Signature, node: JsxOpeningLikeElement, context: InferenceContext): Type[] { + // Skip context sensitive pass + const skipContextParamType = getTypeAtPosition(signature, 0); + const checkAttrTypeSkipContextSensitive = checkExpressionWithContextualType(node.attributes, skipContextParamType, identityMapper); + inferTypes(context.inferences, checkAttrTypeSkipContextSensitive, skipContextParamType); + + // Standard pass const paramType = getTypeAtPosition(signature, 0); - inferTypes(context.inferences, sourceAttributesType, paramType); + const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, context); + inferTypes(context.inferences, checkAttrType, paramType); return getInferredTypes(context); } @@ -17230,7 +17289,7 @@ namespace ts { let candidate: Signature; const inferenceContext = originalCandidate.typeParameters ? - createInferenceContext(originalCandidate, /*flags*/ isInJavaScriptFile(node) ? InferenceFlags.AnyDefault : 0) : + createInferenceContext(originalCandidate, /*flags*/ isInJavaScriptFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None) : undefined; while (true) { @@ -19216,16 +19275,24 @@ namespace ts { return stringType; } + function getContextNode(node: Expression): Node { + if (node.kind === SyntaxKind.JsxAttributes) { + return node.parent.parent; // Needs to be the root JsxElement, so it encompasses the attributes _and_ the children (which are essentially part of the attributes) + } + return node; + } + function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper: TypeMapper | undefined): Type { - const saveContextualType = node.contextualType; - const saveContextualMapper = node.contextualMapper; - node.contextualType = contextualType; - node.contextualMapper = contextualMapper; + const context = getContextNode(node); + const saveContextualType = context.contextualType; + const saveContextualMapper = context.contextualMapper; + context.contextualType = contextualType; + context.contextualMapper = contextualMapper; const checkMode = contextualMapper === identityMapper ? CheckMode.SkipContextSensitive : contextualMapper ? CheckMode.Inferential : CheckMode.Contextual; const result = checkExpression(node, checkMode); - node.contextualType = saveContextualType; - node.contextualMapper = saveContextualMapper; + context.contextualType = saveContextualType; + context.contextualMapper = saveContextualMapper; return result; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e235c953ac5..9e7296f9be1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3904,6 +3904,7 @@ namespace ts { } export const enum InferenceFlags { + None = 0, // No special inference behaviors InferUnionTypes = 1 << 0, // Infer union types for disjoint candidates (otherwise unknownType) NoDefault = 1 << 1, // Infer unknownType for no inferences (otherwise anyType or emptyObjectType) AnyDefault = 1 << 2, // Infer anyType for no inferences (otherwise emptyObjectType) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 4f31edd8884..5e413f16d87 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2227,6 +2227,7 @@ declare namespace ts { isFixed: boolean; } enum InferenceFlags { + None = 0, InferUnionTypes = 1, NoDefault = 2, AnyDefault = 4, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 82025291379..3a1fa35146c 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2227,6 +2227,7 @@ declare namespace ts { isFixed: boolean; } enum InferenceFlags { + None = 0, InferUnionTypes = 1, NoDefault = 2, AnyDefault = 4, diff --git a/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt index 0de31bf04b9..e2a6cf3a685 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt +++ b/tests/baselines/reference/checkJsxChildrenProperty2.errors.txt @@ -8,12 +8,12 @@ tests/cases/conformance/jsx/file.tsx(31,11): error TS2322: Type '{ children: (El Type '(Element | ((name: string) => Element))[]' is not assignable to type 'string | Element'. Type '(Element | ((name: string) => Element))[]' is not assignable to type 'Element'. Property 'type' is missing in type '(Element | ((name: string) => Element))[]'. -tests/cases/conformance/jsx/file.tsx(37,11): error TS2322: Type '{ children: (Element | 1000000)[]; a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & Prop'. - Type '{ children: (Element | 1000000)[]; a: number; b: string; }' is not assignable to type 'Prop'. +tests/cases/conformance/jsx/file.tsx(37,11): error TS2322: Type '{ children: (number | Element)[]; a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & Prop'. + Type '{ children: (number | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'. Types of property 'children' are incompatible. - Type '(Element | 1000000)[]' is not assignable to type 'string | Element'. - Type '(Element | 1000000)[]' is not assignable to type 'Element'. - Property 'type' is missing in type '(Element | 1000000)[]'. + Type '(number | Element)[]' is not assignable to type 'string | Element'. + Type '(number | Element)[]' is not assignable to type 'Element'. + Property 'type' is missing in type '(number | Element)[]'. tests/cases/conformance/jsx/file.tsx(43,11): error TS2322: Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & Prop'. Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'. Types of property 'children' are incompatible. @@ -80,12 +80,12 @@ tests/cases/conformance/jsx/file.tsx(49,11): error TS2322: Type '{ children: Ele let k3 = ~~~~~~~~~~~~~ -!!! error TS2322: Type '{ children: (Element | 1000000)[]; a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & Prop'. -!!! error TS2322: Type '{ children: (Element | 1000000)[]; a: number; b: string; }' is not assignable to type 'Prop'. +!!! error TS2322: Type '{ children: (number | Element)[]; a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & Prop'. +!!! error TS2322: Type '{ children: (number | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'. !!! error TS2322: Types of property 'children' are incompatible. -!!! error TS2322: Type '(Element | 1000000)[]' is not assignable to type 'string | Element'. -!!! error TS2322: Type '(Element | 1000000)[]' is not assignable to type 'Element'. -!!! error TS2322: Property 'type' is missing in type '(Element | 1000000)[]'. +!!! error TS2322: Type '(number | Element)[]' is not assignable to type 'string | Element'. +!!! error TS2322: Type '(number | Element)[]' is not assignable to type 'Element'. +!!! error TS2322: Property 'type' is missing in type '(number | Element)[]'.
My Div
{1000000}
; diff --git a/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt new file mode 100644 index 00000000000..a8c89c6751f --- /dev/null +++ b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt @@ -0,0 +1,27 @@ +tests/cases/conformance/jsx/file.tsx(13,27): error TS2322: Type '{ initialValues: { x: string; }; nextValues: (a: { x: string; }) => string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { initialValues: { x: string; }; nextValues: {}; } & BaseProps<{ x: string; }> & { children?: ReactNode; }'. + Type '{ initialValues: { x: string; }; nextValues: (a: { x: string; }) => string; }' is not assignable to type 'BaseProps<{ x: string; }>'. + Types of property 'nextValues' are incompatible. + Type '(a: { x: string; }) => string' is not assignable to type '(cur: { x: string; }) => { x: string; }'. + Type 'string' is not assignable to type '{ x: string; }'. + + +==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== + import * as React from "react"; + interface BaseProps { + initialValues: T; + nextValues: (cur: T) => T; + } + declare class GenericComponent extends React.Component, {}> { + iv: Values; + } + + let a = a} />; // No error + let b = a} />; // No error - Values should be reinstantiated with `number` (since `object` is a default, not a constraint) + let c = ({ x: a.x })} />; // No Error + let d = a.x} />; // Error - `string` is not assignable to `{x: string}` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ initialValues: { x: string; }; nextValues: (a: { x: string; }) => string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { initialValues: { x: string; }; nextValues: {}; } & BaseProps<{ x: string; }> & { children?: ReactNode; }'. +!!! error TS2322: Type '{ initialValues: { x: string; }; nextValues: (a: { x: string; }) => string; }' is not assignable to type 'BaseProps<{ x: string; }>'. +!!! error TS2322: Types of property 'nextValues' are incompatible. +!!! error TS2322: Type '(a: { x: string; }) => string' is not assignable to type '(cur: { x: string; }) => { x: string; }'. +!!! error TS2322: Type 'string' is not assignable to type '{ x: string; }'. \ No newline at end of file diff --git a/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.js b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.js new file mode 100644 index 00000000000..fe0e910f7cb --- /dev/null +++ b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.js @@ -0,0 +1,23 @@ +//// [file.tsx] +import * as React from "react"; +interface BaseProps { + initialValues: T; + nextValues: (cur: T) => T; +} +declare class GenericComponent extends React.Component, {}> { + iv: Values; +} + +let a = a} />; // No error +let b = a} />; // No error - Values should be reinstantiated with `number` (since `object` is a default, not a constraint) +let c = ({ x: a.x })} />; // No Error +let d = a.x} />; // Error - `string` is not assignable to `{x: string}` + +//// [file.jsx] +"use strict"; +exports.__esModule = true; +var React = require("react"); +var a = ; // No error +var b = ; // No error - Values should be reinstantiated with `number` (since `object` is a default, not a constraint) +var c = ; // No Error +var d = ; // Error - `string` is not assignable to `{x: string}` diff --git a/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.symbols b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.symbols new file mode 100644 index 00000000000..314dc8a5384 --- /dev/null +++ b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.symbols @@ -0,0 +1,74 @@ +=== tests/cases/conformance/jsx/file.tsx === +import * as React from "react"; +>React : Symbol(React, Decl(file.tsx, 0, 6)) + +interface BaseProps { +>BaseProps : Symbol(BaseProps, Decl(file.tsx, 0, 31)) +>T : Symbol(T, Decl(file.tsx, 1, 20)) + + initialValues: T; +>initialValues : Symbol(BaseProps.initialValues, Decl(file.tsx, 1, 24)) +>T : Symbol(T, Decl(file.tsx, 1, 20)) + + nextValues: (cur: T) => T; +>nextValues : Symbol(BaseProps.nextValues, Decl(file.tsx, 2, 19)) +>cur : Symbol(cur, Decl(file.tsx, 3, 15)) +>T : Symbol(T, Decl(file.tsx, 1, 20)) +>T : Symbol(T, Decl(file.tsx, 1, 20)) +} +declare class GenericComponent extends React.Component, {}> { +>GenericComponent : Symbol(GenericComponent, Decl(file.tsx, 4, 1)) +>Props : Symbol(Props, Decl(file.tsx, 5, 31)) +>Values : Symbol(Values, Decl(file.tsx, 5, 42)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) +>React : Symbol(React, Decl(file.tsx, 0, 6)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) +>Props : Symbol(Props, Decl(file.tsx, 5, 31)) +>BaseProps : Symbol(BaseProps, Decl(file.tsx, 0, 31)) +>Values : Symbol(Values, Decl(file.tsx, 5, 42)) + + iv: Values; +>iv : Symbol(GenericComponent.iv, Decl(file.tsx, 5, 116)) +>Values : Symbol(Values, Decl(file.tsx, 5, 42)) +} + +let a = a} />; // No error +>a : Symbol(a, Decl(file.tsx, 9, 3)) +>GenericComponent : Symbol(GenericComponent, Decl(file.tsx, 4, 1)) +>initialValues : Symbol(initialValues, Decl(file.tsx, 9, 25)) +>x : Symbol(x, Decl(file.tsx, 9, 42)) +>nextValues : Symbol(nextValues, Decl(file.tsx, 9, 52)) +>a : Symbol(a, Decl(file.tsx, 9, 65)) +>a : Symbol(a, Decl(file.tsx, 9, 65)) + +let b = a} />; // No error - Values should be reinstantiated with `number` (since `object` is a default, not a constraint) +>b : Symbol(b, Decl(file.tsx, 10, 3)) +>GenericComponent : Symbol(GenericComponent, Decl(file.tsx, 4, 1)) +>initialValues : Symbol(initialValues, Decl(file.tsx, 10, 25)) +>nextValues : Symbol(nextValues, Decl(file.tsx, 10, 44)) +>a : Symbol(a, Decl(file.tsx, 10, 57)) +>a : Symbol(a, Decl(file.tsx, 10, 57)) + +let c = ({ x: a.x })} />; // No Error +>c : Symbol(c, Decl(file.tsx, 11, 3)) +>GenericComponent : Symbol(GenericComponent, Decl(file.tsx, 4, 1)) +>initialValues : Symbol(initialValues, Decl(file.tsx, 11, 25)) +>x : Symbol(x, Decl(file.tsx, 11, 42)) +>nextValues : Symbol(nextValues, Decl(file.tsx, 11, 52)) +>a : Symbol(a, Decl(file.tsx, 11, 65)) +>x : Symbol(x, Decl(file.tsx, 11, 72)) +>a.x : Symbol(x, Decl(file.tsx, 11, 42)) +>a : Symbol(a, Decl(file.tsx, 11, 65)) +>x : Symbol(x, Decl(file.tsx, 11, 42)) + +let d = a.x} />; // Error - `string` is not assignable to `{x: string}` +>d : Symbol(d, Decl(file.tsx, 12, 3)) +>GenericComponent : Symbol(GenericComponent, Decl(file.tsx, 4, 1)) +>initialValues : Symbol(initialValues, Decl(file.tsx, 12, 25)) +>x : Symbol(x, Decl(file.tsx, 12, 42)) +>nextValues : Symbol(nextValues, Decl(file.tsx, 12, 52)) +>a : Symbol(a, Decl(file.tsx, 12, 65)) +>a.x : Symbol(x, Decl(file.tsx, 12, 42)) +>a : Symbol(a, Decl(file.tsx, 12, 65)) +>x : Symbol(x, Decl(file.tsx, 12, 42)) + diff --git a/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.types b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.types new file mode 100644 index 00000000000..1ced8516253 --- /dev/null +++ b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.types @@ -0,0 +1,91 @@ +=== tests/cases/conformance/jsx/file.tsx === +import * as React from "react"; +>React : typeof React + +interface BaseProps { +>BaseProps : BaseProps +>T : T + + initialValues: T; +>initialValues : T +>T : T + + nextValues: (cur: T) => T; +>nextValues : (cur: T) => T +>cur : T +>T : T +>T : T +} +declare class GenericComponent extends React.Component, {}> { +>GenericComponent : GenericComponent +>Props : Props +>Values : Values +>React.Component : React.Component, {}> +>React : typeof React +>Component : typeof React.Component +>Props : Props +>BaseProps : BaseProps +>Values : Values + + iv: Values; +>iv : Values +>Values : Values +} + +let a = a} />; // No error +>a : JSX.Element +> a} /> : JSX.Element +>GenericComponent : typeof GenericComponent +>initialValues : { x: string; } +>{ x: "y" } : { x: string; } +>x : string +>"y" : "y" +>nextValues : (a: { x: string; }) => { x: string; } +>a => a : (a: { x: string; }) => { x: string; } +>a : { x: string; } +>a : { x: string; } + +let b = a} />; // No error - Values should be reinstantiated with `number` (since `object` is a default, not a constraint) +>b : JSX.Element +> a} /> : JSX.Element +>GenericComponent : typeof GenericComponent +>initialValues : number +>12 : 12 +>nextValues : (a: number) => number +>a => a : (a: number) => number +>a : number +>a : number + +let c = ({ x: a.x })} />; // No Error +>c : JSX.Element +> ({ x: a.x })} /> : JSX.Element +>GenericComponent : typeof GenericComponent +>initialValues : { x: string; } +>{ x: "y" } : { x: string; } +>x : string +>"y" : "y" +>nextValues : (a: { x: string; }) => { x: string; } +>a => ({ x: a.x }) : (a: { x: string; }) => { x: string; } +>a : { x: string; } +>({ x: a.x }) : { x: string; } +>{ x: a.x } : { x: string; } +>x : string +>a.x : string +>a : { x: string; } +>x : string + +let d = a.x} />; // Error - `string` is not assignable to `{x: string}` +>d : JSX.Element +> a.x} /> : JSX.Element +>GenericComponent : typeof GenericComponent +>initialValues : { x: string; } +>{ x: "y" } : { x: string; } +>x : string +>"y" : "y" +>nextValues : (a: { x: string; }) => string +>a => a.x : (a: { x: string; }) => string +>a : { x: string; } +>a.x : string +>a : { x: string; } +>x : string + diff --git a/tests/baselines/reference/jsxChildrenGenericContextualTypes.errors.txt b/tests/baselines/reference/jsxChildrenGenericContextualTypes.errors.txt new file mode 100644 index 00000000000..9f5778c8638 --- /dev/null +++ b/tests/baselines/reference/jsxChildrenGenericContextualTypes.errors.txt @@ -0,0 +1,68 @@ +tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(20,22): error TS2322: Type '{ prop: "x"; children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'. + Type '{ prop: "x"; children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; }' is not assignable to type 'LitProps<"x">'. + Types of property 'children' are incompatible. + Type '(p: IntrinsicAttributes & LitProps<"x">) => "y"' is not assignable to type '(x: LitProps<"x">) => "x"'. + Type '"y"' is not assignable to type '"x"'. +tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(21,27): error TS2322: Type '{ children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x" | "y">'. + Type '{ children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'LitProps<"x" | "y">'. + Types of property 'children' are incompatible. + Type '(p: IntrinsicAttributes & LitProps<"x">) => "y"' is not assignable to type '(x: LitProps<"x" | "y">) => "x" | "y"'. + Types of parameters 'p' and 'x' are incompatible. + Type 'LitProps<"x" | "y">' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'. + Type 'LitProps<"x" | "y">' is not assignable to type 'LitProps<"x">'. + Types of property 'prop' are incompatible. + Type '"x" | "y"' is not assignable to type '"x"'. + Type '"y"' is not assignable to type '"x"'. +tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx(22,29): error TS2322: Type '{ children: () => number; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'. + Type '{ children: () => number; prop: "x"; }' is not assignable to type 'LitProps<"x">'. + Types of property 'children' are incompatible. + Type '() => number' is not assignable to type '(x: LitProps<"x">) => "x"'. + Type 'number' is not assignable to type '"x"'. + + +==== tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx (3 errors) ==== + namespace JSX { + export interface Element {} + export interface ElementAttributesProperty { props: {}; } + export interface ElementChildrenAttribute { children: {}; } + export interface IntrinsicAttributes {} + export interface IntrinsicElements { [key: string]: Element } + } + const Elem = (p: { prop: T, children: (t: T) => T }) =>
; + Elem({prop: {a: "x"}, children: i => ({a: "z"})}); + const q = ({a: "z"})} /> + const qq = {i => ({a: "z"})} + + interface LitProps { prop: T, children: (x: this) => T } + const ElemLit = (p: LitProps) =>
; + ElemLit({prop: "x", children: () => "x"}); + const j = "x"} /> + const jj = {() => "x"} + + // Should error + const arg = "y"} /> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ prop: "x"; children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'. +!!! error TS2322: Type '{ prop: "x"; children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; }' is not assignable to type 'LitProps<"x">'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type '(p: IntrinsicAttributes & LitProps<"x">) => "y"' is not assignable to type '(x: LitProps<"x">) => "x"'. +!!! error TS2322: Type '"y"' is not assignable to type '"x"'. + const argchild = {p => "y"} + ~~~~~~~~ +!!! error TS2322: Type '{ children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x" | "y">'. +!!! error TS2322: Type '{ children: (p: IntrinsicAttributes & LitProps<"x">) => "y"; prop: "x"; }' is not assignable to type 'LitProps<"x" | "y">'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type '(p: IntrinsicAttributes & LitProps<"x">) => "y"' is not assignable to type '(x: LitProps<"x" | "y">) => "x" | "y"'. +!!! error TS2322: Types of parameters 'p' and 'x' are incompatible. +!!! error TS2322: Type 'LitProps<"x" | "y">' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'. +!!! error TS2322: Type 'LitProps<"x" | "y">' is not assignable to type 'LitProps<"x">'. +!!! error TS2322: Types of property 'prop' are incompatible. +!!! error TS2322: Type '"x" | "y"' is not assignable to type '"x"'. +!!! error TS2322: Type '"y"' is not assignable to type '"x"'. + const mismatched = {() => 12} + ~~~~~~~~ +!!! error TS2322: Type '{ children: () => number; prop: "x"; }' is not assignable to type 'IntrinsicAttributes & LitProps<"x">'. +!!! error TS2322: Type '{ children: () => number; prop: "x"; }' is not assignable to type 'LitProps<"x">'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type '() => number' is not assignable to type '(x: LitProps<"x">) => "x"'. +!!! error TS2322: Type 'number' is not assignable to type '"x"'. \ No newline at end of file diff --git a/tests/baselines/reference/jsxChildrenGenericContextualTypes.js b/tests/baselines/reference/jsxChildrenGenericContextualTypes.js new file mode 100644 index 00000000000..cffa13be412 --- /dev/null +++ b/tests/baselines/reference/jsxChildrenGenericContextualTypes.js @@ -0,0 +1,38 @@ +//// [jsxChildrenGenericContextualTypes.tsx] +namespace JSX { + export interface Element {} + export interface ElementAttributesProperty { props: {}; } + export interface ElementChildrenAttribute { children: {}; } + export interface IntrinsicAttributes {} + export interface IntrinsicElements { [key: string]: Element } +} +const Elem = (p: { prop: T, children: (t: T) => T }) =>
; +Elem({prop: {a: "x"}, children: i => ({a: "z"})}); +const q = ({a: "z"})} /> +const qq = {i => ({a: "z"})} + +interface LitProps { prop: T, children: (x: this) => T } +const ElemLit = (p: LitProps) =>
; +ElemLit({prop: "x", children: () => "x"}); +const j = "x"} /> +const jj = {() => "x"} + +// Should error +const arg = "y"} /> +const argchild = {p => "y"} +const mismatched = {() => 12} + +//// [jsxChildrenGenericContextualTypes.jsx] +"use strict"; +var Elem = function (p) { return
; }; +Elem({ prop: { a: "x" }, children: function (i) { return ({ a: "z" }); } }); +var q = ; +var qq = {function (i) { return ({ a: "z" }); }}; +var ElemLit = function (p) { return
; }; +ElemLit({ prop: "x", children: function () { return "x"; } }); +var j = ; +var jj = {function () { return "x"; }}; +// Should error +var arg = ; +var argchild = {function (p) { return "y"; }}; +var mismatched = {function () { return 12; }}; diff --git a/tests/baselines/reference/jsxChildrenGenericContextualTypes.symbols b/tests/baselines/reference/jsxChildrenGenericContextualTypes.symbols new file mode 100644 index 00000000000..ce5535615ea --- /dev/null +++ b/tests/baselines/reference/jsxChildrenGenericContextualTypes.symbols @@ -0,0 +1,119 @@ +=== tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx === +namespace JSX { +>JSX : Symbol(JSX, Decl(jsxChildrenGenericContextualTypes.tsx, 0, 0)) + + export interface Element {} +>Element : Symbol(Element, Decl(jsxChildrenGenericContextualTypes.tsx, 0, 15)) + + export interface ElementAttributesProperty { props: {}; } +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(jsxChildrenGenericContextualTypes.tsx, 1, 31)) +>props : Symbol(ElementAttributesProperty.props, Decl(jsxChildrenGenericContextualTypes.tsx, 2, 48)) + + export interface ElementChildrenAttribute { children: {}; } +>ElementChildrenAttribute : Symbol(ElementChildrenAttribute, Decl(jsxChildrenGenericContextualTypes.tsx, 2, 61)) +>children : Symbol(ElementChildrenAttribute.children, Decl(jsxChildrenGenericContextualTypes.tsx, 3, 47)) + + export interface IntrinsicAttributes {} +>IntrinsicAttributes : Symbol(IntrinsicAttributes, Decl(jsxChildrenGenericContextualTypes.tsx, 3, 63)) + + export interface IntrinsicElements { [key: string]: Element } +>IntrinsicElements : Symbol(IntrinsicElements, Decl(jsxChildrenGenericContextualTypes.tsx, 4, 43)) +>key : Symbol(key, Decl(jsxChildrenGenericContextualTypes.tsx, 5, 42)) +>Element : Symbol(Element, Decl(jsxChildrenGenericContextualTypes.tsx, 0, 15)) +} +const Elem = (p: { prop: T, children: (t: T) => T }) =>
; +>Elem : Symbol(Elem, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 5)) +>T : Symbol(T, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 14)) +>U : Symbol(U, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 16)) +>p : Symbol(p, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 25)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 29)) +>T : Symbol(T, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 14)) +>children : Symbol(children, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 38)) +>t : Symbol(t, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 50)) +>T : Symbol(T, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 14)) +>T : Symbol(T, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 14)) +>div : Symbol(JSX.IntrinsicElements, Decl(jsxChildrenGenericContextualTypes.tsx, 4, 43)) +>div : Symbol(JSX.IntrinsicElements, Decl(jsxChildrenGenericContextualTypes.tsx, 4, 43)) + +Elem({prop: {a: "x"}, children: i => ({a: "z"})}); +>Elem : Symbol(Elem, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 5)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 8, 6)) +>a : Symbol(a, Decl(jsxChildrenGenericContextualTypes.tsx, 8, 13)) +>children : Symbol(children, Decl(jsxChildrenGenericContextualTypes.tsx, 8, 21)) +>i : Symbol(i, Decl(jsxChildrenGenericContextualTypes.tsx, 8, 31)) +>a : Symbol(a, Decl(jsxChildrenGenericContextualTypes.tsx, 8, 39)) + +const q = ({a: "z"})} /> +>q : Symbol(q, Decl(jsxChildrenGenericContextualTypes.tsx, 9, 5)) +>Elem : Symbol(Elem, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 5)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 9, 15)) +>a : Symbol(a, Decl(jsxChildrenGenericContextualTypes.tsx, 9, 23)) +>children : Symbol(children, Decl(jsxChildrenGenericContextualTypes.tsx, 9, 31)) +>i : Symbol(i, Decl(jsxChildrenGenericContextualTypes.tsx, 9, 42)) +>a : Symbol(a, Decl(jsxChildrenGenericContextualTypes.tsx, 9, 49)) + +const qq = {i => ({a: "z"})} +>qq : Symbol(qq, Decl(jsxChildrenGenericContextualTypes.tsx, 10, 5)) +>Elem : Symbol(Elem, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 5)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 10, 16)) +>a : Symbol(a, Decl(jsxChildrenGenericContextualTypes.tsx, 10, 24)) +>i : Symbol(i, Decl(jsxChildrenGenericContextualTypes.tsx, 10, 34)) +>a : Symbol(a, Decl(jsxChildrenGenericContextualTypes.tsx, 10, 41)) +>Elem : Symbol(Elem, Decl(jsxChildrenGenericContextualTypes.tsx, 7, 5)) + +interface LitProps { prop: T, children: (x: this) => T } +>LitProps : Symbol(LitProps, Decl(jsxChildrenGenericContextualTypes.tsx, 10, 57)) +>T : Symbol(T, Decl(jsxChildrenGenericContextualTypes.tsx, 12, 19)) +>prop : Symbol(LitProps.prop, Decl(jsxChildrenGenericContextualTypes.tsx, 12, 23)) +>T : Symbol(T, Decl(jsxChildrenGenericContextualTypes.tsx, 12, 19)) +>children : Symbol(LitProps.children, Decl(jsxChildrenGenericContextualTypes.tsx, 12, 32)) +>x : Symbol(x, Decl(jsxChildrenGenericContextualTypes.tsx, 12, 44)) +>T : Symbol(T, Decl(jsxChildrenGenericContextualTypes.tsx, 12, 19)) + +const ElemLit = (p: LitProps) =>
; +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) +>T : Symbol(T, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 17)) +>p : Symbol(p, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 35)) +>LitProps : Symbol(LitProps, Decl(jsxChildrenGenericContextualTypes.tsx, 10, 57)) +>T : Symbol(T, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 17)) +>div : Symbol(JSX.IntrinsicElements, Decl(jsxChildrenGenericContextualTypes.tsx, 4, 43)) +>div : Symbol(JSX.IntrinsicElements, Decl(jsxChildrenGenericContextualTypes.tsx, 4, 43)) + +ElemLit({prop: "x", children: () => "x"}); +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 14, 9)) +>children : Symbol(children, Decl(jsxChildrenGenericContextualTypes.tsx, 14, 19)) + +const j = "x"} /> +>j : Symbol(j, Decl(jsxChildrenGenericContextualTypes.tsx, 15, 5)) +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 15, 18)) +>children : Symbol(children, Decl(jsxChildrenGenericContextualTypes.tsx, 15, 27)) + +const jj = {() => "x"} +>jj : Symbol(jj, Decl(jsxChildrenGenericContextualTypes.tsx, 16, 5)) +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 16, 19)) +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) + +// Should error +const arg = "y"} /> +>arg : Symbol(arg, Decl(jsxChildrenGenericContextualTypes.tsx, 19, 5)) +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 19, 20)) +>children : Symbol(children, Decl(jsxChildrenGenericContextualTypes.tsx, 19, 29)) +>p : Symbol(p, Decl(jsxChildrenGenericContextualTypes.tsx, 19, 40)) + +const argchild = {p => "y"} +>argchild : Symbol(argchild, Decl(jsxChildrenGenericContextualTypes.tsx, 20, 5)) +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 20, 25)) +>p : Symbol(p, Decl(jsxChildrenGenericContextualTypes.tsx, 20, 36)) +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) + +const mismatched = {() => 12} +>mismatched : Symbol(mismatched, Decl(jsxChildrenGenericContextualTypes.tsx, 21, 5)) +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) +>prop : Symbol(prop, Decl(jsxChildrenGenericContextualTypes.tsx, 21, 27)) +>ElemLit : Symbol(ElemLit, Decl(jsxChildrenGenericContextualTypes.tsx, 13, 5)) + diff --git a/tests/baselines/reference/jsxChildrenGenericContextualTypes.types b/tests/baselines/reference/jsxChildrenGenericContextualTypes.types new file mode 100644 index 00000000000..0196248d39c --- /dev/null +++ b/tests/baselines/reference/jsxChildrenGenericContextualTypes.types @@ -0,0 +1,165 @@ +=== tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx === +namespace JSX { +>JSX : any + + export interface Element {} +>Element : Element + + export interface ElementAttributesProperty { props: {}; } +>ElementAttributesProperty : ElementAttributesProperty +>props : {} + + export interface ElementChildrenAttribute { children: {}; } +>ElementChildrenAttribute : ElementChildrenAttribute +>children : {} + + export interface IntrinsicAttributes {} +>IntrinsicAttributes : IntrinsicAttributes + + export interface IntrinsicElements { [key: string]: Element } +>IntrinsicElements : IntrinsicElements +>key : string +>Element : Element +} +const Elem = (p: { prop: T, children: (t: T) => T }) =>
; +>Elem : (p: { prop: T; children: (t: T) => T; }) => JSX.Element +>(p: { prop: T, children: (t: T) => T }) =>
: (p: { prop: T; children: (t: T) => T; }) => JSX.Element +>T : T +>U : U +>p : { prop: T; children: (t: T) => T; } +>prop : T +>T : T +>children : (t: T) => T +>t : T +>T : T +>T : T +>
: JSX.Element +>div : any +>div : any + +Elem({prop: {a: "x"}, children: i => ({a: "z"})}); +>Elem({prop: {a: "x"}, children: i => ({a: "z"})}) : JSX.Element +>Elem : (p: { prop: T; children: (t: T) => T; }) => JSX.Element +>{prop: {a: "x"}, children: i => ({a: "z"})} : { prop: { a: string; }; children: (i: { a: string; }) => { a: string; }; } +>prop : { a: string; } +>{a: "x"} : { a: string; } +>a : string +>"x" : "x" +>children : (i: { a: string; }) => { a: string; } +>i => ({a: "z"}) : (i: { a: string; }) => { a: string; } +>i : { a: string; } +>({a: "z"}) : { a: string; } +>{a: "z"} : { a: string; } +>a : string +>"z" : "z" + +const q = ({a: "z"})} /> +>q : JSX.Element +> ({a: "z"})} /> : JSX.Element +>Elem : (p: { prop: T; children: (t: T) => T; }) => JSX.Element +>prop : { a: string; } +>{a: "x"} : { a: string; } +>a : string +>"x" : "x" +>children : (i: { a: string; }) => { a: string; } +>i => ({a: "z"}) : (i: { a: string; }) => { a: string; } +>i : { a: string; } +>({a: "z"}) : { a: string; } +>{a: "z"} : { a: string; } +>a : string +>"z" : "z" + +const qq = {i => ({a: "z"})} +>qq : JSX.Element +>{i => ({a: "z"})} : JSX.Element +>Elem : (p: { prop: T; children: (t: T) => T; }) => JSX.Element +>prop : { a: string; } +>{a: "x"} : { a: string; } +>a : string +>"x" : "x" +>i => ({a: "z"}) : (i: { a: string; }) => { a: string; } +>i : { a: string; } +>({a: "z"}) : { a: string; } +>{a: "z"} : { a: string; } +>a : string +>"z" : "z" +>Elem : (p: { prop: T; children: (t: T) => T; }) => JSX.Element + +interface LitProps { prop: T, children: (x: this) => T } +>LitProps : LitProps +>T : T +>prop : T +>T : T +>children : (x: this) => T +>x : this +>T : T + +const ElemLit = (p: LitProps) =>
; +>ElemLit : (p: LitProps) => JSX.Element +>(p: LitProps) =>
: (p: LitProps) => JSX.Element +>T : T +>p : LitProps +>LitProps : LitProps +>T : T +>
: JSX.Element +>div : any +>div : any + +ElemLit({prop: "x", children: () => "x"}); +>ElemLit({prop: "x", children: () => "x"}) : JSX.Element +>ElemLit : (p: LitProps) => JSX.Element +>{prop: "x", children: () => "x"} : { prop: "x"; children: () => "x"; } +>prop : "x" +>"x" : "x" +>children : () => "x" +>() => "x" : () => "x" +>"x" : "x" + +const j = "x"} /> +>j : JSX.Element +> "x"} /> : JSX.Element +>ElemLit : (p: LitProps) => JSX.Element +>prop : "x" +>children : () => "x" +>() => "x" : () => "x" +>"x" : "x" + +const jj = {() => "x"} +>jj : JSX.Element +>{() => "x"} : JSX.Element +>ElemLit : (p: LitProps) => JSX.Element +>prop : "x" +>() => "x" : () => "x" +>"x" : "x" +>ElemLit : (p: LitProps) => JSX.Element + +// Should error +const arg = "y"} /> +>arg : JSX.Element +> "y"} /> : JSX.Element +>ElemLit : (p: LitProps) => JSX.Element +>prop : "x" +>children : (p: JSX.IntrinsicAttributes & LitProps<"x">) => "y" +>p => "y" : (p: JSX.IntrinsicAttributes & LitProps<"x">) => "y" +>p : JSX.IntrinsicAttributes & LitProps<"x"> +>"y" : "y" + +const argchild = {p => "y"} +>argchild : JSX.Element +>{p => "y"} : JSX.Element +>ElemLit : (p: LitProps) => JSX.Element +>prop : "x" +>p => "y" : (p: JSX.IntrinsicAttributes & LitProps<"x">) => "y" +>p : JSX.IntrinsicAttributes & LitProps<"x"> +>"y" : "y" +>ElemLit : (p: LitProps) => JSX.Element + +const mismatched = {() => 12} +>mismatched : JSX.Element +>{() => 12} : JSX.Element +>ElemLit : (p: LitProps) => JSX.Element +>prop : "x" +>() => 12 : () => number +>12 : 12 +>ElemLit : (p: LitProps) => JSX.Element + diff --git a/tests/baselines/reference/jsxElementClassTooManyParams.js b/tests/baselines/reference/jsxElementClassTooManyParams.js new file mode 100644 index 00000000000..e232f3392d7 --- /dev/null +++ b/tests/baselines/reference/jsxElementClassTooManyParams.js @@ -0,0 +1,27 @@ +//// [jsxElementClassTooManyParams.tsx] +namespace JSX { + export interface Element {} + export interface IntrinsicClassAttributes { + ref?: TClass; + item?: TOther; + } + export interface ElementClass extends Element {} + export interface ElementAttributesProperty { props: {}; } + export interface ElementChildrenAttribute { children: {}; } + export interface IntrinsicAttributes {} + export interface IntrinsicElements { [key: string]: Element } +} +class ElemClass implements JSX.ElementClass { + constructor(public props: T) {} +} +const elem = + +//// [jsxElementClassTooManyParams.jsx] +"use strict"; +var ElemClass = /** @class */ (function () { + function ElemClass(props) { + this.props = props; + } + return ElemClass; +}()); +var elem = ; diff --git a/tests/baselines/reference/jsxElementClassTooManyParams.symbols b/tests/baselines/reference/jsxElementClassTooManyParams.symbols new file mode 100644 index 00000000000..dbb0f408450 --- /dev/null +++ b/tests/baselines/reference/jsxElementClassTooManyParams.symbols @@ -0,0 +1,58 @@ +=== tests/cases/compiler/jsxElementClassTooManyParams.tsx === +namespace JSX { +>JSX : Symbol(JSX, Decl(jsxElementClassTooManyParams.tsx, 0, 0)) + + export interface Element {} +>Element : Symbol(Element, Decl(jsxElementClassTooManyParams.tsx, 0, 15)) + + export interface IntrinsicClassAttributes { +>IntrinsicClassAttributes : Symbol(IntrinsicClassAttributes, Decl(jsxElementClassTooManyParams.tsx, 1, 31)) +>TClass : Symbol(TClass, Decl(jsxElementClassTooManyParams.tsx, 2, 46)) +>TOther : Symbol(TOther, Decl(jsxElementClassTooManyParams.tsx, 2, 53)) + + ref?: TClass; +>ref : Symbol(IntrinsicClassAttributes.ref, Decl(jsxElementClassTooManyParams.tsx, 2, 69)) +>TClass : Symbol(TClass, Decl(jsxElementClassTooManyParams.tsx, 2, 46)) + + item?: TOther; +>item : Symbol(IntrinsicClassAttributes.item, Decl(jsxElementClassTooManyParams.tsx, 3, 21)) +>TOther : Symbol(TOther, Decl(jsxElementClassTooManyParams.tsx, 2, 53)) + } + export interface ElementClass extends Element {} +>ElementClass : Symbol(ElementClass, Decl(jsxElementClassTooManyParams.tsx, 5, 5)) +>Element : Symbol(Element, Decl(jsxElementClassTooManyParams.tsx, 0, 15)) + + export interface ElementAttributesProperty { props: {}; } +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(jsxElementClassTooManyParams.tsx, 6, 52)) +>props : Symbol(ElementAttributesProperty.props, Decl(jsxElementClassTooManyParams.tsx, 7, 48)) + + export interface ElementChildrenAttribute { children: {}; } +>ElementChildrenAttribute : Symbol(ElementChildrenAttribute, Decl(jsxElementClassTooManyParams.tsx, 7, 61)) +>children : Symbol(ElementChildrenAttribute.children, Decl(jsxElementClassTooManyParams.tsx, 8, 47)) + + export interface IntrinsicAttributes {} +>IntrinsicAttributes : Symbol(IntrinsicAttributes, Decl(jsxElementClassTooManyParams.tsx, 8, 63)) + + export interface IntrinsicElements { [key: string]: Element } +>IntrinsicElements : Symbol(IntrinsicElements, Decl(jsxElementClassTooManyParams.tsx, 9, 43)) +>key : Symbol(key, Decl(jsxElementClassTooManyParams.tsx, 10, 42)) +>Element : Symbol(Element, Decl(jsxElementClassTooManyParams.tsx, 0, 15)) +} +class ElemClass implements JSX.ElementClass { +>ElemClass : Symbol(ElemClass, Decl(jsxElementClassTooManyParams.tsx, 11, 1)) +>T : Symbol(T, Decl(jsxElementClassTooManyParams.tsx, 12, 16)) +>x : Symbol(x, Decl(jsxElementClassTooManyParams.tsx, 12, 27)) +>JSX.ElementClass : Symbol(JSX.ElementClass, Decl(jsxElementClassTooManyParams.tsx, 5, 5)) +>JSX : Symbol(JSX, Decl(jsxElementClassTooManyParams.tsx, 0, 0)) +>ElementClass : Symbol(JSX.ElementClass, Decl(jsxElementClassTooManyParams.tsx, 5, 5)) + + constructor(public props: T) {} +>props : Symbol(ElemClass.props, Decl(jsxElementClassTooManyParams.tsx, 13, 16)) +>T : Symbol(T, Decl(jsxElementClassTooManyParams.tsx, 12, 16)) +} +const elem = +>elem : Symbol(elem, Decl(jsxElementClassTooManyParams.tsx, 15, 5)) +>ElemClass : Symbol(ElemClass, Decl(jsxElementClassTooManyParams.tsx, 11, 1)) +>x : Symbol(x, Decl(jsxElementClassTooManyParams.tsx, 15, 23)) +>y : Symbol(y, Decl(jsxElementClassTooManyParams.tsx, 15, 30)) + diff --git a/tests/baselines/reference/jsxElementClassTooManyParams.types b/tests/baselines/reference/jsxElementClassTooManyParams.types new file mode 100644 index 00000000000..c0237c6a2dd --- /dev/null +++ b/tests/baselines/reference/jsxElementClassTooManyParams.types @@ -0,0 +1,61 @@ +=== tests/cases/compiler/jsxElementClassTooManyParams.tsx === +namespace JSX { +>JSX : any + + export interface Element {} +>Element : Element + + export interface IntrinsicClassAttributes { +>IntrinsicClassAttributes : IntrinsicClassAttributes +>TClass : TClass +>TOther : TOther + + ref?: TClass; +>ref : TClass | undefined +>TClass : TClass + + item?: TOther; +>item : TOther | undefined +>TOther : TOther + } + export interface ElementClass extends Element {} +>ElementClass : ElementClass +>Element : Element + + export interface ElementAttributesProperty { props: {}; } +>ElementAttributesProperty : ElementAttributesProperty +>props : {} + + export interface ElementChildrenAttribute { children: {}; } +>ElementChildrenAttribute : ElementChildrenAttribute +>children : {} + + export interface IntrinsicAttributes {} +>IntrinsicAttributes : IntrinsicAttributes + + export interface IntrinsicElements { [key: string]: Element } +>IntrinsicElements : IntrinsicElements +>key : string +>Element : Element +} +class ElemClass implements JSX.ElementClass { +>ElemClass : ElemClass +>T : T +>x : number +>JSX.ElementClass : any +>JSX : any +>ElementClass : JSX.ElementClass + + constructor(public props: T) {} +>props : T +>T : T +} +const elem = +>elem : JSX.Element +> : JSX.Element +>ElemClass : typeof ElemClass +>x : number +>12 : 12 +>y : number +>24 : 24 + diff --git a/tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx b/tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx new file mode 100644 index 00000000000..4b4259574bf --- /dev/null +++ b/tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx @@ -0,0 +1,24 @@ +// @strict: true +// @jsx: preserve +namespace JSX { + export interface Element {} + export interface ElementAttributesProperty { props: {}; } + export interface ElementChildrenAttribute { children: {}; } + export interface IntrinsicAttributes {} + export interface IntrinsicElements { [key: string]: Element } +} +const Elem = (p: { prop: T, children: (t: T) => T }) =>
; +Elem({prop: {a: "x"}, children: i => ({a: "z"})}); +const q = ({a: "z"})} /> +const qq = {i => ({a: "z"})} + +interface LitProps { prop: T, children: (x: this) => T } +const ElemLit = (p: LitProps) =>
; +ElemLit({prop: "x", children: () => "x"}); +const j = "x"} /> +const jj = {() => "x"} + +// Should error +const arg = "y"} /> +const argchild = {p => "y"} +const mismatched = {() => 12} \ No newline at end of file diff --git a/tests/cases/compiler/jsxElementClassTooManyParams.tsx b/tests/cases/compiler/jsxElementClassTooManyParams.tsx new file mode 100644 index 00000000000..25eedb348d8 --- /dev/null +++ b/tests/cases/compiler/jsxElementClassTooManyParams.tsx @@ -0,0 +1,18 @@ +// @strict: true +// @jsx: preserve +namespace JSX { + export interface Element {} + export interface IntrinsicClassAttributes { + ref?: TClass; + item?: TOther; + } + export interface ElementClass extends Element {} + export interface ElementAttributesProperty { props: {}; } + export interface ElementChildrenAttribute { children: {}; } + export interface IntrinsicAttributes {} + export interface IntrinsicElements { [key: string]: Element } +} +class ElemClass implements JSX.ElementClass { + constructor(public props: T) {} +} +const elem = \ No newline at end of file diff --git a/tests/cases/conformance/jsx/checkJsxGenericTagHasCorrectInferences.tsx b/tests/cases/conformance/jsx/checkJsxGenericTagHasCorrectInferences.tsx new file mode 100644 index 00000000000..04574d4e098 --- /dev/null +++ b/tests/cases/conformance/jsx/checkJsxGenericTagHasCorrectInferences.tsx @@ -0,0 +1,18 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @skipLibCheck: true +// @libFiles: react.d.ts,lib.d.ts +import * as React from "react"; +interface BaseProps { + initialValues: T; + nextValues: (cur: T) => T; +} +declare class GenericComponent extends React.Component, {}> { + iv: Values; +} + +let a = a} />; // No error +let b = a} />; // No error - Values should be reinstantiated with `number` (since `object` is a default, not a constraint) +let c = ({ x: a.x })} />; // No Error +let d = a.x} />; // Error - `string` is not assignable to `{x: string}` \ No newline at end of file From c33a14d66d0a452673ce77256e178bf84e875d2b Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 5 Feb 2018 17:17:37 -0800 Subject: [PATCH 19/20] We fixed formik :D (#21660) --- .../user/chrome-devtools-frontend.log | 4 +-- tests/baselines/reference/user/formik.log | 28 ------------------- tests/cases/user/formik/index.tsx | 2 +- 3 files changed, 3 insertions(+), 31 deletions(-) delete mode 100644 tests/baselines/reference/user/formik.log diff --git a/tests/baselines/reference/user/chrome-devtools-frontend.log b/tests/baselines/reference/user/chrome-devtools-frontend.log index 11b61110d8d..9d4a3b6b748 100644 --- a/tests/baselines/reference/user/chrome-devtools-frontend.log +++ b/tests/baselines/reference/user/chrome-devtools-frontend.log @@ -12,8 +12,8 @@ Standard output: ../../../../built/local/lib.dom.d.ts(9264,13): error TS2300: Duplicate identifier 'Request'. ../../../../built/local/lib.dom.d.ts(13522,11): error TS2300: Duplicate identifier 'Window'. ../../../../built/local/lib.dom.d.ts(13711,13): error TS2300: Duplicate identifier 'Window'. -../../../../built/local/lib.es5.d.ts(1321,11): error TS2300: Duplicate identifier 'ArrayLike'. -../../../../built/local/lib.es5.d.ts(1350,6): error TS2300: Duplicate identifier 'Record'. +../../../../built/local/lib.es5.d.ts(1328,11): error TS2300: Duplicate identifier 'ArrayLike'. +../../../../built/local/lib.es5.d.ts(1357,6): error TS2300: Duplicate identifier 'Record'. ../../../../node_modules/@types/node/index.d.ts(150,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'module' must be of type '{ [x: string]: any; }', but here has type 'NodeModule'. node_modules/chrome-devtools-frontend/front_end/Runtime.js(43,8): error TS2339: Property '_importScriptPathPrefix' does not exist on type 'Window'. node_modules/chrome-devtools-frontend/front_end/Runtime.js(95,28): error TS2339: Property 'response' does not exist on type 'EventTarget'. diff --git a/tests/baselines/reference/user/formik.log b/tests/baselines/reference/user/formik.log deleted file mode 100644 index 52ea18319a2..00000000000 --- a/tests/baselines/reference/user/formik.log +++ /dev/null @@ -1,28 +0,0 @@ -Exit Code: 1 -Standard output: -index.tsx(26,7): error TS2322: Type '{ initialValues: { email: string; password: string; }; validate: (values: Values) => FormikErrors...' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes FormikErrors...' is not assignable to type 'Readonly & { initialValues: { email: string; p...'. - Types of property 'onSubmit' are incompatible. - Type '(values: Values, { setSubmitting, setErrors }: FormikActions) => void' is not assignable to type '((values: { email: string; password: string; }, formikActions: FormikActions<{ email: string; pas...'. - Type '(values: Values, { setSubmitting, setErrors }: FormikActions) => void' is not assignable to type '(values: { email: string; password: string; }, formikActions: FormikActions<{ email: string; pass...'. - Types of parameters 'values' and 'values' are incompatible. - Type '{ email: string; password: string; }' is not assignable to type 'Values'. -index.tsx(32,13): error TS2322: Type '{}' is not assignable to type 'FormikErrors'. - Property 'email' is missing in type '{}'. -index.tsx(33,21): error TS2339: Property 'email' does not exist on type 'Values'. -index.tsx(36,68): error TS2339: Property 'email' does not exist on type 'Values'. -index.tsx(46,22): error TS2345: Argument of type 'Values' is not assignable to parameter of type 'MyData'. -index.tsx(47,11): error TS7006: Parameter 'user' implicitly has an 'any' type. -index.tsx(52,11): error TS7006: Parameter 'errors' implicitly has an 'any' type. -index.tsx(74,27): error TS2339: Property 'email' does not exist on type 'Values'. -index.tsx(76,20): error TS2339: Property 'email' does not exist on type 'FormikTouched'. -index.tsx(76,36): error TS2339: Property 'email' does not exist on type 'FormikErrors'. -index.tsx(76,58): error TS2339: Property 'email' does not exist on type 'FormikErrors'. -index.tsx(82,27): error TS2339: Property 'password' does not exist on type 'Values'. -index.tsx(84,20): error TS2339: Property 'password' does not exist on type 'FormikTouched'. -index.tsx(84,39): error TS2339: Property 'password' does not exist on type 'FormikErrors'. -index.tsx(84,64): error TS2339: Property 'password' does not exist on type 'FormikErrors'. - - - -Standard error: diff --git a/tests/cases/user/formik/index.tsx b/tests/cases/user/formik/index.tsx index 04e06cbd193..309ed883c5b 100644 --- a/tests/cases/user/formik/index.tsx +++ b/tests/cases/user/formik/index.tsx @@ -29,7 +29,7 @@ const Basic = () => ( }} validate={values => { // same as above, but feel free to move this into a class method now. - let errors: FormikErrors = {}; + let errors: FormikErrors = {} as FormikErrors; // FormikErrors isn't optionalized, so in strict null checks this needs a cast if (!values.email) { errors.email = 'Required'; } else if ( From 1a8a996f95d476875d1641e01b85028fe5f948b0 Mon Sep 17 00:00:00 2001 From: csigs Date: Tue, 6 Feb 2018 05:10:12 +0000 Subject: [PATCH 20/20] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl index a2ee47c3620..e651b11346d 100644 --- a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -8769,6 +8769,15 @@ + + + + + + + + +