Skip to content

Commit 7d7750d

Browse files
committed
WIP
1 parent f1288c3 commit 7d7750d

File tree

156 files changed

+984
-405
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

156 files changed

+984
-405
lines changed

src/compiler/checker.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18675,7 +18675,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1867518675
case SyntaxKind.ObjectLiteralExpression:
1867618676
return some((node as ObjectLiteralExpression).properties, isContextSensitive);
1867718677
case SyntaxKind.ArrayLiteralExpression:
18678-
return some((node as ArrayLiteralExpression).elements, isContextSensitive);
18678+
if ((node as ArrayLiteralExpression).elements.length > 0) {
18679+
return some((node as ArrayLiteralExpression).elements, isContextSensitive);
18680+
}
18681+
return true;
1867918682
case SyntaxKind.ConditionalExpression:
1868018683
return isContextSensitive((node as ConditionalExpression).whenTrue) ||
1868118684
isContextSensitive((node as ConditionalExpression).whenFalse);
@@ -29121,6 +29124,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2912129124
if (forceTuple || inConstContext || contextualType && someType(contextualType, isTupleLikeType)) {
2912229125
return createArrayLiteralType(createTupleType(elementTypes, elementFlags, /*readonly*/ inConstContext));
2912329126
}
29127+
if (elementCount === 0 && contextualType && !checkMode) {
29128+
// For an empty array literal, produce the type (T1 & T2 & T3...)[] where Tn is the element type
29129+
// of each array-like union constituent of the contextual type
29130+
const contextualElementTypes: Type[] = [];
29131+
forEachType(contextualType, type => {
29132+
if (isArrayLikeType(type)) {
29133+
// Note that if we're here, it's not a tuple contextual type, so the
29134+
// numeric index signature must be present and sufficient
29135+
const elementType = getIndexTypeOfType(type, numberType);
29136+
if (elementType) {
29137+
contextualElementTypes.push(elementType);
29138+
}
29139+
}
29140+
});
29141+
// It's possible that zero contextual types are arraylike
29142+
if (contextualElementTypes.length > 1) {
29143+
return createArrayType(getIntersectionType(contextualElementTypes));
29144+
} else if (contextualElementTypes.length === 1) {
29145+
return createArrayType(contextualElementTypes);
29146+
}
29147+
}
2912429148
return createArrayLiteralType(createArrayType(elementTypes.length ?
2912529149
getUnionType(sameMap(elementTypes, (t, i) => elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessTypeOrUndefined(t, numberType) || anyType : t), UnionReduction.Subtype) :
2912629150
strictNullChecks ? implicitNeverType : undefinedWideningType, inConstContext));
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
tests/cases/compiler/APISample_jsdoc.ts(102,11): error TS2719: Type '(import("typescript").JSDocTag | undefined)[]' is not assignable to type '(import("typescript").JSDocTag | undefined)[]'. Two different types with this name exist, but they are unrelated.
2+
Type 'import("typescript").JSDocTag | undefined' is not assignable to type 'import("typescript").JSDocTag | undefined'. Two different types with this name exist, but they are unrelated.
3+
4+
5+
==== tests/cases/compiler/node_modules/typescript/package.json (0 errors) ====
6+
{
7+
"name": "typescript",
8+
"types": "/.ts/typescript.d.ts"
9+
}
10+
11+
==== tests/cases/compiler/APISample_jsdoc.ts (1 errors) ====
12+
/*
13+
* Note: This test is a public API sample. The original sources can be found
14+
* at: https://github.com/YousefED/typescript-json-schema
15+
* https://github.com/vega/ts-json-schema-generator
16+
* Please log a "breaking change" issue for any API breaking change affecting this issue
17+
*/
18+
19+
declare var console: any;
20+
21+
import * as ts from "typescript";
22+
23+
// excerpted from https://github.com/YousefED/typescript-json-schema
24+
// (converted from a method and modified; for example, `this: any` to compensate, among other changes)
25+
function parseCommentsIntoDefinition(this: any,
26+
symbol: ts.Symbol,
27+
definition: {description?: string, [s: string]: string | undefined},
28+
otherAnnotations: { [s: string]: true}): void {
29+
if (!symbol) {
30+
return;
31+
}
32+
33+
// the comments for a symbol
34+
let comments = symbol.getDocumentationComment(undefined);
35+
36+
if (comments.length) {
37+
definition.description = comments.map(comment => comment.kind === "lineBreak" ? comment.text : comment.text.trim().replace(/\r\n/g, "\n")).join("");
38+
}
39+
40+
// jsdocs are separate from comments
41+
const jsdocs = symbol.getJsDocTags(this.checker);
42+
jsdocs.forEach(doc => {
43+
// if we have @TJS-... annotations, we have to parse them
44+
const { name, text } = doc;
45+
if (this.userValidationKeywords[name]) {
46+
definition[name] = this.parseValue(text);
47+
} else {
48+
// special annotations
49+
otherAnnotations[doc.name] = true;
50+
}
51+
});
52+
}
53+
54+
55+
// excerpted from https://github.com/vega/ts-json-schema-generator
56+
export interface Annotations {
57+
[name: string]: any;
58+
}
59+
function getAnnotations(this: any, node: ts.Node): Annotations | undefined {
60+
const symbol: ts.Symbol = (node as any).symbol;
61+
if (!symbol) {
62+
return undefined;
63+
}
64+
65+
const jsDocTags: ts.JSDocTagInfo[] = symbol.getJsDocTags(this.checker);
66+
if (!jsDocTags || !jsDocTags.length) {
67+
return undefined;
68+
}
69+
70+
const annotations: Annotations = jsDocTags.reduce((result: Annotations, jsDocTag: ts.JSDocTagInfo) => {
71+
const value = this.parseJsDocTag(jsDocTag);
72+
if (value !== undefined) {
73+
result[jsDocTag.name] = value;
74+
}
75+
76+
return result;
77+
}, {});
78+
return Object.keys(annotations).length ? annotations : undefined;
79+
}
80+
81+
// these examples are artificial and mostly nonsensical
82+
function parseSpecificTags(node: ts.Node) {
83+
if (node.kind === ts.SyntaxKind.Parameter) {
84+
return ts.getJSDocParameterTags(node as ts.ParameterDeclaration);
85+
}
86+
if (node.kind === ts.SyntaxKind.FunctionDeclaration) {
87+
const func = node as ts.FunctionDeclaration;
88+
if (ts.hasJSDocParameterTags(func)) {
89+
const flat: ts.JSDocTag[] = [];
90+
for (const tags of func.parameters.map(ts.getJSDocParameterTags)) {
91+
if (tags) flat.push(...tags);
92+
}
93+
return flat;
94+
}
95+
}
96+
}
97+
98+
function getReturnTypeFromJSDoc(node: ts.Node) {
99+
if (node.kind === ts.SyntaxKind.FunctionDeclaration) {
100+
return ts.getJSDocReturnType(node);
101+
}
102+
let type = ts.getJSDocType(node);
103+
if (type && type.kind === ts.SyntaxKind.FunctionType) {
104+
return (type as ts.FunctionTypeNode).type;
105+
}
106+
}
107+
108+
function getAllTags(node: ts.Node) {
109+
ts.getJSDocTags(node);
110+
}
111+
112+
function getSomeOtherTags(node: ts.Node) {
113+
const tags: (ts.JSDocTag | undefined)[] = [];
114+
~~~~
115+
!!! error TS2719: Type '(import("typescript").JSDocTag | undefined)[]' is not assignable to type '(import("typescript").JSDocTag | undefined)[]'. Two different types with this name exist, but they are unrelated.
116+
!!! error TS2719: Type 'import("typescript").JSDocTag | undefined' is not assignable to type 'import("typescript").JSDocTag | undefined'. Two different types with this name exist, but they are unrelated.
117+
tags.push(ts.getJSDocAugmentsTag(node));
118+
tags.push(ts.getJSDocClassTag(node));
119+
tags.push(ts.getJSDocReturnTag(node));
120+
const type = ts.getJSDocTypeTag(node);
121+
if (type) {
122+
tags.push(type);
123+
}
124+
tags.push(ts.getJSDocTemplateTag(node));
125+
return tags;
126+
}
127+

