Skip to content

Commit 9be853f

Browse files
authored
Merge pull request #13487 from Microsoft/genericDefaults
Adds support for type parameter defaults
2 parents f4175c0 + 23216f9 commit 9be853f

File tree

58 files changed

+11499
-2054
lines changed

Some content is hidden

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

58 files changed

+11499
-2054
lines changed

src/compiler/checker.ts

+246-67
Large diffs are not rendered by default.

src/compiler/declarationEmitter.ts

+17
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,23 @@ namespace ts {
10101010
emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.constraint, getTypeParameterConstraintVisibilityError);
10111011
}
10121012
}
1013+
if (node.default && !isPrivateMethodTypeParameter(node)) {
1014+
write(" = ");
1015+
if (node.parent.kind === SyntaxKind.FunctionType ||
1016+
node.parent.kind === SyntaxKind.ConstructorType ||
1017+
(node.parent.parent && node.parent.parent.kind === SyntaxKind.TypeLiteral)) {
1018+
Debug.assert(node.parent.kind === SyntaxKind.MethodDeclaration ||
1019+
node.parent.kind === SyntaxKind.MethodSignature ||
1020+
node.parent.kind === SyntaxKind.FunctionType ||
1021+
node.parent.kind === SyntaxKind.ConstructorType ||
1022+
node.parent.kind === SyntaxKind.CallSignature ||
1023+
node.parent.kind === SyntaxKind.ConstructSignature);
1024+
emitType(node.default);
1025+
}
1026+
else {
1027+
emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.default, getTypeParameterConstraintVisibilityError);
1028+
}
1029+
}
10131030

10141031
function getTypeParameterConstraintVisibilityError(): SymbolAccessibilityDiagnostic {
10151032
// Type parameter constraints are named by user so we should always be able to name it

src/compiler/diagnosticMessages.json

+8
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,14 @@
20592059
"category": "Error",
20602060
"code": 2705
20612061
},
2062+
"Required type parameters may not follow optional type parameters.": {
2063+
"category": "Error",
2064+
"code": 2706
2065+
},
2066+
"Generic type '{0}' requires between {1} and {2} type arguments.": {
2067+
"category": "Error",
2068+
"code": 2707
2069+
},
20622070

20632071
"Import declaration '{0}' is using private name '{1}'.": {
20642072
"category": "Error",

src/compiler/parser.ts

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ namespace ts {
6666
case SyntaxKind.TypeParameter:
6767
return visitNode(cbNode, (<TypeParameterDeclaration>node).name) ||
6868
visitNode(cbNode, (<TypeParameterDeclaration>node).constraint) ||
69+
visitNode(cbNode, (<TypeParameterDeclaration>node).default) ||
6970
visitNode(cbNode, (<TypeParameterDeclaration>node).expression);
7071
case SyntaxKind.ShorthandPropertyAssignment:
7172
return visitNodes(cbNodes, node.decorators) ||
@@ -2102,6 +2103,10 @@ namespace ts {
21022103
}
21032104
}
21042105

2106+
if (parseOptional(SyntaxKind.EqualsToken)) {
2107+
node.default = parseType();
2108+
}
2109+
21052110
return finishNode(node);
21062111
}
21072112

src/compiler/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@
624624
kind: SyntaxKind.TypeParameter;
625625
name: Identifier;
626626
constraint?: TypeNode;
627+
default?: TypeNode;
627628

628629
// For error recovery purposes.
629630
expression?: Expression;
@@ -2736,6 +2737,7 @@
27362737
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
27372738
resolvedExports?: SymbolTable; // Resolved exports of module
27382739
exportsChecked?: boolean; // True if exports of external module have been checked
2740+
typeParametersChecked?: boolean; // True if type parameters of merged class and interface declarations have been checked.
27392741
isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration
27402742
bindingElement?: BindingElement; // Binding element associated with property symbol
27412743
exportsSomeValue?: boolean; // True if module exports some value (not just types)
@@ -3060,12 +3062,15 @@
30603062
// Type parameters (TypeFlags.TypeParameter)
30613063
export interface TypeParameter extends TypeVariable {
30623064
constraint: Type; // Constraint
3065+
default?: Type;
30633066
/* @internal */
30643067
target?: TypeParameter; // Instantiation target
30653068
/* @internal */
30663069
mapper?: TypeMapper; // Instantiation mapper
30673070
/* @internal */
30683071
isThisType?: boolean;
3072+
/* @internal */
3073+
resolvedDefaultType?: Type;
30693074
}
30703075

