Skip to content

Commit bf925fb

Browse files
committed
Add horrible probably wrong check
1 parent a4faf75 commit bf925fb

28 files changed

Lines changed: 1348 additions & 157 deletions

src/compiler/checker.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,7 @@ import {
875875
ObjectLiteralElementLike,
876876
ObjectLiteralExpression,
877877
ObjectType,
878+
OmittedExpression,
878879
OptionalChain,
879880
OptionalTypeNode,
880881
or,
@@ -41954,6 +41955,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4195441955
}
4195541956
checkCollisionsForDeclarationName(node, node.name);
4195641957
}
41958+
41959+
// TODO(jakebailey): copy pasted from declaration.ts; improve
41960+
type CanHaveLiteralInitializer = VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration;
41961+
function canHaveLiteralInitializer(node: Node): boolean {
41962+
switch (node.kind) {
41963+
case SyntaxKind.PropertyDeclaration:
41964+
case SyntaxKind.PropertySignature:
41965+
return !hasEffectiveModifier(node, ModifierFlags.Private);
41966+
case SyntaxKind.Parameter:
41967+
case SyntaxKind.VariableDeclaration:
41968+
return true;
41969+
}
41970+
return false;
41971+
}
41972+
41973+
function shouldPrintWithInitializer(node: Node) {
41974+
return canHaveLiteralInitializer(node) && isLiteralConstDeclaration(node as CanHaveLiteralInitializer); // TODO: Make safe
41975+
}
41976+
41977+
function getBindingNameVisible(elem: BindingElement | VariableDeclaration | OmittedExpression): boolean {
41978+
if (isOmittedExpression(elem)) {
41979+
return false;
41980+
}
41981+
if (isBindingPattern(elem.name)) {
41982+
// If any child binding pattern element has been marked visible (usually by collect linked aliases), then this is visible
41983+
return some(elem.name.elements, getBindingNameVisible);
41984+
}
41985+
else {
41986+
return isDeclarationVisible(elem);
41987+
}
41988+
}
41989+
41990+
function isDeclarationAndNotVisible(node: NamedDeclaration) {
41991+
switch (node.kind) {
41992+
case SyntaxKind.FunctionDeclaration:
41993+
case SyntaxKind.ModuleDeclaration:
41994+
case SyntaxKind.InterfaceDeclaration:
41995+
case SyntaxKind.ClassDeclaration:
41996+
case SyntaxKind.TypeAliasDeclaration:
41997+
case SyntaxKind.EnumDeclaration:
41998+
return !isDeclarationVisible(node);
41999+
// The following should be doing their own visibility checks based on filtering their members
42000+
case SyntaxKind.VariableDeclaration:
42001+
return !getBindingNameVisible(node as VariableDeclaration);
42002+
case SyntaxKind.ImportEqualsDeclaration:
42003+
case SyntaxKind.ImportDeclaration:
42004+
case SyntaxKind.ExportDeclaration:
42005+
case SyntaxKind.ExportAssignment:
42006+
return false;
42007+
case SyntaxKind.ClassStaticBlockDeclaration:
42008+
return true;
42009+
}
42010+
return false;
42011+
}
42012+
42013+
if (
42014+
!(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature))
42015+
&& !shouldPrintWithInitializer(node)
42016+
&& !isDeclarationAndNotVisible(node)
42017+
) {
42018+
const widenedLiteralType = getWidenedLiteralType(type);
42019+
if (!isTypeIdenticalTo(type, widenedLiteralType)) {
42020+
error(node.name, Diagnostics.The_type_of_this_declaration_is_ambiguous_and_may_be_observed_as_either_0_or_1, typeToString(widenedLiteralType), typeToString(type));
42021+
}
42022+
}
4195742023
}
4195842024

4195942025
function errorNextVariableOrPropertyDeclarationMustHaveSameType(firstDeclaration: Declaration | undefined, firstType: Type, nextDeclaration: Declaration, nextType: Type): void {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3667,6 +3667,10 @@
36673667
"category": "Error",
36683668
"code": 2855
36693669
},
3670+
"The type of this declaration is ambiguous and may be observed as either '{0}' or '{1}'.": {
3671+
"category": "Error",
3672+
"code": 2856
3673+
},
36703674