tests/baselines/reference/accessorsOverrideProperty9.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ApiItem {
2020
>members : readonly ApiItem[]
2121

2222
return [];
23-
>[] : never[]
23+
>[] : ApiItem[]
2424
}
2525
}
2626

@@ -63,7 +63,7 @@ function ApiItemContainerMixin<TBaseClass extends IApiItemConstructor>(
6363
>members : readonly ApiItem[]
6464

6565
return [];
66-
>[] : never[]
66+
>[] : ApiItem[]
6767
}
6868
}
6969

@@ -83,7 +83,7 @@ export class ApiEnum extends ApiItemContainerMixin(ApiItem) {
8383
>members : readonly ApiEnumMember[]
8484

8585
return [];
86-
>[] : never[]
86+
>[] : ApiEnumMember[]
8787
}
8888
}
8989

tests/baselines/reference/arrayAssignmentTest1.types

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,35 +81,35 @@ var f1 = function () { return new C1();}
8181

8282
var arr_any: any[] = [];
8383
>arr_any : any[]
84-
>[] : undefined[]
84+
>[] : any[]
8585

8686
var arr_i1: I1[] = [];
8787
>arr_i1 : I1[]
88-
>[] : undefined[]
88+
>[] : I1[]
8989

9090
var arr_c1: C1[] = [];
9191
>arr_c1 : C1[]
92-
>[] : undefined[]
92+
>[] : C1[]
9393

9494
var arr_c2: C2[] = [];
9595
>arr_c2 : C2[]
96-
>[] : undefined[]
96+
>[] : C2[]
9797

