From bf4f6677b984996dfcb5747cd755d7e27e3b881b Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Fri, 1 Jan 2016 18:02:30 -0800 Subject: [PATCH 1/2] Generic default type parameters --- src/compiler/checker.ts | 103 ++++++++-- src/compiler/diagnosticMessages.json | 8 + src/compiler/parser.ts | 5 + src/compiler/types.ts | 2 + .../typeParameterCircularDefault.errors.txt | 99 ++++++++++ .../reference/typeParameterCircularDefault.js | 94 +++++++++ .../reference/typeParameterDefaults.js | 128 +++++++++++++ .../reference/typeParameterDefaults.symbols | 153 +++++++++++++++ .../reference/typeParameterDefaults.types | 178 ++++++++++++++++++ .../typeParameterDefaultsErrors.errors.txt | 42 +++++ .../reference/typeParameterDefaultsErrors.js | 41 ++++ .../typeParameterCircularDefault.ts | 47 +++++ .../typeParameters/typeParameterDefaults.js | 46 +++++ .../typeParameters/typeParameterDefaults.ts | 58 ++++++ .../typeParameterDefaultsErrors.ts | 29 +++ 15 files changed, 1021 insertions(+), 12 deletions(-) create mode 100644 tests/baselines/reference/typeParameterCircularDefault.errors.txt create mode 100644 tests/baselines/reference/typeParameterCircularDefault.js create mode 100644 tests/baselines/reference/typeParameterDefaults.js create mode 100644 tests/baselines/reference/typeParameterDefaults.symbols create mode 100644 tests/baselines/reference/typeParameterDefaults.types create mode 100644 tests/baselines/reference/typeParameterDefaultsErrors.errors.txt create mode 100644 tests/baselines/reference/typeParameterDefaultsErrors.js create mode 100644 tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts create mode 100644 tests/cases/conformance/types/typeParameters/typeParameterDefaults.js create mode 100644 tests/cases/conformance/types/typeParameters/typeParameterDefaults.ts create mode 100644 tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5d57e9d202874..7ee62201c0e91 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -124,6 +124,7 @@ namespace ts { anyFunctionType.flags |= TypeFlags.ContainsAnyFunctionType; const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + const noDefaultType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); @@ -2938,10 +2939,25 @@ namespace ts { return getClassExtendsHeritageClauseElement(type.symbol.valueDeclaration); } + function getRequiredTypeArgumentCount(typeParameters: TypeParameter[]) { + if (typeParameters) { + for (let i = typeParameters.length - 1; i >= 0; i--) { + if (!typeParameters[i].default) { + return i + 1; + } + } + } + return 0; + } + + function getMaximumTypeArgumentCount(typeParameters: TypeParameter[]) { + return typeParameters ? typeParameters.length : 0; + } + function getConstructorsForTypeArguments(type: ObjectType, typeArgumentNodes: TypeNode[]): Signature[] { const typeArgCount = typeArgumentNodes ? typeArgumentNodes.length : 0; return filter(getSignaturesOfType(type, SignatureKind.Construct), - sig => (sig.typeParameters ? sig.typeParameters.length : 0) === typeArgCount); + sig => typeArgCount >= getRequiredTypeArgumentCount(sig.typeParameters) && typeArgCount <= getMaximumTypeArgumentCount(sig.typeParameters)); } function getInstantiatedConstructorsForTypeArguments(type: ObjectType, typeArgumentNodes: TypeNode[]): Signature[] { @@ -3188,9 +3204,24 @@ namespace ts { if (!links.declaredType) { const type = createType(TypeFlags.TypeParameter); type.symbol = symbol; - if (!(getDeclarationOfKind(symbol, SyntaxKind.TypeParameter)).constraint) { + const declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter); + if (!declaration.constraint) { type.constraint = noConstraintType; } + const defaultType = forEach(symbol.declarations, decl => (decl.kind === SyntaxKind.TypeParameter) && (decl).default); + if (defaultType) { + if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) { + type.default = unknownType; + } + else { + type.default = getTypeOfNode(defaultType); + } + + if (!popTypeResolution()) { + error(symbol.declarations[0], Diagnostics.Type_parameter_0_has_a_circular_default, type.symbol.name); + } + } + symbol.declarations.forEach links.declaredType = type; } return links.declaredType; @@ -3416,13 +3447,17 @@ namespace ts { return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; } const baseTypeNode = getBaseTypeNodeOfClass(classType); - const typeArguments = map(baseTypeNode.typeArguments, getTypeFromTypeNode); + let typeArguments = map(baseTypeNode.typeArguments, getTypeFromTypeNode); const typeArgCount = typeArguments ? typeArguments.length : 0; const result: Signature[] = []; for (const baseSig of baseSignatures) { - const typeParamCount = baseSig.typeParameters ? baseSig.typeParameters.length : 0; - if (typeParamCount === typeArgCount) { - const sig = typeParamCount ? getSignatureInstantiation(baseSig, typeArguments) : cloneSignature(baseSig); + const minTypeParamCount = getRequiredTypeArgumentCount(baseSig.typeParameters); + const maxTypeParamCount = getMaximumTypeArgumentCount(baseSig.typeParameters); + if (typeArgCount >= minTypeParamCount && typeArgCount <= maxTypeParamCount) { + for (let i = typeArgCount; i < maxTypeParamCount; i++) { + (typeArguments = typeArguments || []).push(baseSig.typeParameters[i].default); + } + const sig = typeArgCount ? getSignatureInstantiation(baseSig, typeArguments) : cloneSignature(baseSig); sig.typeParameters = classType.localTypeParameters; sig.resolvedReturnType = classType; result.push(sig); @@ -4185,19 +4220,44 @@ namespace ts { return type; } + function checkTypeArgumentArity(typeParameters: TypeParameter[], typeArguments: NodeArray): boolean { + if (typeArguments && (typeArguments.length > typeParameters.length)) { + return false; + } + else { + for (let i = (typeArguments && typeArguments.length) || 0; i < typeParameters.length; i++) { + if (!typeParameters[i].default) { + return false; + } + } + } + return true; + } + // Get type from reference to class or interface function getTypeFromClassOrInterfaceReference(node: TypeReferenceNode | ExpressionWithTypeArguments, symbol: Symbol): Type { const type = getDeclaredTypeOfSymbol(symbol); const typeParameters = type.localTypeParameters; if (typeParameters) { - if (!node.typeArguments || node.typeArguments.length !== typeParameters.length) { - error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length); + if (!checkTypeArgumentArity(typeParameters, node.typeArguments)) { + const minArgCount = getRequiredTypeArgumentCount(typeParameters); + const maxArgCount = getMaximumTypeArgumentCount(typeParameters); + error(node, + minArgCount === maxArgCount ? Diagnostics.Generic_type_0_requires_1_type_argument_s : Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments, + typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), + minArgCount, + maxArgCount); return unknownType; } + const typeArguments = concatenate(type.outerTypeParameters, map(node.typeArguments, getTypeFromTypeNode)) || []; + for (let i = (typeArguments && typeArguments.length) || 0; i < typeParameters.length; i++) { + typeArguments.push(typeParameters[i].default); + } + // In a type reference, the outer type parameters of the referenced class or interface are automatically // supplied as type arguments and the type reference only specifies arguments for the local type parameters // of the class or interface. - return createTypeReference(type, concatenate(type.outerTypeParameters, map(node.typeArguments, getTypeFromTypeNode))); + return createTypeReference(type, typeArguments); } if (node.typeArguments) { error(node, Diagnostics.Type_0_is_not_generic, typeToString(type)); @@ -4214,7 +4274,8 @@ namespace ts { const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters; if (typeParameters) { - if (!node.typeArguments || node.typeArguments.length !== typeParameters.length) { + if (!checkTypeArgumentArity(typeParameters, node.typeArguments)) { + debugger; error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, symbolToString(symbol), typeParameters.length); return unknownType; } @@ -6424,11 +6485,11 @@ namespace ts { inferenceSucceeded = !!unionOrSuperType; } else { - // Infer the empty object type when no inferences were made. It is important to remember that + // Infer the default, or the empty object type, when no inferences were made. It is important to remember that // in this case, inference still succeeds, meaning there is no error for not having inference // candidates. An inference error only occurs when there are *conflicting* candidates, i.e. // candidates with no common supertype. - inferredType = emptyObjectType; + inferredType = context.typeParameters[index].default || emptyObjectType; inferenceSucceeded = true; } context.inferredTypes[index] = inferredType; @@ -11075,6 +11136,10 @@ namespace ts { } checkSourceElement(node.constraint); + if(node.default) { + checkSourceElement(node.default); + } + getConstraintOfTypeParameter(getDeclaredTypeOfTypeParameter(getSymbolOfNode(node))); if (produceDiagnostics) { checkTypeNameIsReserved(node.name, Diagnostics.Type_parameter_name_cannot_be_0); @@ -11537,6 +11602,7 @@ namespace ts { Diagnostics.Type_0_does_not_satisfy_the_constraint_1); } } + if(!result) debugger; return result; } @@ -13460,13 +13526,25 @@ namespace ts { } // Check each type parameter and check that list has no duplicate type parameter declarations + // and no required parameters after optional parameters and no forward references to other + // type parameters in defaults function checkTypeParameters(typeParameterDeclarations: TypeParameterDeclaration[]) { if (typeParameterDeclarations) { + let seenDefault = false; for (let i = 0, n = typeParameterDeclarations.length; i < n; i++) { const node = typeParameterDeclarations[i]; checkTypeParameter(node); if (produceDiagnostics) { + if (seenDefault) { + if (!node.default) { + error(node, Diagnostics.Required_type_parameters_may_not_follow_optional_type_parameters); + } + } + else { + seenDefault = !!node.default; + } + for (let j = 0; j < i; j++) { if (typeParameterDeclarations[j].symbol === node.symbol) { error(node.name, Diagnostics.Duplicate_identifier_0, declarationNameToString(node.name)); @@ -13496,6 +13574,7 @@ namespace ts { } function checkClassLikeDeclaration(node: ClassLikeDeclaration) { + debugger; checkGrammarClassDeclarationHeritageClauses(node); checkDecorators(node); if (node.name) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a43f3534df6b5..3d2fa6541edb9 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1771,6 +1771,14 @@ "category": "Error", "code": 2660 }, + "Required type parameters may not follow optional type parameters": { + "category": "Error", + "code": 2661 + }, + "Type parameter '{0}' has a circular default.": { + "category": "Error", + "code": 2662 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", "code": 4000 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7f5d052a7e719..2735f964893e8 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -59,6 +59,7 @@ namespace ts { case SyntaxKind.TypeParameter: return visitNode(cbNode, (node).name) || visitNode(cbNode, (node).constraint) || + visitNode(cbNode, (node).default) || visitNode(cbNode, (node).expression); case SyntaxKind.ShorthandPropertyAssignment: return visitNodes(cbNodes, node.decorators) || @@ -2005,6 +2006,10 @@ namespace ts { } } + if (parseOptional(SyntaxKind.EqualsToken)) { + node.default = parseType(); + } + return finishNode(node); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 24f70373a8ace..bfa3b3a8ba16c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -538,6 +538,7 @@ namespace ts { export interface TypeParameterDeclaration extends Declaration { name: Identifier; constraint?: TypeNode; + default?: TypeNode; // For error recovery purposes. expression?: Expression; @@ -2248,6 +2249,7 @@ namespace ts { // Type parameters (TypeFlags.TypeParameter) export interface TypeParameter extends Type { constraint: Type; // Constraint + default?: Type; /* @internal */ target?: TypeParameter; // Instantiation target /* @internal */ diff --git a/tests/baselines/reference/typeParameterCircularDefault.errors.txt b/tests/baselines/reference/typeParameterCircularDefault.errors.txt new file mode 100644 index 0000000000000..cb30743f28fc8 --- /dev/null +++ b/tests/baselines/reference/typeParameterCircularDefault.errors.txt @@ -0,0 +1,99 @@ +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(4,14): error TS2662: Type parameter 'T' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(4,21): error TS2662: Type parameter 'U' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(7,14): error TS2662: Type parameter 'T' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(10,14): error TS2662: Type parameter 'T' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(16,14): error TS2662: Type parameter 'T' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(16,21): error TS2662: Type parameter 'U' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(16,28): error TS2662: Type parameter 'V' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(28,10): error TS2662: Type parameter 'T' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(28,17): error TS2662: Type parameter 'U' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(31,10): error TS2662: Type parameter 'T' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(34,10): error TS2662: Type parameter 'T' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(40,10): error TS2662: Type parameter 'T' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(40,17): error TS2662: Type parameter 'U' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(40,24): error TS2662: Type parameter 'V' has a circular default. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(43,5): error TS2502: 'p' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts(45,10): error TS2662: Type parameter 'T' has a circular default. + + +==== tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts (16 errors) ==== + /** Interfaces **/ + + // Two-way circular + interface I1 { } + ~~~~~ +!!! error TS2662: Type parameter 'T' has a circular default. + ~~~~~ +!!! error TS2662: Type parameter 'U' has a circular default. + + // Self-circular + interface I2 { } + ~~~~~ +!!! error TS2662: Type parameter 'T' has a circular default. + + // Wrapped circular + interface I3> { } + ~~~~~~~~~~~~ +!!! error TS2662: Type parameter 'T' has a circular default. + + // OK, I guess? + interface I4 { } + + // Three-way circular + interface I5 { } + ~~~~~ +!!! error TS2662: Type parameter 'T' has a circular default. + ~~~~~ +!!! error TS2662: Type parameter 'U' has a circular default. + ~~~~~ +!!! error TS2662: Type parameter 'V' has a circular default. + + // Indirect through type query + var a: I6; + var b = p.x; + interface I6 { + x: T; + } + + + /** Classes **/ + // Two-way circular + class C1 { } + ~~~~~ +!!! error TS2662: Type parameter 'T' has a circular default. + ~~~~~ +!!! error TS2662: Type parameter 'U' has a circular default. + + // Self-circular + class C2 { } + ~~~~~ +!!! error TS2662: Type parameter 'T' has a circular default. + + // Wrapped circular + class C3> { } + ~~~~~~~~~~~~ +!!! error TS2662: Type parameter 'T' has a circular default. + + // OK, I guess? + class C4 { } + + // Three-way circular + class C5 { } + ~~~~~ +!!! error TS2662: Type parameter 'T' has a circular default. + ~~~~~ +!!! error TS2662: Type parameter 'U' has a circular default. + ~~~~~ +!!! error TS2662: Type parameter 'V' has a circular default. + + // Indirect through type query + var p: C6; + ~ +!!! error TS2502: 'p' is referenced directly or indirectly in its own type annotation. + var n = p.x; + class C6 { + ~~~~~~~~~~~~ +!!! error TS2662: Type parameter 'T' has a circular default. + x: T; + } + \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterCircularDefault.js b/tests/baselines/reference/typeParameterCircularDefault.js new file mode 100644 index 0000000000000..72522c580faab --- /dev/null +++ b/tests/baselines/reference/typeParameterCircularDefault.js @@ -0,0 +1,94 @@ +//// [typeParameterCircularDefault.ts] +/** Interfaces **/ + +// Two-way circular +interface I1 { } + +// Self-circular +interface I2 { } + +// Wrapped circular +interface I3> { } + +// OK, I guess? +interface I4 { } + +// Three-way circular +interface I5 { } + +// Indirect through type query +var a: I6; +var b = p.x; +interface I6 { + x: T; +} + + +/** Classes **/ +// Two-way circular +class C1 { } + +// Self-circular +class C2 { } + +// Wrapped circular +class C3> { } + +// OK, I guess? +class C4 { } + +// Three-way circular +class C5 { } + +// Indirect through type query +var p: C6; +var n = p.x; +class C6 { + x: T; +} + + +//// [typeParameterCircularDefault.js] +/** Interfaces **/ +// Indirect through type query +var a; +var b = p.x; +/** Classes **/ +// Two-way circular +var C1 = (function () { + function C1() { + } + return C1; +}()); +// Self-circular +var C2 = (function () { + function C2() { + } + return C2; +}()); +// Wrapped circular +var C3 = (function () { + function C3() { + } + return C3; +}()); +// OK, I guess? +var C4 = (function () { + function C4() { + } + return C4; +}()); +// Three-way circular +var C5 = (function () { + function C5() { + } + return C5; +}()); +// Indirect through type query +var p; +var n = p.x; +var C6 = (function () { + function C6() { + } + return C6; +}()); diff --git a/tests/baselines/reference/typeParameterDefaults.js b/tests/baselines/reference/typeParameterDefaults.js new file mode 100644 index 0000000000000..5ecc00938c3aa --- /dev/null +++ b/tests/baselines/reference/typeParameterDefaults.js @@ -0,0 +1,128 @@ +//// [typeParameterDefaults.ts] +/** Defaults on interfaces **/ +interface HasDefault1 { + x: T; +} +// OK +let a3: HasDefault1; +// a3.x: number +a3.x = 10; + +interface HasDefault2 { + x1: T1; + x2: T2; +} +// Same as +let a5: HasDefault2; +// a5.x1: string +a5.x1 = ''; +// a5.x2: number +a5.x2 = 42; + +let a6: HasDefault2; +// a6.x1: boolean, a6.x2: boolean +a6.x1 = true; +a6.x2 = false; + +/** Defaults on classes */ +class ClassDefault1 { + x: T; +} +let c1 = new ClassDefault1(); +// c1.x: number +c1.x = 10; + +class Derived1 extends ClassDefault1 { +} +let d1 = new Derived1(); +// d1.x: number +d1.x = 10; + +class Derived2 extends ClassDefault1 { +} +let d2a = new Derived2(); +// d2a.x: string +d2a.x = 'hello'; + +let d2b = new Derived2(); +// d2b.x: number +d2b.x = 43; + +class ClassDefault2 { + t: T; + u: U; +} +class Derived3 extends ClassDefault2 {} +let d3 = new Derived3(); +// d3.u: string +d3.u = ''; + + + +//// [typeParameterDefaults.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +// OK +var a3; +// a3.x: number +a3.x = 10; +// Same as +var a5; +// a5.x1: string +a5.x1 = ''; +// a5.x2: number +a5.x2 = 42; +var a6; +// a6.x1: boolean, a6.x2: boolean +a6.x1 = true; +a6.x2 = false; +/** Defaults on classes */ +var ClassDefault1 = (function () { + function ClassDefault1() { + } + return ClassDefault1; +}()); +var c1 = new ClassDefault1(); +// c1.x: number +c1.x = 10; +var Derived1 = (function (_super) { + __extends(Derived1, _super); + function Derived1() { + _super.apply(this, arguments); + } + return Derived1; +}(ClassDefault1)); +var d1 = new Derived1(); +// d1.x: number +d1.x = 10; +var Derived2 = (function (_super) { + __extends(Derived2, _super); + function Derived2() { + _super.apply(this, arguments); + } + return Derived2; +}(ClassDefault1)); +var d2a = new Derived2(); +// d2a.x: string +d2a.x = 'hello'; +var d2b = new Derived2(); +// d2b.x: number +d2b.x = 43; +var ClassDefault2 = (function () { + function ClassDefault2() { + } + return ClassDefault2; +}()); +var Derived3 = (function (_super) { + __extends(Derived3, _super); + function Derived3() { + _super.apply(this, arguments); + } + return Derived3; +}(ClassDefault2)); +var d3 = new Derived3(); +// d3.u: string +d3.u = ''; diff --git a/tests/baselines/reference/typeParameterDefaults.symbols b/tests/baselines/reference/typeParameterDefaults.symbols new file mode 100644 index 0000000000000..99758533a4a49 --- /dev/null +++ b/tests/baselines/reference/typeParameterDefaults.symbols @@ -0,0 +1,153 @@ +=== tests/cases/conformance/types/typeParameters/typeParameterDefaults.ts === +/** Defaults on interfaces **/ +interface HasDefault1 { +>HasDefault1 : Symbol(HasDefault1, Decl(typeParameterDefaults.ts, 0, 0)) +>T : Symbol(T, Decl(typeParameterDefaults.ts, 1, 22)) + + x: T; +>x : Symbol(x, Decl(typeParameterDefaults.ts, 1, 35)) +>T : Symbol(T, Decl(typeParameterDefaults.ts, 1, 22)) +} +// OK +let a3: HasDefault1; +>a3 : Symbol(a3, Decl(typeParameterDefaults.ts, 5, 3)) +>HasDefault1 : Symbol(HasDefault1, Decl(typeParameterDefaults.ts, 0, 0)) + +// a3.x: number +a3.x = 10; +>a3.x : Symbol(HasDefault1.x, Decl(typeParameterDefaults.ts, 1, 35)) +>a3 : Symbol(a3, Decl(typeParameterDefaults.ts, 5, 3)) +>x : Symbol(HasDefault1.x, Decl(typeParameterDefaults.ts, 1, 35)) + +interface HasDefault2 { +>HasDefault2 : Symbol(HasDefault2, Decl(typeParameterDefaults.ts, 7, 10)) +>T1 : Symbol(T1, Decl(typeParameterDefaults.ts, 9, 22)) +>T2 : Symbol(T2, Decl(typeParameterDefaults.ts, 9, 25)) + + x1: T1; +>x1 : Symbol(x1, Decl(typeParameterDefaults.ts, 9, 40)) +>T1 : Symbol(T1, Decl(typeParameterDefaults.ts, 9, 22)) + + x2: T2; +>x2 : Symbol(x2, Decl(typeParameterDefaults.ts, 10, 8)) +>T2 : Symbol(T2, Decl(typeParameterDefaults.ts, 9, 25)) +} +// Same as +let a5: HasDefault2; +>a5 : Symbol(a5, Decl(typeParameterDefaults.ts, 14, 3)) +>HasDefault2 : Symbol(HasDefault2, Decl(typeParameterDefaults.ts, 7, 10)) + +// a5.x1: string +a5.x1 = ''; +>a5.x1 : Symbol(HasDefault2.x1, Decl(typeParameterDefaults.ts, 9, 40)) +>a5 : Symbol(a5, Decl(typeParameterDefaults.ts, 14, 3)) +>x1 : Symbol(HasDefault2.x1, Decl(typeParameterDefaults.ts, 9, 40)) + +// a5.x2: number +a5.x2 = 42; +>a5.x2 : Symbol(HasDefault2.x2, Decl(typeParameterDefaults.ts, 10, 8)) +>a5 : Symbol(a5, Decl(typeParameterDefaults.ts, 14, 3)) +>x2 : Symbol(HasDefault2.x2, Decl(typeParameterDefaults.ts, 10, 8)) + +let a6: HasDefault2; +>a6 : Symbol(a6, Decl(typeParameterDefaults.ts, 20, 3)) +>HasDefault2 : Symbol(HasDefault2, Decl(typeParameterDefaults.ts, 7, 10)) + +// a6.x1: boolean, a6.x2: boolean +a6.x1 = true; +>a6.x1 : Symbol(HasDefault2.x1, Decl(typeParameterDefaults.ts, 9, 40)) +>a6 : Symbol(a6, Decl(typeParameterDefaults.ts, 20, 3)) +>x1 : Symbol(HasDefault2.x1, Decl(typeParameterDefaults.ts, 9, 40)) + +a6.x2 = false; +>a6.x2 : Symbol(HasDefault2.x2, Decl(typeParameterDefaults.ts, 10, 8)) +>a6 : Symbol(a6, Decl(typeParameterDefaults.ts, 20, 3)) +>x2 : Symbol(HasDefault2.x2, Decl(typeParameterDefaults.ts, 10, 8)) + +/** Defaults on classes */ +class ClassDefault1 { +>ClassDefault1 : Symbol(ClassDefault1, Decl(typeParameterDefaults.ts, 23, 14)) +>T : Symbol(T, Decl(typeParameterDefaults.ts, 26, 20)) + + x: T; +>x : Symbol(x, Decl(typeParameterDefaults.ts, 26, 33)) +>T : Symbol(T, Decl(typeParameterDefaults.ts, 26, 20)) +} +let c1 = new ClassDefault1(); +>c1 : Symbol(c1, Decl(typeParameterDefaults.ts, 29, 3)) +>ClassDefault1 : Symbol(ClassDefault1, Decl(typeParameterDefaults.ts, 23, 14)) + +// c1.x: number +c1.x = 10; +>c1.x : Symbol(ClassDefault1.x, Decl(typeParameterDefaults.ts, 26, 33)) +>c1 : Symbol(c1, Decl(typeParameterDefaults.ts, 29, 3)) +>x : Symbol(ClassDefault1.x, Decl(typeParameterDefaults.ts, 26, 33)) + +class Derived1 extends ClassDefault1 { +>Derived1 : Symbol(Derived1, Decl(typeParameterDefaults.ts, 31, 10)) +>ClassDefault1 : Symbol(ClassDefault1, Decl(typeParameterDefaults.ts, 23, 14)) +} +let d1 = new Derived1(); +>d1 : Symbol(d1, Decl(typeParameterDefaults.ts, 35, 3)) +>Derived1 : Symbol(Derived1, Decl(typeParameterDefaults.ts, 31, 10)) + +// d1.x: number +d1.x = 10; +>d1.x : Symbol(ClassDefault1.x, Decl(typeParameterDefaults.ts, 26, 33)) +>d1 : Symbol(d1, Decl(typeParameterDefaults.ts, 35, 3)) +>x : Symbol(ClassDefault1.x, Decl(typeParameterDefaults.ts, 26, 33)) + +class Derived2 extends ClassDefault1 { +>Derived2 : Symbol(Derived2, Decl(typeParameterDefaults.ts, 37, 10)) +>T : Symbol(T, Decl(typeParameterDefaults.ts, 39, 15)) +>ClassDefault1 : Symbol(ClassDefault1, Decl(typeParameterDefaults.ts, 23, 14)) +>T : Symbol(T, Decl(typeParameterDefaults.ts, 39, 15)) +} +let d2a = new Derived2(); +>d2a : Symbol(d2a, Decl(typeParameterDefaults.ts, 41, 3)) +>Derived2 : Symbol(Derived2, Decl(typeParameterDefaults.ts, 37, 10)) + +// d2a.x: string +d2a.x = 'hello'; +>d2a.x : Symbol(ClassDefault1.x, Decl(typeParameterDefaults.ts, 26, 33)) +>d2a : Symbol(d2a, Decl(typeParameterDefaults.ts, 41, 3)) +>x : Symbol(ClassDefault1.x, Decl(typeParameterDefaults.ts, 26, 33)) + +let d2b = new Derived2(); +>d2b : Symbol(d2b, Decl(typeParameterDefaults.ts, 45, 3)) +>Derived2 : Symbol(Derived2, Decl(typeParameterDefaults.ts, 37, 10)) + +// d2b.x: number +d2b.x = 43; +>d2b.x : Symbol(ClassDefault1.x, Decl(typeParameterDefaults.ts, 26, 33)) +>d2b : Symbol(d2b, Decl(typeParameterDefaults.ts, 45, 3)) +>x : Symbol(ClassDefault1.x, Decl(typeParameterDefaults.ts, 26, 33)) + +class ClassDefault2 { +>ClassDefault2 : Symbol(ClassDefault2, Decl(typeParameterDefaults.ts, 47, 11)) +>T : Symbol(T, Decl(typeParameterDefaults.ts, 49, 20)) +>U : Symbol(U, Decl(typeParameterDefaults.ts, 49, 22)) + + t: T; +>t : Symbol(t, Decl(typeParameterDefaults.ts, 49, 36)) +>T : Symbol(T, Decl(typeParameterDefaults.ts, 49, 20)) + + u: U; +>u : Symbol(u, Decl(typeParameterDefaults.ts, 50, 6)) +>U : Symbol(U, Decl(typeParameterDefaults.ts, 49, 22)) +} +class Derived3 extends ClassDefault2 {} +>Derived3 : Symbol(Derived3, Decl(typeParameterDefaults.ts, 52, 1)) +>ClassDefault2 : Symbol(ClassDefault2, Decl(typeParameterDefaults.ts, 47, 11)) + +let d3 = new Derived3(); +>d3 : Symbol(d3, Decl(typeParameterDefaults.ts, 54, 3)) +>Derived3 : Symbol(Derived3, Decl(typeParameterDefaults.ts, 52, 1)) + +// d3.u: string +d3.u = ''; +>d3.u : Symbol(ClassDefault2.u, Decl(typeParameterDefaults.ts, 50, 6)) +>d3 : Symbol(d3, Decl(typeParameterDefaults.ts, 54, 3)) +>u : Symbol(ClassDefault2.u, Decl(typeParameterDefaults.ts, 50, 6)) + + diff --git a/tests/baselines/reference/typeParameterDefaults.types b/tests/baselines/reference/typeParameterDefaults.types new file mode 100644 index 0000000000000..78c6926384610 --- /dev/null +++ b/tests/baselines/reference/typeParameterDefaults.types @@ -0,0 +1,178 @@ +=== tests/cases/conformance/types/typeParameters/typeParameterDefaults.ts === +/** Defaults on interfaces **/ +interface HasDefault1 { +>HasDefault1 : HasDefault1 +>T : T + + x: T; +>x : T +>T : T +} +// OK +let a3: HasDefault1; +>a3 : HasDefault1 +>HasDefault1 : HasDefault1 + +// a3.x: number +a3.x = 10; +>a3.x = 10 : number +>a3.x : number +>a3 : HasDefault1 +>x : number +>10 : number + +interface HasDefault2 { +>HasDefault2 : HasDefault2 +>T1 : T1 +>T2 : T2 + + x1: T1; +>x1 : T1 +>T1 : T1 + + x2: T2; +>x2 : T2 +>T2 : T2 +} +// Same as +let a5: HasDefault2; +>a5 : HasDefault2 +>HasDefault2 : HasDefault2 + +// a5.x1: string +a5.x1 = ''; +>a5.x1 = '' : string +>a5.x1 : string +>a5 : HasDefault2 +>x1 : string +>'' : string + +// a5.x2: number +a5.x2 = 42; +>a5.x2 = 42 : number +>a5.x2 : number +>a5 : HasDefault2 +>x2 : number +>42 : number + +let a6: HasDefault2; +>a6 : HasDefault2 +>HasDefault2 : HasDefault2 + +// a6.x1: boolean, a6.x2: boolean +a6.x1 = true; +>a6.x1 = true : boolean +>a6.x1 : boolean +>a6 : HasDefault2 +>x1 : boolean +>true : boolean + +a6.x2 = false; +>a6.x2 = false : boolean +>a6.x2 : boolean +>a6 : HasDefault2 +>x2 : boolean +>false : boolean + +/** Defaults on classes */ +class ClassDefault1 { +>ClassDefault1 : ClassDefault1 +>T : T + + x: T; +>x : T +>T : T +} +let c1 = new ClassDefault1(); +>c1 : ClassDefault1 +>new ClassDefault1() : ClassDefault1 +>ClassDefault1 : typeof ClassDefault1 + +// c1.x: number +c1.x = 10; +>c1.x = 10 : number +>c1.x : number +>c1 : ClassDefault1 +>x : number +>10 : number + +class Derived1 extends ClassDefault1 { +>Derived1 : Derived1 +>ClassDefault1 : ClassDefault1 +} +let d1 = new Derived1(); +>d1 : Derived1 +>new Derived1() : Derived1 +>Derived1 : typeof Derived1 + +// d1.x: number +d1.x = 10; +>d1.x = 10 : number +>d1.x : number +>d1 : Derived1 +>x : number +>10 : number + +class Derived2 extends ClassDefault1 { +>Derived2 : Derived2 +>T : T +>ClassDefault1 : ClassDefault1 +>T : T +} +let d2a = new Derived2(); +>d2a : Derived2 +>new Derived2() : Derived2 +>Derived2 : typeof Derived2 + +// d2a.x: string +d2a.x = 'hello'; +>d2a.x = 'hello' : string +>d2a.x : string +>d2a : Derived2 +>x : string +>'hello' : string + +let d2b = new Derived2(); +>d2b : Derived2 +>new Derived2() : Derived2 +>Derived2 : typeof Derived2 + +// d2b.x: number +d2b.x = 43; +>d2b.x = 43 : number +>d2b.x : number +>d2b : Derived2 +>x : number +>43 : number + +class ClassDefault2 { +>ClassDefault2 : ClassDefault2 +>T : T +>U : U + + t: T; +>t : T +>T : T + + u: U; +>u : U +>U : U +} +class Derived3 extends ClassDefault2 {} +>Derived3 : Derived3 +>ClassDefault2 : ClassDefault2 + +let d3 = new Derived3(); +>d3 : Derived3 +>new Derived3() : Derived3 +>Derived3 : typeof Derived3 + +// d3.u: string +d3.u = ''; +>d3.u = '' : string +>d3.u : string +>d3 : Derived3 +>u : string +>'' : string + + diff --git a/tests/baselines/reference/typeParameterDefaultsErrors.errors.txt b/tests/baselines/reference/typeParameterDefaultsErrors.errors.txt new file mode 100644 index 0000000000000..8b05b5ec8a07d --- /dev/null +++ b/tests/baselines/reference/typeParameterDefaultsErrors.errors.txt @@ -0,0 +1,42 @@ +tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts(7,9): error TS2314: Generic type 'NoDefaults' requires 1 type argument(s). +tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts(13,9): error TS2314: Generic type 'NoDefaultsWithConstraint' requires 1 type argument(s). +tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts(20,9): error TS2660: Generic type 'HasDefault2' requires between 1 and 2 type arguments. + + +==== tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts (3 errors) ==== + + /** Existing behavior unchanged **/ + interface NoDefaults { + x: T; + } + // Still an error + let a1: NoDefaults; + ~~~~~~~~~~ +!!! error TS2314: Generic type 'NoDefaults' requires 1 type argument(s). + + interface NoDefaultsWithConstraint { + x: T; + } + // Still an error + let a2: NoDefaultsWithConstraint; + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2314: Generic type 'NoDefaultsWithConstraint' requires 1 type argument(s). + + interface HasDefault2 { + x1: T1; + x2: T2; + } + // Still an error + let a4: HasDefault2; + ~~~~~~~~~~~ +!!! error TS2660: Generic type 'HasDefault2' requires between 1 and 2 type arguments. + + /** Required may not follow optional */ + interface Wrong { } + + /** Error: A default may only use preceding type parameters */ + interface NoForwardRefs1 { } + + /** Make sure this doesn't crash */ + // interface NoForwardRefs2 { } + \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterDefaultsErrors.js b/tests/baselines/reference/typeParameterDefaultsErrors.js new file mode 100644 index 0000000000000..6438158dbe7fd --- /dev/null +++ b/tests/baselines/reference/typeParameterDefaultsErrors.js @@ -0,0 +1,41 @@ +//// [typeParameterDefaultsErrors.ts] + +/** Existing behavior unchanged **/ +interface NoDefaults { + x: T; +} +// Still an error +let a1: NoDefaults; + +interface NoDefaultsWithConstraint { + x: T; +} +// Still an error +let a2: NoDefaultsWithConstraint; + +interface HasDefault2 { + x1: T1; + x2: T2; +} +// Still an error +let a4: HasDefault2; + +/** Required may not follow optional */ +interface Wrong { } + +/** Error: A default may only use preceding type parameters */ +interface NoForwardRefs1 { } + +/** Make sure this doesn't crash */ +// interface NoForwardRefs2 { } + + +//// [typeParameterDefaultsErrors.js] +// Still an error +var a1; +// Still an error +var a2; +// Still an error +var a4; +/** Make sure this doesn't crash */ +// interface NoForwardRefs2 { } diff --git a/tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts b/tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts new file mode 100644 index 0000000000000..4455f081aabde --- /dev/null +++ b/tests/cases/conformance/types/typeParameters/typeParameterCircularDefault.ts @@ -0,0 +1,47 @@ +/** Interfaces **/ + +// Two-way circular +interface I1 { } + +// Self-circular +interface I2 { } + +// Wrapped circular +interface I3> { } + +// OK, I guess? +interface I4 { } + +// Three-way circular +interface I5 { } + +// Indirect through type query +var a: I6; +var b = p.x; +interface I6 { + x: T; +} + + +/** Classes **/ +// Two-way circular +class C1 { } + +// Self-circular +class C2 { } + +// Wrapped circular +class C3> { } + +// OK, I guess? +class C4 { } + +// Three-way circular +class C5 { } + +// Indirect through type query +var p: C6; +var n = p.x; +class C6 { + x: T; +} diff --git a/tests/cases/conformance/types/typeParameters/typeParameterDefaults.js b/tests/cases/conformance/types/typeParameters/typeParameterDefaults.js new file mode 100644 index 0000000000000..446fcc07e4e18 --- /dev/null +++ b/tests/cases/conformance/types/typeParameters/typeParameterDefaults.js @@ -0,0 +1,46 @@ +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +// Still an error +var a1; +// Still an error +var a2; +// OK +var a3; +// a3.x: number +a3.x = 10; +// Still an error +var a4; +// Same as +var a5; +// a5.x1: string +a5.x1 = ''; +// a5.x2: number +a5.x2 = 42; +var a6; +// a6.x1: boolean, a6.x2: boolean +a6.x1 = true; +a6.x2 = false; +/** Defaults on classes */ +var ClassDefault1 = (function () { + function ClassDefault1() { + } + return ClassDefault1; +}()); +var c1 = new ClassDefault1(); +// c1.x: number +c1.x = 10; +var Derived1 = (function (_super) { + __extends(Derived1, _super); + function Derived1() { + _super.apply(this, arguments); + } + return Derived1; +}(ClassDefault1)); +var d1 = new Derived1(); +// d1.x: number +d1.x = 10; +/** Make sure this doesn't crash */ +// interface NoForwardRefs2 { } diff --git a/tests/cases/conformance/types/typeParameters/typeParameterDefaults.ts b/tests/cases/conformance/types/typeParameters/typeParameterDefaults.ts new file mode 100644 index 0000000000000..a1283b64ef642 --- /dev/null +++ b/tests/cases/conformance/types/typeParameters/typeParameterDefaults.ts @@ -0,0 +1,58 @@ +/** Defaults on interfaces **/ +interface HasDefault1 { + x: T; +} +// OK +let a3: HasDefault1; +// a3.x: number +a3.x = 10; + +interface HasDefault2 { + x1: T1; + x2: T2; +} +// Same as +let a5: HasDefault2; +// a5.x1: string +a5.x1 = ''; +// a5.x2: number +a5.x2 = 42; + +let a6: HasDefault2; +// a6.x1: boolean, a6.x2: boolean +a6.x1 = true; +a6.x2 = false; + +/** Defaults on classes */ +class ClassDefault1 { + x: T; +} +let c1 = new ClassDefault1(); +// c1.x: number +c1.x = 10; + +class Derived1 extends ClassDefault1 { +} +let d1 = new Derived1(); +// d1.x: number +d1.x = 10; + +class Derived2 extends ClassDefault1 { +} +let d2a = new Derived2(); +// d2a.x: string +d2a.x = 'hello'; + +let d2b = new Derived2(); +// d2b.x: number +d2b.x = 43; + +class ClassDefault2 { + t: T; + u: U; +} +class Derived3 extends ClassDefault2 {} +let d3 = new Derived3(); +// d3.u: string +d3.u = ''; + diff --git a/tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts b/tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts new file mode 100644 index 0000000000000..0b6b72b27bcfc --- /dev/null +++ b/tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts @@ -0,0 +1,29 @@ + +/** Existing behavior unchanged **/ +interface NoDefaults { + x: T; +} +// Still an error +let a1: NoDefaults; + +interface NoDefaultsWithConstraint { + x: T; +} +// Still an error +let a2: NoDefaultsWithConstraint; + +interface HasDefault2 { + x1: T1; + x2: T2; +} +// Still an error +let a4: HasDefault2; + +/** Required may not follow optional */ +interface Wrong { } + +/** Error: A default may only use preceding type parameters */ +interface NoForwardRefs1 { } + +/** Make sure this doesn't crash */ +// interface NoForwardRefs2 { } From df9becfe4160111ba40b3c8706afaed0903b18bd Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 4 Jan 2016 12:29:43 -0800 Subject: [PATCH 2/2] Tidy up --- src/compiler/checker.ts | 7 +------ src/compiler/diagnosticMessages.json | 4 ++++ .../reference/typeParameterDefaultsErrors.errors.txt | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 30b66a2f4c317..6d054c438dca1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -128,7 +128,6 @@ namespace ts { anyFunctionType.flags |= TypeFlags.ContainsAnyFunctionType; const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const noDefaultType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); @@ -3231,7 +3230,6 @@ namespace ts { error(symbol.declarations[0], Diagnostics.Type_parameter_0_has_a_circular_default, type.symbol.name); } } - symbol.declarations.forEach links.declaredType = type; } return links.declaredType; @@ -4285,7 +4283,6 @@ namespace ts { const typeParameters = links.typeParameters; if (typeParameters) { if (!checkTypeArgumentArity(typeParameters, node.typeArguments)) { - debugger; error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, symbolToString(symbol), typeParameters.length); return unknownType; } @@ -11144,7 +11141,7 @@ namespace ts { } checkSourceElement(node.constraint); - if(node.default) { + if (node.default) { checkSourceElement(node.default); } @@ -11610,7 +11607,6 @@ namespace ts { Diagnostics.Type_0_does_not_satisfy_the_constraint_1); } } - if(!result) debugger; return result; } @@ -13582,7 +13578,6 @@ namespace ts { } function checkClassLikeDeclaration(node: ClassLikeDeclaration) { - debugger; checkGrammarClassDeclarationHeritageClauses(node); checkDecorators(node); if (node.name) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 3d2fa6541edb9..3e0c85ec259ef 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1778,6 +1778,10 @@ "Type parameter '{0}' has a circular default.": { "category": "Error", "code": 2662 + }, + "Generic type '{0}' requires between {1} and {2} type arguments": { + "category": "Error", + "code": 2663 }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/typeParameterDefaultsErrors.errors.txt b/tests/baselines/reference/typeParameterDefaultsErrors.errors.txt index 8b05b5ec8a07d..59f925eede416 100644 --- a/tests/baselines/reference/typeParameterDefaultsErrors.errors.txt +++ b/tests/baselines/reference/typeParameterDefaultsErrors.errors.txt @@ -1,6 +1,6 @@ tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts(7,9): error TS2314: Generic type 'NoDefaults' requires 1 type argument(s). tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts(13,9): error TS2314: Generic type 'NoDefaultsWithConstraint' requires 1 type argument(s). -tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts(20,9): error TS2660: Generic type 'HasDefault2' requires between 1 and 2 type arguments. +tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts(20,9): error TS2663: Generic type 'HasDefault2' requires between 1 and 2 type arguments ==== tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts (3 errors) ==== @@ -29,7 +29,7 @@ tests/cases/conformance/types/typeParameters/typeParameterDefaultsErrors.ts(20,9 // Still an error let a4: HasDefault2; ~~~~~~~~~~~ -!!! error TS2660: Generic type 'HasDefault2' requires between 1 and 2 type arguments. +!!! error TS2663: Generic type 'HasDefault2' requires between 1 and 2 type arguments /** Required may not follow optional */ interface Wrong { }