diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5aea2c15d4f21..2314379641fe5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -37102,7 +37102,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Treat any call to the global 'Symbol' function that is part of a const variable or readonly property // as a fresh unique symbol literal type. if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) { - return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent)); + return getESSymbolLikeTypeForNode(walkUpOuterExpressions(node, OuterExpressionKinds.Parentheses | OuterExpressionKinds.Satisfies)); } if ( node.kind === SyntaxKind.CallExpression && !node.questionDotToken && node.parent.kind === SyntaxKind.ExpressionStatement && diff --git a/tests/baselines/reference/uniqueSymbols.errors.txt b/tests/baselines/reference/uniqueSymbols.errors.txt new file mode 100644 index 0000000000000..eeac3a94e1bf2 --- /dev/null +++ b/tests/baselines/reference/uniqueSymbols.errors.txt @@ -0,0 +1,279 @@ +uniqueSymbols.ts(272,27): error TS2352: Conversion of type 'symbol' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. + + +==== uniqueSymbols.ts (1 errors) ==== + // declarations with call initializer + const constCall = Symbol(); + let letCall = Symbol(); + var varCall = Symbol(); + + // ambient declaration with type + declare const constType: unique symbol; + + // declaration with type and call initializer + const constTypeAndCall: unique symbol = Symbol(); + + // declaration from initializer + const constInitToConstCall = constCall; + const constInitToLetCall = letCall; + const constInitToVarCall = varCall; + const constInitToConstDeclAmbient = constType; + let letInitToConstCall = constCall; + let letInitToLetCall = letCall; + let letInitToVarCall = varCall; + let letInitToConstDeclAmbient = constType; + var varInitToConstCall = constCall; + var varInitToLetCall = letCall; + var varInitToVarCall = varCall; + var varInitToConstDeclAmbient = constType; + + // declaration from initializer with type query + const constInitToConstCallWithTypeQuery: typeof constCall = constCall; + const constInitToConstDeclAmbientWithTypeQuery: typeof constType = constType; + + // assignment from any + // https://github.com/Microsoft/TypeScript/issues/29108 + const fromAny: unique symbol = {} as any; + + // function return inference + function funcReturnConstCall() { return constCall; } + function funcReturnLetCall() { return letCall; } + function funcReturnVarCall() { return varCall; } + + // function return value with type query + function funcReturnConstCallWithTypeQuery(): typeof constCall { return constCall; } + + // generator function yield inference + function* genFuncYieldConstCall() { yield constCall; } + function* genFuncYieldLetCall() { yield letCall; } + function* genFuncYieldVarCall() { yield varCall; } + + // generator function yield with return type query + function* genFuncYieldConstCallWithTypeQuery(): IterableIterator { yield constCall; } + + // async function return inference + async function asyncFuncReturnConstCall() { return constCall; } + async function asyncFuncReturnLetCall() { return letCall; } + async function asyncFuncReturnVarCall() { return varCall; } + + // async generator function yield inference + async function* asyncGenFuncYieldConstCall() { yield constCall; } + async function* asyncGenFuncYieldLetCall() { yield letCall; } + async function* asyncGenFuncYieldVarCall() { yield varCall; } + + // classes + class C { + static readonly readonlyStaticCall = Symbol(); + static readonly readonlyStaticType: unique symbol; + static readonly readonlyStaticTypeAndCall: unique symbol = Symbol(); + static readwriteStaticCall = Symbol(); + + readonly readonlyCall = Symbol(); + readwriteCall = Symbol(); + } + declare const c: C; + + const constInitToCReadonlyStaticCall = C.readonlyStaticCall; + const constInitToCReadonlyStaticType = C.readonlyStaticType; + const constInitToCReadonlyStaticTypeAndCall = C.readonlyStaticTypeAndCall; + const constInitToCReadwriteStaticCall = C.readwriteStaticCall; + + const constInitToCReadonlyStaticCallWithTypeQuery: typeof C.readonlyStaticCall = C.readonlyStaticCall; + const constInitToCReadonlyStaticTypeWithTypeQuery: typeof C.readonlyStaticType = C.readonlyStaticType; + const constInitToCReadonlyStaticTypeAndCallWithTypeQuery: typeof C.readonlyStaticTypeAndCall = C.readonlyStaticTypeAndCall; + const constInitToCReadwriteStaticCallWithTypeQuery: typeof C.readwriteStaticCall = C.readwriteStaticCall; + + const constInitToCReadonlyCall = c.readonlyCall; + const constInitToCReadwriteCall = c.readwriteCall; + const constInitToCReadonlyCallWithTypeQuery: typeof c.readonlyCall = c.readonlyCall; + const constInitToCReadwriteCallWithTypeQuery: typeof c.readwriteCall = c.readwriteCall; + const constInitToCReadonlyCallWithIndexedAccess: C["readonlyCall"] = c.readonlyCall; + const constInitToCReadwriteCallWithIndexedAccess: C["readwriteCall"] = c.readwriteCall; + + // interfaces + interface I { + readonly readonlyType: unique symbol; + } + declare const i: I; + + const constInitToIReadonlyType = i.readonlyType; + const constInitToIReadonlyTypeWithTypeQuery: typeof i.readonlyType = i.readonlyType; + const constInitToIReadonlyTypeWithIndexedAccess: I["readonlyType"] = i.readonlyType; + + // type literals + type L = { + readonly readonlyType: unique symbol; + nested: { + readonly readonlyNestedType: unique symbol; + } + }; + declare const l: L; + + const constInitToLReadonlyType = l.readonlyType; + const constInitToLReadonlyNestedType = l.nested.readonlyNestedType; + const constInitToLReadonlyTypeWithTypeQuery: typeof l.readonlyType = l.readonlyType; + const constInitToLReadonlyNestedTypeWithTypeQuery: typeof l.nested.readonlyNestedType = l.nested.readonlyNestedType; + const constInitToLReadonlyTypeWithIndexedAccess: L["readonlyType"] = l.readonlyType; + const constInitToLReadonlyNestedTypeWithIndexedAccess: L["nested"]["readonlyNestedType"] = l.nested.readonlyNestedType; + + // type argument inference + const promiseForConstCall = Promise.resolve(constCall); + const arrayOfConstCall = [constCall]; + + // unique symbol widening in expressions + declare const s: unique symbol; + declare namespace N { const s: unique symbol; } + declare const o: { [s]: "a", [N.s]: "b" }; + declare function f(x: T): T; + declare function g(x: typeof s): void; + declare function g(x: typeof N.s): void; + + // widening positions + + // argument inference + f(s); + f(N.s); + f(N["s"]); + + // array literal elements + [s]; + [N.s]; + [N["s"]]; + + // property assignments/methods + const o2 = { + a: s, + b: N.s, + c: N["s"], + + method1() { return s; }, + async method2() { return s; }, + async * method3() { yield s; }, + * method4() { yield s; }, + method5(p = s) { return p; }, + }; + + // property initializers + class C0 { + static readonly a = s; + static readonly b = N.s; + static readonly c = N["s"]; + + static d = s; + static e = N.s; + static f = N["s"]; + + readonly a = s; + readonly b = N.s; + readonly c = N["s"]; + + d = s; + e = N.s; + f = N["s"]; + + method1() { return s; } + async method2() { return s; } + async * method3() { yield s; } + * method4() { yield s; } + method5(p = s) { return p; } + } + + // non-widening positions + + // element access + o[s]; + o[N.s]; + o[N["s"]]; + + // arguments (no-inference) + f(s); + f(N.s); + f(N["s"]); + g(s); + g(N.s); + g(N["s"]); + + // falsy expressions + s || ""; + N.s || ""; + N["s"] || ""; + + // conditionals + Math.random() * 2 ? s : "a"; + Math.random() * 2 ? N.s : "a"; + Math.random() * 2 ? N["s"] : "a"; + + // computed property names + ({ + [s]: "a", + [N.s]: "b", + }); + + class C1 { + static [s]: "a"; + static [N.s]: "b"; + + [s]: "a"; + [N.s]: "b"; + } + + // contextual types + + interface Context { + method1(): typeof s; + method2(): Promise; + method3(): AsyncIterableIterator; + method4(): IterableIterator; + method5(p?: typeof s): typeof s; + } + + const o3: Context = { + method1() { + return s; // return type should not widen due to contextual type + }, + async method2() { + return s; // return type should not widen due to contextual type + }, + async * method3() { + yield s; // yield type should not widen due to contextual type + }, + * method4() { + yield s; // yield type should not widen due to contextual type + }, + method5(p = s) { // parameter should not widen due to contextual type + return p; + }, + }; + + // allowed when not emitting declarations + + const o4 = { + method1(p: typeof s): typeof s { + return p; + }, + method2(p: I["readonlyType"]): I["readonlyType"] { + return p; + } + }; + + const ce0 = class { + method1(p: typeof s): typeof s { + return p; + } + method2(p: I["readonlyType"]): I["readonlyType"] { + return p; + } + }; + + function funcInferredReturnType(obj: { method(p: typeof s): void }) { + return obj; + } + + // https://github.com/microsoft/TypeScript/issues/61070 + const bar = Symbol('bar') satisfies symbol; + let bar2 = Symbol('bar2') satisfies symbol; + + const testErrorMessage1 = Symbol() as string; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Conversion of type 'symbol' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. + \ No newline at end of file diff --git a/tests/baselines/reference/uniqueSymbols.js b/tests/baselines/reference/uniqueSymbols.js index 35a40abc5bcb9..ca256c3e44609 100644 --- a/tests/baselines/reference/uniqueSymbols.js +++ b/tests/baselines/reference/uniqueSymbols.js @@ -267,6 +267,12 @@ const ce0 = class { function funcInferredReturnType(obj: { method(p: typeof s): void }) { return obj; } + +// https://github.com/microsoft/TypeScript/issues/61070 +const bar = Symbol('bar') satisfies symbol; +let bar2 = Symbol('bar2') satisfies symbol; + +const testErrorMessage1 = Symbol() as string; //// [uniqueSymbols.js] @@ -458,3 +464,7 @@ const ce0 = class { function funcInferredReturnType(obj) { return obj; } +// https://github.com/microsoft/TypeScript/issues/61070 +const bar = Symbol('bar'); +let bar2 = Symbol('bar2'); +const testErrorMessage1 = Symbol(); diff --git a/tests/baselines/reference/uniqueSymbols.symbols b/tests/baselines/reference/uniqueSymbols.symbols index 530dd96de549a..5e4d0e33cb56c 100644 --- a/tests/baselines/reference/uniqueSymbols.symbols +++ b/tests/baselines/reference/uniqueSymbols.symbols @@ -863,3 +863,16 @@ function funcInferredReturnType(obj: { method(p: typeof s): void }) { >obj : Symbol(obj, Decl(uniqueSymbols.ts, 263, 32)) } +// https://github.com/microsoft/TypeScript/issues/61070 +const bar = Symbol('bar') satisfies symbol; +>bar : Symbol(bar, Decl(uniqueSymbols.ts, 268, 5)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) + +let bar2 = Symbol('bar2') satisfies symbol; +>bar2 : Symbol(bar2, Decl(uniqueSymbols.ts, 269, 3)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) + +const testErrorMessage1 = Symbol() as string; +>testErrorMessage1 : Symbol(testErrorMessage1, Decl(uniqueSymbols.ts, 271, 5)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) + diff --git a/tests/baselines/reference/uniqueSymbols.types b/tests/baselines/reference/uniqueSymbols.types index c9aa5b7952203..912a9d0d4923a 100644 --- a/tests/baselines/reference/uniqueSymbols.types +++ b/tests/baselines/reference/uniqueSymbols.types @@ -136,6 +136,7 @@ const fromAny: unique symbol = {} as any; >fromAny : unique symbol > : ^^^^^^^^^^^^^ >{} as any : any +> : ^^^ >{} : {} > : ^^ @@ -172,6 +173,7 @@ function* genFuncYieldConstCall() { yield constCall; } >genFuncYieldConstCall : () => Generator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield constCall : any +> : ^^^ >constCall : unique symbol > : ^^^^^^^^^^^^^ @@ -179,6 +181,7 @@ function* genFuncYieldLetCall() { yield letCall; } >genFuncYieldLetCall : () => Generator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield letCall : any +> : ^^^ >letCall : symbol > : ^^^^^^ @@ -186,6 +189,7 @@ function* genFuncYieldVarCall() { yield varCall; } >genFuncYieldVarCall : () => Generator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield varCall : any +> : ^^^ >varCall : symbol > : ^^^^^^ @@ -196,6 +200,7 @@ function* genFuncYieldConstCallWithTypeQuery(): IterableIteratorconstCall : unique symbol > : ^^^^^^^^^^^^^ >yield constCall : any +> : ^^^ >constCall : unique symbol > : ^^^^^^^^^^^^^ @@ -223,6 +228,7 @@ async function* asyncGenFuncYieldConstCall() { yield constCall; } >asyncGenFuncYieldConstCall : () => AsyncGenerator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield constCall : any +> : ^^^ >constCall : unique symbol > : ^^^^^^^^^^^^^ @@ -230,6 +236,7 @@ async function* asyncGenFuncYieldLetCall() { yield letCall; } >asyncGenFuncYieldLetCall : () => AsyncGenerator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield letCall : any +> : ^^^ >letCall : symbol > : ^^^^^^ @@ -237,6 +244,7 @@ async function* asyncGenFuncYieldVarCall() { yield varCall; } >asyncGenFuncYieldVarCall : () => AsyncGenerator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield varCall : any +> : ^^^ >varCall : symbol > : ^^^^^^ @@ -812,6 +820,7 @@ const o2 = { >method3 : () => AsyncGenerator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield s : any +> : ^^^ >s : unique symbol > : ^^^^^^^^^^^^^ @@ -819,6 +828,7 @@ const o2 = { >method4 : () => Generator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield s : any +> : ^^^ >s : unique symbol > : ^^^^^^^^^^^^^ @@ -959,6 +969,7 @@ class C0 { >method3 : () => AsyncGenerator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield s : any +> : ^^^ >s : unique symbol > : ^^^^^^^^^^^^^ @@ -966,6 +977,7 @@ class C0 { >method4 : () => Generator > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >yield s : any +> : ^^^ >s : unique symbol > : ^^^^^^^^^^^^^ @@ -1330,6 +1342,7 @@ const o3: Context = { yield s; // yield type should not widen due to contextual type >yield s : any +> : ^^^ >s : unique symbol > : ^^^^^^^^^^^^^ @@ -1340,6 +1353,7 @@ const o3: Context = { yield s; // yield type should not widen due to contextual type >yield s : any +> : ^^^ >s : unique symbol > : ^^^^^^^^^^^^^ @@ -1443,3 +1457,38 @@ function funcInferredReturnType(obj: { method(p: typeof s): void }) { > : ^^^^^^^^^ ^^ ^^^ ^^^ } +// https://github.com/microsoft/TypeScript/issues/61070 +const bar = Symbol('bar') satisfies symbol; +>bar : unique symbol +> : ^^^^^^^^^^^^^ +>Symbol('bar') satisfies symbol : unique symbol +> : ^^^^^^^^^^^^^ +>Symbol('bar') : unique symbol +> : ^^^^^^^^^^^^^ +>Symbol : SymbolConstructor +> : ^^^^^^^^^^^^^^^^^ +>'bar' : "bar" +> : ^^^^^ + +let bar2 = Symbol('bar2') satisfies symbol; +>bar2 : symbol +> : ^^^^^^ +>Symbol('bar2') satisfies symbol : symbol +> : ^^^^^^ +>Symbol('bar2') : symbol +> : ^^^^^^ +>Symbol : SymbolConstructor +> : ^^^^^^^^^^^^^^^^^ +>'bar2' : "bar2" +> : ^^^^^^ + +const testErrorMessage1 = Symbol() as string; +>testErrorMessage1 : string +> : ^^^^^^ +>Symbol() as string : string +> : ^^^^^^ +>Symbol() : symbol +> : ^^^^^^ +>Symbol : SymbolConstructor +> : ^^^^^^^^^^^^^^^^^ + diff --git a/tests/cases/conformance/types/uniqueSymbol/uniqueSymbols.ts b/tests/cases/conformance/types/uniqueSymbol/uniqueSymbols.ts index 02a77ff98e184..c9c6c14305285 100644 --- a/tests/cases/conformance/types/uniqueSymbol/uniqueSymbols.ts +++ b/tests/cases/conformance/types/uniqueSymbol/uniqueSymbols.ts @@ -269,3 +269,9 @@ const ce0 = class { function funcInferredReturnType(obj: { method(p: typeof s): void }) { return obj; } + +// https://github.com/microsoft/TypeScript/issues/61070 +const bar = Symbol('bar') satisfies symbol; +let bar2 = Symbol('bar2') satisfies symbol; + +const testErrorMessage1 = Symbol() as string;