36713675
"Import declaration '{0}' is using private name '{1}'.": {
36723676
"category": "Error",
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
ambientConstLiterals.ts(20,7): error TS2856: The type of this declaration is ambiguous and may be observed as either 'string' or '"abc" | "def"'.
2+
ambientConstLiterals.ts(21,7): error TS2856: The type of this declaration is ambiguous and may be observed as either 'number' or '123 | 456'.
3+
4+
5+
==== ambientConstLiterals.ts (2 errors) ====
6+
function f<T>(x: T): T {
7+
return x;
8+
}
9+
10+
enum E { A, B, C, "non identifier" }
11+
12+
const c1 = "abc";
13+
const c2 = 123;
14+
const c3 = c1;
15+
const c4 = c2;
16+
const c5 = f(123);
17+
const c6 = f(-123);
18+
const c7 = true;
19+
const c8 = E.A;
20+
const c8b = E["non identifier"];
21+
const c9 = { x: "abc" };
22+
const c10 = [123];
23+
const c11 = "abc" + "def";
24+
const c12 = 123 + 456;
25+
const c13 = Math.random() > 0.5 ? "abc" : "def";
26+
~~~
27+
!!! error TS2856: The type of this declaration is ambiguous and may be observed as either 'string' or '"abc" | "def"'.
28+
const c14 = Math.random() > 0.5 ? 123 : 456;
29+
~~~
30+
!!! error TS2856: The type of this declaration is ambiguous and may be observed as either 'number' or '123 | 456'.

tests/baselines/reference/declFileExportAssignmentImportInternalModule.js

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,6 @@ module.exports = m;
3434

3535
//// [declFileExportAssignmentImportInternalModule.d.ts]
3636
declare namespace m3 {
37-
namespace m2 {
38-
interface connectModule {
39-
(res: any, req: any, next: any): void;
40-
}
41-
interface connectExport {
42-
use: (mod: connectModule) => connectExport;
43-
listen: (port: number) => void;
44-
}
45-
}
46-
var server: {
47-
(): m2.connectExport;
48-
test1: m2.connectModule;
49-
test2(): m2.connectModule;
50-
};
5137
}
5238
import m = m3;
5339
export = m;

tests/baselines/reference/declarationEmitImportInExportAssignmentModule.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,5 @@ module.exports = m;
3030

3131
//// [declarationEmitImportInExportAssignmentModule.d.ts]
3232
declare namespace m {
33-
namespace c {
34-
class c {
35-
}
36-
}
37-
import x = c;
38-
var a: typeof x;
3933
}
4034
export = m;

tests/baselines/reference/es6ExportClause.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ declare class c {
3737
interface i {
3838
}
3939
declare namespace m {
40-
var x: number;
4140
}
4241
declare var x: number;
4342
declare namespace uninstantiated {

tests/baselines/reference/es6ExportClauseInEs5.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ declare class c {
4242
interface i {
4343
}
4444
declare namespace m {
45-
var x: number;
4645
}
4746
declare var x: number;
4847
declare namespace uninstantiated {

tests/baselines/reference/importCallExpression5ES2020.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
2.ts(2,7): error TS2856: The type of this declaration is ambiguous and may be observed as either 'string | undefined' or '"./0" | undefined'.
12
2.ts(3,23): error TS7036: Dynamic import's specifier must be of type 'string', but here has type '"./0" | undefined'.
23
2.ts(4,24): error TS7036: Dynamic import's specifier must be of type 'string', but here has type 'undefined'.
34
2.ts(5,24): error TS7036: Dynamic import's specifier must be of type 'string', but here has type '"./1" | null'.
@@ -14,9 +15,11 @@
1415
==== 1.ts (0 errors) ====
1516
export function backup() { return "backup"; }
1617

17-
==== 2.ts (4 errors) ====
18+
==== 2.ts (5 errors) ====
1819
declare function bar(): boolean;
1920
const specify = bar() ? "./0" : undefined;
21+
~~~~~~~
22+
!!! error TS2856: The type of this declaration is ambiguous and may be observed as either 'string | undefined' or '"./0" | undefined'.
2023
let myModule = import(specify);
2124
~~~~~~~
2225
!!! error TS7036: Dynamic import's specifier must be of type 'string', but here has type '"./0" | undefined'.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
inferenceOptionalPropertiesToIndexSignatures.ts(15,7): error TS2856: The type of this declaration is ambiguous and may be observed as either 'string | null' or '"value2" | null'.
2+
3+
4+
==== inferenceOptionalPropertiesToIndexSignatures.ts (1 errors) ====
5+
declare function foo<T>(obj: { [x: string]: T }): T;
6+
7+
declare const x1: { a: string, b: number };
8+
declare const x2: { a: string, b: number | undefined };
9+
declare const x3: { a: string, b?: number };
10+
declare const x4: { a: string, b?: number | undefined };
11+
12+
let a1 = foo(x1); // string | number
13+
let a2 = foo(x2); // string | number | undefined
14+
let a3 = foo(x3); // string | number
15+
let a4 = foo(x4); // string | number
16+
17+
// Repro from #43045
18+
19+
const param2 = Math.random() < 0.5 ? 'value2' : null;
20+
~~~~~~
21+
!!! error TS2856: The type of this declaration is ambiguous and may be observed as either 'string | null' or '"value2" | null'.
22+
23+
const obj = {
24+
param1: 'value1',
25+
...(param2 ? {param2} : {})
26+
};
27+
28+
const query = Object.entries(obj).map(
29+
([k, v]) => `${k}=${encodeURIComponent(v)}`
30+
).join('&');
31+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
a.js(2,5): error TS2856: The type of this declaration is ambiguous and may be observed as either 'string' or '"foo"'.
2+
3+
4+
==== b.js (0 errors) ====
5+
export const FOO = "foo";
6+
7+
==== a.js (1 errors) ====
8+
/** @type {import('./b').FOO} */
9+
let x;
10+
~
11+
!!! error TS2856: The type of this declaration is ambiguous and may be observed as either 'string' or '"foo"'.
12+

0 commit comments

Comments
 (0)