30713076
// Indexed access types (TypeFlags.IndexedAccess)

src/compiler/utilities.ts

+14
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ namespace ts {
2424
return undefined;
2525
}
2626

27+
export function findDeclaration<T extends Declaration>(symbol: Symbol, predicate: (node: Declaration) => node is T): T | undefined;
28+
export function findDeclaration(symbol: Symbol, predicate: (node: Declaration) => boolean): Declaration | undefined;
29+
export function findDeclaration(symbol: Symbol, predicate: (node: Declaration) => boolean): Declaration | undefined {
30+
const declarations = symbol.declarations;
31+
if (declarations) {
32+
for (const declaration of declarations) {
33+
if (predicate(declaration)) {
34+
return declaration;
35+
}
36+
}
37+
}
38+
return undefined;
39+
}
40+
2741
export interface StringSymbolWriter extends SymbolWriter {
2842
string(): string;
2943
}

src/lib/es2015.promise.d.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
interface PromiseConstructor {
32
/**
43
* A reference to the prototype.

src/lib/es5.d.ts

+3-66
Original file line numberDiff line numberDiff line change
@@ -1310,39 +1310,7 @@ interface PromiseLike<T> {
13101310
* @param onrejected The callback to execute when the Promise is rejected.
13111311
* @returns A Promise for the completion of which ever callback is executed.
13121312
*/
1313-
then(
1314-
onfulfilled?: ((value: T) => T | PromiseLike<T>) | undefined | null,
1315-
onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): PromiseLike<T>;
1316-
1317-
/**
1318-
* Attaches callbacks for the resolution and/or rejection of the Promise.
1319-
* @param onfulfilled The callback to execute when the Promise is resolved.
1320-
* @param onrejected The callback to execute when the Promise is rejected.
1321-
* @returns A Promise for the completion of which ever callback is executed.
1322-
*/
1323-
then<TResult>(
1324-
onfulfilled: ((value: T) => T | PromiseLike<T>) | undefined | null,
1325-
onrejected: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<T | TResult>;
1326-
1327-
/**
1328-
* Attaches callbacks for the resolution and/or rejection of the Promise.
1329-
* @param onfulfilled The callback to execute when the Promise is resolved.
1330-
* @param onrejected The callback to execute when the Promise is rejected.
1331-
* @returns A Promise for the completion of which ever callback is executed.
1332-
*/
1333-
then<TResult>(
1334-
onfulfilled: (value: T) => TResult | PromiseLike<TResult>,
1335-
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): PromiseLike<TResult>;
1336-
1337-
/**
1338-
* Attaches callbacks for the resolution and/or rejection of the Promise.
1339-
* @param onfulfilled The callback to execute when the Promise is resolved.
1340-
* @param onrejected The callback to execute when the Promise is rejected.
1341-
* @returns A Promise for the completion of which ever callback is executed.
1342-
*/
1343-
then<TResult1, TResult2>(
1344-
onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>,
1345-
onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>;
1313+
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;
13461314
}
13471315

13481316
/**
@@ -1355,45 +1323,14 @@ interface Promise<T> {
13551323
* @param onrejected The callback to execute when the Promise is rejected.
13561324
* @returns A Promise for the completion of which ever callback is executed.
13571325
*/
1358-
then(onfulfilled?: ((value: T) => T | PromiseLike<T>) | undefined | null, onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): Promise<T>;
1359-
1360-
/**
1361-
* Attaches callbacks for the resolution and/or rejection of the Promise.
1362-
* @param onfulfilled The callback to execute when the Promise is resolved.
1363-
* @param onrejected The callback to execute when the Promise is rejected.
1364-
* @returns A Promise for the completion of which ever callback is executed.
1365-
*/
1366-
then<TResult>(onfulfilled: ((value: T) => T | PromiseLike<T>) | undefined | null, onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
1367-
1368-
/**
1369-
* Attaches callbacks for the resolution and/or rejection of the Promise.
1370-
* @param onfulfilled The callback to execute when the Promise is resolved.
1371-
* @param onrejected The callback to execute when the Promise is rejected.
1372-
* @returns A Promise for the completion of which ever callback is executed.
1373-
*/
1374-
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>, onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<TResult>;
1375-
1376-
/**
1377-
* Attaches callbacks for the resolution and/or rejection of the Promise.
1378-
* @param onfulfilled The callback to execute when the Promise is resolved.
1379-
* @param onrejected The callback to execute when the Promise is rejected.
1380-
* @returns A Promise for the completion of which ever callback is executed.
1381-
*/
1382-
then<TResult1, TResult2>(onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2>;
1383-
1384-
/**
1385-
* Attaches a callback for only the rejection of the Promise.
1386-
* @param onrejected The callback to execute when the Promise is rejected.
1387-
* @returns A Promise for the completion of the callback.
1388-
*/
1389-
catch(onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): Promise<T>;
1326+
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
13901327

13911328
/**
13921329
* Attaches a callback for only the rejection of the Promise.
13931330
* @param onrejected The callback to execute when the Promise is rejected.
13941331
* @returns A Promise for the completion of the callback.
13951332
*/
1396-
catch<TResult>(onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
1333+
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
13971334
}
13981335

13991336
interface ArrayLike<T> {

src/services/services.ts

+1
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ namespace ts {
397397
parameters: Symbol[];
398398
thisParameter: Symbol;
399399
resolvedReturnType: Type;
400+
minTypeArgumentCount: number;
400401
minArgumentCount: number;
401402
hasRestParameter: boolean;
402403
hasLiteralTypes: boolean;

tests/baselines/reference/asyncFunctionDeclaration15_es5.errors.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration1
66
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration15_es5.ts(10,23): error TS1055: Type 'typeof Thenable' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.
77
Type 'Thenable' is not assignable to type 'PromiseLike<any>'.
88
Types of property 'then' are incompatible.
9-
Type '() => void' is not assignable to type '{ (onfulfilled?: (value: any) => any, onrejected?: (reason: any) => any): PromiseLike<any>; <TResult>(onfulfilled: (value: any) => any, onrejected: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<any>; <TResult>(onfulfilled: (value: any) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>; <TResult1, TResult2>(onfulfilled: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>; }'.
9+
Type '() => void' is not assignable to type '<TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => PromiseLike<TResult1 | TResult2>'.
1010
Type 'void' is not assignable to type 'PromiseLike<any>'.
1111
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration15_es5.ts(17,16): error TS1059: Return expression in async function does not have a valid callable 'then' member.
1212
tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration15_es5.ts(23,25): error TS1058: Operand for 'await' does not have a valid callable 'then' member.
@@ -37,7 +37,7 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration1
3737
!!! error TS1055: Type 'typeof Thenable' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.
3838
!!! error TS1055: Type 'Thenable' is not assignable to type 'PromiseLike<any>'.
3939
!!! error TS1055: Types of property 'then' are incompatible.
40-
!!! error TS1055: Type '() => void' is not assignable to type '{ (onfulfilled?: (value: any) => any, onrejected?: (reason: any) => any): PromiseLike<any>; <TResult>(onfulfilled: (value: any) => any, onrejected: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<any>; <TResult>(onfulfilled: (value: any) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>; <TResult1, TResult2>(onfulfilled: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>; }'.
40+
!!! error TS1055: Type '() => void' is not assignable to type '<TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => PromiseLike<TResult1 | TResult2>'.
4141
!!! error TS1055: Type 'void' is not assignable to type 'PromiseLike<any>'.
4242
async function fn7() { return; } // valid: Promise<void>
4343
async function fn8() { return 1; } // valid: Promise<number>

tests/baselines/reference/constructSignaturesWithOverloads2.errors.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
tests/cases/conformance/types/objectTypeLiteral/constructSignatures/constructSignaturesWithOverloads2.ts(27,11): error TS2428: All declarations of 'I' must have identical type parameters.
12
tests/cases/conformance/types/objectTypeLiteral/constructSignatures/constructSignaturesWithOverloads2.ts(32,11): error TS2428: All declarations of 'I' must have identical type parameters.
23

34

4-
==== tests/cases/conformance/types/objectTypeLiteral/constructSignatures/constructSignaturesWithOverloads2.ts (1 errors) ====
5+
==== tests/cases/conformance/types/objectTypeLiteral/constructSignatures/constructSignaturesWithOverloads2.ts (2 errors) ====
56
// No errors expected for basic overloads of construct signatures with merged declarations
67

78
// clodules
@@ -29,6 +30,8 @@ tests/cases/conformance/types/objectTypeLiteral/constructSignatures/constructSig
2930

3031
// merged interfaces
3132
interface I {
33+
~
34+
!!! error TS2428: All declarations of 'I' must have identical type parameters.
3235
new (x: number, y?: string): C;
3336
new (x: number, y: string): C;
3437
}

tests/baselines/reference/extendedInterfacesWithDuplicateTypeParameters.errors.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
tests/cases/compiler/extendedInterfacesWithDuplicateTypeParameters.ts(1,42): error TS2300: Duplicate identifier 'A'.
2+
tests/cases/compiler/extendedInterfacesWithDuplicateTypeParameters.ts(5,11): error TS2428: All declarations of 'InterfaceWithSomeTypars' must have identical type parameters.
23
tests/cases/compiler/extendedInterfacesWithDuplicateTypeParameters.ts(9,11): error TS2428: All declarations of 'InterfaceWithSomeTypars' must have identical type parameters.
34
tests/cases/compiler/extendedInterfacesWithDuplicateTypeParameters.ts(9,38): error TS2300: Duplicate identifier 'C'.
45

56

6-
==== tests/cases/compiler/extendedInterfacesWithDuplicateTypeParameters.ts (3 errors) ====
7+
==== tests/cases/compiler/extendedInterfacesWithDuplicateTypeParameters.ts (4 errors) ====
78
interface InterfaceWithMultipleTypars<A, A> { // should error
89
~
910
!!! error TS2300: Duplicate identifier 'A'.
1011
bar(): void;
1112
}
1213

1314
interface InterfaceWithSomeTypars<B> { // should not error
15+
~~~~~~~~~~~~~~~~~~~~~~~
16+
!!! error TS2428: All declarations of 'InterfaceWithSomeTypars' must have identical type parameters.
1417
bar(): void;
1518
}
1619

tests/baselines/reference/genericAndNonGenericInterfaceWithTheSameName.errors.txt

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1+
tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterfaceWithTheSameName.ts(3,11): error TS2428: All declarations of 'A' must have identical type parameters.
12
tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterfaceWithTheSameName.ts(7,11): error TS2428: All declarations of 'A' must have identical type parameters.
3+
tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterfaceWithTheSameName.ts(12,15): error TS2428: All declarations of 'A' must have identical type parameters.
24
tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterfaceWithTheSameName.ts(16,15): error TS2428: All declarations of 'A' must have identical type parameters.
5+
tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterfaceWithTheSameName.ts(34,22): error TS2428: All declarations of 'A' must have identical type parameters.
36
tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterfaceWithTheSameName.ts(40,22): error TS2428: All declarations of 'A' must have identical type parameters.
47

58

6-
==== tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterfaceWithTheSameName.ts (3 errors) ====
9+
==== tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterfaceWithTheSameName.ts (6 errors) ====
710
// generic and non-generic interfaces with the same name do not merge
811

912
interface A {
13+
~
14+
!!! error TS2428: All declarations of 'A' must have identical type parameters.
1015
foo: string;
1116
}
1217

@@ -18,6 +23,8 @@ tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterf
1823

1924
module M {
2025
interface A<T> {
26+
~
27+
!!! error TS2428: All declarations of 'A' must have identical type parameters.
2128
bar: T;
2229
}
2330

@@ -42,6 +49,8 @@ tests/cases/conformance/interfaces/declarationMerging/genericAndNonGenericInterf
4249

4350
module M3 {
4451
export interface A {
52+
~
53+
!!! error TS2428: All declarations of 'A' must have identical type parameters.
4554
foo: string;
4655
}
4756
}

0 commit comments

Comments
 (0)