9898
var arr_i1_2: I1[] = [];
9999
>arr_i1_2 : I1[]
100-
>[] : undefined[]
100+
>[] : I1[]
101101

102102
var arr_c1_2: C1[] = [];
103103
>arr_c1_2 : C1[]
104-
>[] : undefined[]
104+
>[] : C1[]
105105

106106
var arr_c2_2: C2[] = [];
107107
>arr_c2_2 : C2[]
108-
>[] : undefined[]
108+
>[] : C2[]
109109

110110
var arr_c3: C3[] = [];
111111
>arr_c3 : C3[]
112-
>[] : undefined[]
112+
>[] : C3[]
113113

114114
var i1_error: I1 = []; // should be an error - is
115115
>i1_error : I1

tests/baselines/reference/arrayAssignmentTest2.types

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,35 +81,35 @@ var f1 = function () { return new C1();}
8181

8282
var arr_any: any[] = [];
8383
>arr_any : any[]
84-
>[] : undefined[]
84+
>[] : any[]
8585

8686
var arr_i1: I1[] = [];
8787
>arr_i1 : I1[]
88-
>[] : undefined[]
88+
>[] : I1[]
8989

9090
var arr_c1: C1[] = [];
9191
>arr_c1 : C1[]
92-
>[] : undefined[]
92+
>[] : C1[]
9393

9494
var arr_c2: C2[] = [];
9595
>arr_c2 : C2[]
96-
>[] : undefined[]
96+
>[] : C2[]
9797

9898
var arr_i1_2: I1[] = [];
9999
>arr_i1_2 : I1[]
100-
>[] : undefined[]
100+
>[] : I1[]
101101

102102
var arr_c1_2: C1[] = [];
103103
>arr_c1_2 : C1[]
104-
>[] : undefined[]
104+
>[] : C1[]
105105

106106
var arr_c2_2: C2[] = [];
107107
>arr_c2_2 : C2[]
108-
>[] : undefined[]
108+
>[] : C2[]
109109

110110
var arr_c3: C3[] = [];
111111
>arr_c3 : C3[]
112-
>[] : undefined[]
112+
>[] : C3[]
113113

114114
// "clean up error" occurs at this point
115115
arr_c3 = arr_c2_2; // should be an error - is

tests/baselines/reference/arrayAssignmentTest4.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var o1 = {one : 1};
3232

3333
var arr_any: any[] = [];
3434
>arr_any : any[]
35-
>[] : undefined[]
35+
>[] : any[]
3636

3737
arr_any = function () { return null;} // should be an error - is
3838
>arr_any = function () { return null;} : () => any

tests/baselines/reference/arrayConcat2.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
=== tests/cases/compiler/arrayConcat2.ts ===
22
var a: string[] = [];
33
>a : string[]
4-
>[] : undefined[]
4+
>[] : string[]
55

66
a.concat("hello", 'world');
77
>a.concat("hello", 'world') : string[]
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
tests/cases/compiler/arrayContextualTyping.ts(9,9): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
2+
Type 'string' is not assignable to type 'number'.
3+
tests/cases/compiler/arrayContextualTyping.ts(14,11): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
4+
Type 'number' is not assignable to type 'string'.
5+
6+
7+
==== tests/cases/compiler/arrayContextualTyping.ts (2 errors) ====
8+
// Setup
9+
declare class MyCustomArray extends Array<number> {
10+
isCustom: true;
11+
}
12+
13+
// MVP: An empty array contextually typed by an array type gets that array's type
14+
const m1 = [] satisfies number[];
15+
m1.push(0); // Should be OK
16+
m1.push(""); // Should error
17+
~~
18+
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
19+
!!! error TS2345: Type 'string' is not assignable to type 'number'.
20+
21+
// Works in object fields?
22+
const m2 = { a: [] satisfies string[] };
23+
m2.a.push(""); // Should be OK
24+
m2.a.push(0); // Should error
25+
~
26+
!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
27+
!!! error TS2345: Type 'number' is not assignable to type 'string'.
28+
29+
// If the contextual type is a union, keep the array-supertyping parts of the union
30+
const m3 = [] satisfies number[] | ArrayLike<string>;
31+
const m3t: number[] | string[] = m3;
32+
33+
// Keep only the array parts
34+
const m4 = [] satisfies MyCustomArray | string[];
35+
const m4t: string[] = m4;
36+
37+
// Should OK
38+
const m5: string[] | number[] = [] satisfies string[] | number[];
39+
// Should OK
40+
type Obj = { a: string[] } | { a: number[] };
41+
const m6: Obj = { a: [] } satisfies Obj;
42+
43+
// Should all OK
44+
type DiscrObj = { a: string[], kind: "strings" } | { a: number[], kind: "numbers" };
45+
const m7: DiscrObj = { a: [], kind: "numbers"};
46+
const m8: DiscrObj = { a: [], kind: "numbers"} satisfies DiscrObj;
47+
const m9: DiscrObj = { a: [], kind: "strings"} satisfies DiscrObj;
48+

0 commit comments

Comments
 (0)