Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(50375): Errors for missing enum-named properties should attempt to preserve names #50382

Merged
merged 6 commits into from Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/compiler/checker.ts
Expand Up @@ -20310,7 +20310,8 @@ namespace ts {
shouldSkipElaboration = true; // Retain top-level error for interface implementing issues, otherwise omit it
}
if (props.length === 1) {
const propName = symbolToString(unmatchedProperty);
const nameType = getSymbolLinks(unmatchedProperty).nameType;
const propName = nameType && nameType.flags & TypeFlags.EnumLiteral ? `[${symbolToString(nameType.symbol, nameType.symbol.valueDeclaration)}]` : symbolToString(unmatchedProperty);
a-tarasyuk marked this conversation as resolved.
Show resolved Hide resolved
a-tarasyuk marked this conversation as resolved.
Show resolved Hide resolved
reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, ...getTypeNamesForErrorDisplay(source, target));
if (length(unmatchedProperty.declarations)) {
associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations![0], Diagnostics._0_is_declared_here, propName));
Expand Down
5 changes: 3 additions & 2 deletions src/services/codefixes/fixAddMissingMember.ts
Expand Up @@ -642,8 +642,9 @@ namespace ts.codefix {
}

function createPropertyNameFromSymbol(symbol: Symbol, target: ScriptTarget, quotePreference: QuotePreference, checker: TypeChecker) {
if (isTransientSymbol(symbol) && symbol.nameType && symbol.nameType.flags & TypeFlags.UniqueESSymbol) {
const expression = checker.symbolToExpression((symbol.nameType as UniqueESSymbolType).symbol, SymbolFlags.Value, symbol.valueDeclaration, NodeBuilderFlags.AllowUniqueESSymbolType);
if (isTransientSymbol(symbol) && symbol.nameType && symbol.nameType.flags & (TypeFlags.UniqueESSymbol | TypeFlags.EnumLiteral)) {
const nameTypeSymbol = symbol.nameType.symbol;
const expression = checker.symbolToExpression(nameTypeSymbol, SymbolFlags.Value, nameTypeSymbol.valueDeclaration, NodeBuilderFlags.AllowUniqueESSymbolType);
a-tarasyuk marked this conversation as resolved.
Show resolved Hide resolved
if (expression) {
return factory.createComputedPropertyName(expression);
}
Expand Down
@@ -0,0 +1,12 @@
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithEnumIndexer.ts(5,5): error TS2741: Property '[E.A]' is missing in type '{}' but required in type 'Record<E, any>'.


==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithEnumIndexer.ts (1 errors) ====
enum E {
A
}

let foo: Record<E, any> = {}
~~~
!!! error TS2741: Property '[E.A]' is missing in type '{}' but required in type 'Record<E, any>'.

14 changes: 14 additions & 0 deletions tests/baselines/reference/assignmentCompatWithEnumIndexer.js
@@ -0,0 +1,14 @@
//// [assignmentCompatWithEnumIndexer.ts]
enum E {
A
}

let foo: Record<E, any> = {}


//// [assignmentCompatWithEnumIndexer.js]
var E;
(function (E) {
E[E["A"] = 0] = "A";
})(E || (E = {}));
var foo = {};
13 changes: 13 additions & 0 deletions tests/baselines/reference/assignmentCompatWithEnumIndexer.symbols
@@ -0,0 +1,13 @@
=== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithEnumIndexer.ts ===
enum E {
>E : Symbol(E, Decl(assignmentCompatWithEnumIndexer.ts, 0, 0))

A
>A : Symbol(E.A, Decl(assignmentCompatWithEnumIndexer.ts, 0, 8))
}

let foo: Record<E, any> = {}
>foo : Symbol(foo, Decl(assignmentCompatWithEnumIndexer.ts, 4, 3))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>E : Symbol(E, Decl(assignmentCompatWithEnumIndexer.ts, 0, 0))

12 changes: 12 additions & 0 deletions tests/baselines/reference/assignmentCompatWithEnumIndexer.types
@@ -0,0 +1,12 @@
=== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithEnumIndexer.ts ===
enum E {
>E : E

A
>A : E.A
}

let foo: Record<E, any> = {}
>foo : Record<E, any>
>{} : {}

@@ -0,0 +1,5 @@
enum E {
A
}

let foo: Record<E, any> = {}
18 changes: 18 additions & 0 deletions tests/cases/fourslash/codeFixAddMissingProperties23.ts
@@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />

////enum E {
//// A
////}
////let obj: Record<E, any> = {}

verify.codeFix({
index: 0,
description: ts.Diagnostics.Add_missing_properties.message,
newFileContent:
`enum E {
A
}
let obj: Record<E, any> = {
[E.A]: undefined
}`,
});