diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8fa3c4fce2a4a..1fb3fdc4ab4ff 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22636,7 +22636,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!(target.flags & TypeFlags.Never) && isLiteralType(source) && !typeCouldHaveTopLevelSingletonTypes(target)) { generalizedSource = getBaseTypeOfLiteralType(source); Debug.assert(!isTypeAssignableTo(generalizedSource, target), "generalized source shouldn't be assignable"); - generalizedSourceType = getTypeNameForErrorDisplay(generalizedSource); + // When a non-enum union of literals generalizes to a single non-union + // base type (e.g. "a" | "b" -> string), skip the generalization for + // display purposes. The per-member elaboration already shows the base + // type, so using it here would produce a duplicate message (see #63050). + if (source.flags & TypeFlags.Union && !(source.flags & TypeFlags.EnumLiteral) && !(generalizedSource.flags & TypeFlags.Union)) { + generalizedSource = source; + } + else { + generalizedSourceType = getTypeNameForErrorDisplay(generalizedSource); + } } // If `target` is of indexed access type (And `source` it is not), we use the object type of `target` for better error reporting diff --git a/tests/baselines/reference/bigintPropertyName.errors.txt b/tests/baselines/reference/bigintPropertyName.errors.txt index 2b2db4f45c631..524287994ff1d 100644 --- a/tests/baselines/reference/bigintPropertyName.errors.txt +++ b/tests/baselines/reference/bigintPropertyName.errors.txt @@ -23,7 +23,7 @@ g.ts(32,3): error TS2538: Type 'bigint' cannot be used as an index type. g.ts(33,4): error TS2538: Type 'bigint' cannot be used as an index type. g.ts(35,1): error TS1434: Unexpected keyword or identifier. g.ts(35,2): error TS1353: A bigint literal must be an integer. -q.ts(2,19): error TS2322: Type 'bigint' is not assignable to type 'string | number | symbol'. +q.ts(2,19): error TS2322: Type 'Q' is not assignable to type 'string | number | symbol'. Type 'bigint' is not assignable to type 'string | number | symbol'. @@ -138,6 +138,6 @@ q.ts(2,19): error TS2322: Type 'bigint' is not assignable to type 'string | numb type Q = 6n | 7n | 8n; type T = { [t in Q]: string }; ~ -!!! error TS2322: Type 'bigint' is not assignable to type 'string | number | symbol'. +!!! error TS2322: Type 'Q' is not assignable to type 'string | number | symbol'. !!! error TS2322: Type 'bigint' is not assignable to type 'string | number | symbol'. \ No newline at end of file diff --git a/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt b/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt index 0ee31ce889f0b..2855106b8f31c 100644 --- a/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt +++ b/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt @@ -2,14 +2,14 @@ complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts(33,5): error TS2322 Type '{ type: T; localChannelId: string; }' is not assignable to type 'Pick | ChannelOfType, "type">'. Types of property 'type' are incompatible. Type 'T' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. - Type 'string' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. + Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. Type 'string' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. Type 'string' is not assignable to type 'ChannelOfType["type"]'. Type '"text"' is not assignable to type 'T & "text"'. Type '"text"' is not assignable to type 'T'. '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. Type 'T' is not assignable to type 'ChannelOfType["type"]'. - Type 'string' is not assignable to type 'ChannelOfType["type"]'. + Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. Type 'string' is not assignable to type 'ChannelOfType["type"]'. Type '"text"' is not assignable to type 'T & "text"'. Type '"text"' is not assignable to type 'T'. @@ -63,14 +63,14 @@ complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts(33,5): error TS2322 !!! error TS2322: Type '{ type: T; localChannelId: string; }' is not assignable to type 'Pick | ChannelOfType, "type">'. !!! error TS2322: Types of property 'type' are incompatible. !!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. -!!! error TS2322: Type 'string' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. +!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. !!! error TS2322: Type 'string' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. !!! error TS2322: Type 'string' is not assignable to type 'ChannelOfType["type"]'. !!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'. !!! error TS2322: Type '"text"' is not assignable to type 'T'. !!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. !!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType["type"]'. -!!! error TS2322: Type 'string' is not assignable to type 'ChannelOfType["type"]'. +!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. !!! error TS2322: Type 'string' is not assignable to type 'ChannelOfType["type"]'. !!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'. !!! error TS2322: Type '"text"' is not assignable to type 'T'. diff --git a/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.errors.txt b/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.errors.txt new file mode 100644 index 0000000000000..dd9a8469cd038 --- /dev/null +++ b/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.errors.txt @@ -0,0 +1,23 @@ +noDoubleErrorForLiteralUnionFromAmbient.ts(7,7): error TS2322: Type '"a" | "b"' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. +noDoubleErrorForLiteralUnionFromAmbient.ts(11,7): error TS2322: Type 'string' is not assignable to type 'number'. + + +==== noDoubleErrorForLiteralUnionFromAmbient.ts (2 errors) ==== + // Repro from #63050 + // When assigning a union of string literals from an ambient declaration to + // an incompatible type, the error should not show the same message twice. + + declare const x: "a" | "b" + + const y: number = x + ~ +!!! error TS2322: Type '"a" | "b"' is not assignable to type 'number'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + + declare const single: "hello" + + const z: number = single + ~ +!!! error TS2322: Type 'string' is not assignable to type 'number'. + \ No newline at end of file diff --git a/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.js b/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.js new file mode 100644 index 0000000000000..09f4331683f70 --- /dev/null +++ b/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.js @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/noDoubleErrorForLiteralUnionFromAmbient.ts] //// + +//// [noDoubleErrorForLiteralUnionFromAmbient.ts] +// Repro from #63050 +// When assigning a union of string literals from an ambient declaration to +// an incompatible type, the error should not show the same message twice. + +declare const x: "a" | "b" + +const y: number = x + +declare const single: "hello" + +const z: number = single + + +//// [noDoubleErrorForLiteralUnionFromAmbient.js] +"use strict"; +// Repro from #63050 +// When assigning a union of string literals from an ambient declaration to +// an incompatible type, the error should not show the same message twice. +const y = x; +const z = single; diff --git a/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.symbols b/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.symbols new file mode 100644 index 0000000000000..a132abcbda1a6 --- /dev/null +++ b/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.symbols @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/noDoubleErrorForLiteralUnionFromAmbient.ts] //// + +=== noDoubleErrorForLiteralUnionFromAmbient.ts === +// Repro from #63050 +// When assigning a union of string literals from an ambient declaration to +// an incompatible type, the error should not show the same message twice. + +declare const x: "a" | "b" +>x : Symbol(x, Decl(noDoubleErrorForLiteralUnionFromAmbient.ts, 4, 13)) + +const y: number = x +>y : Symbol(y, Decl(noDoubleErrorForLiteralUnionFromAmbient.ts, 6, 5)) +>x : Symbol(x, Decl(noDoubleErrorForLiteralUnionFromAmbient.ts, 4, 13)) + +declare const single: "hello" +>single : Symbol(single, Decl(noDoubleErrorForLiteralUnionFromAmbient.ts, 8, 13)) + +const z: number = single +>z : Symbol(z, Decl(noDoubleErrorForLiteralUnionFromAmbient.ts, 10, 5)) +>single : Symbol(single, Decl(noDoubleErrorForLiteralUnionFromAmbient.ts, 8, 13)) + diff --git a/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.types b/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.types new file mode 100644 index 0000000000000..a0e90131f3157 --- /dev/null +++ b/tests/baselines/reference/noDoubleErrorForLiteralUnionFromAmbient.types @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/noDoubleErrorForLiteralUnionFromAmbient.ts] //// + +=== noDoubleErrorForLiteralUnionFromAmbient.ts === +// Repro from #63050 +// When assigning a union of string literals from an ambient declaration to +// an incompatible type, the error should not show the same message twice. + +declare const x: "a" | "b" +>x : "a" | "b" +> : ^^^^^^^^^ + +const y: number = x +>y : number +> : ^^^^^^ +>x : "a" | "b" +> : ^^^^^^^^^ + +declare const single: "hello" +>single : "hello" +> : ^^^^^^^ + +const z: number = single +>z : number +> : ^^^^^^ +>single : "hello" +> : ^^^^^^^ + diff --git a/tests/baselines/reference/typeOfOperator1.errors.txt b/tests/baselines/reference/typeOfOperator1.errors.txt index c9201fb0137ac..0bf68567af3c1 100644 --- a/tests/baselines/reference/typeOfOperator1.errors.txt +++ b/tests/baselines/reference/typeOfOperator1.errors.txt @@ -1,4 +1,4 @@ -typeOfOperator1.ts(3,5): error TS2322: Type 'string' is not assignable to type 'number'. +typeOfOperator1.ts(3,5): error TS2322: Type '"string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'. @@ -7,5 +7,5 @@ typeOfOperator1.ts(3,5): error TS2322: Type 'string' is not assignable to type ' var y: string = typeof x; var z: number = typeof x; ~ -!!! error TS2322: Type 'string' is not assignable to type 'number'. +!!! error TS2322: Type '"string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"' is not assignable to type 'number'. !!! error TS2322: Type 'string' is not assignable to type 'number'. \ No newline at end of file diff --git a/tests/cases/compiler/noDoubleErrorForLiteralUnionFromAmbient.ts b/tests/cases/compiler/noDoubleErrorForLiteralUnionFromAmbient.ts new file mode 100644 index 0000000000000..b5183d3fb421c --- /dev/null +++ b/tests/cases/compiler/noDoubleErrorForLiteralUnionFromAmbient.ts @@ -0,0 +1,13 @@ +// @strict: true + +// Repro from #63050 +// When assigning a union of string literals from an ambient declaration to +// an incompatible type, the error should not show the same message twice. + +declare const x: "a" | "b" + +const y: number = x + +declare const single: "hello" + +const z: number = single