diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 34454f3906e..9e1086a98e5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -48798,11 +48798,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } switch (modifier.kind) { - case SyntaxKind.ConstKeyword: + case SyntaxKind.ConstKeyword: { if (node.kind !== SyntaxKind.EnumDeclaration && node.kind !== SyntaxKind.TypeParameter) { return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); } - const parent = node.parent; + const parent = (isJSDocTemplateTag(node.parent) && getEffectiveJSDocHost(node.parent)) || node.parent; if ( node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(parent) || isClassLike(parent) || isFunctionTypeNode(parent) || isConstructorTypeNode(parent) || isCallSignatureDeclaration(parent) || isConstructSignatureDeclaration(parent) || isMethodSignature(parent)) @@ -48810,6 +48810,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, tokenToString(modifier.kind)); } break; + } case SyntaxKind.OverrideKeyword: // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. if (flags & ModifierFlags.Override) { @@ -49088,10 +49089,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; case SyntaxKind.InKeyword: - case SyntaxKind.OutKeyword: + case SyntaxKind.OutKeyword: { const inOutFlag = modifier.kind === SyntaxKind.InKeyword ? ModifierFlags.In : ModifierFlags.Out; const inOutText = modifier.kind === SyntaxKind.InKeyword ? "in" : "out"; - if (node.kind !== SyntaxKind.TypeParameter || !(isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent))) { + const parent = isJSDocTemplateTag(node.parent) && (getEffectiveJSDocHost(node.parent) || find(getJSDocRoot(node.parent)?.tags, isJSDocTypedefTag)) || node.parent; + if (node.kind !== SyntaxKind.TypeParameter || parent && !(isInterfaceDeclaration(parent) || isClassLike(parent) || isTypeAliasDeclaration(parent) || isJSDocTypedefTag(parent))) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, inOutText); } if (flags & inOutFlag) { @@ -49102,6 +49104,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } flags |= inOutFlag; break; + } } } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index bdd80887cda..4f68271ccb7 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -9710,8 +9710,9 @@ namespace Parser { if (isBracketed) { skipWhitespace(); } - const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); + const modifiers = parseModifiers(/*allowDecorators*/ false, /*permitConstAsModifier*/ true); + const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); let defaultType: TypeNode | undefined; if (isBracketed) { skipWhitespace(); @@ -9723,7 +9724,7 @@ namespace Parser { if (nodeIsMissing(name)) { return undefined; } - return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos); + return finishNode(factory.createTypeParameterDeclaration(modifiers, name, /*constraint*/ undefined, defaultType), typeParameterPos); } function parseTemplateTagTypeParameters() { diff --git a/tests/baselines/reference/jsdocTemplateTag6.symbols b/tests/baselines/reference/jsdocTemplateTag6.symbols new file mode 100644 index 00000000000..105ba2b51f2 --- /dev/null +++ b/tests/baselines/reference/jsdocTemplateTag6.symbols @@ -0,0 +1,192 @@ +//// [tests/cases/conformance/jsdoc/jsdocTemplateTag6.ts] //// + +=== a.js === +/** + * @template const T + * @param {T} x + * @returns {T} + */ +function f1(x) { +>f1 : Symbol(f1, Decl(a.js, 0, 0)) +>x : Symbol(x, Decl(a.js, 5, 12)) + + return x; +>x : Symbol(x, Decl(a.js, 5, 12)) +} +const t1 = f1("a"); +>t1 : Symbol(t1, Decl(a.js, 8, 5)) +>f1 : Symbol(f1, Decl(a.js, 0, 0)) + +const t2 = f1(["a", ["b", "c"]]); +>t2 : Symbol(t2, Decl(a.js, 9, 5)) +>f1 : Symbol(f1, Decl(a.js, 0, 0)) + +const t3 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>t3 : Symbol(t3, Decl(a.js, 10, 5)) +>f1 : Symbol(f1, Decl(a.js, 0, 0)) +>a : Symbol(a, Decl(a.js, 10, 15)) +>b : Symbol(b, Decl(a.js, 10, 21)) +>d : Symbol(d, Decl(a.js, 10, 29)) +>f : Symbol(f, Decl(a.js, 10, 49)) + +/** + * @template const T, U + * @param {T} x + * @returns {T} + */ +function f2(x) { +>f2 : Symbol(f2, Decl(a.js, 10, 63)) +>x : Symbol(x, Decl(a.js, 17, 12)) + + return x; +>x : Symbol(x, Decl(a.js, 17, 12)) + +}; +const t4 = f2('a'); +>t4 : Symbol(t4, Decl(a.js, 20, 5)) +>f2 : Symbol(f2, Decl(a.js, 10, 63)) + +const t5 = f2(['a', ['b', 'c']]); +>t5 : Symbol(t5, Decl(a.js, 21, 5)) +>f2 : Symbol(f2, Decl(a.js, 10, 63)) + +const t6 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>t6 : Symbol(t6, Decl(a.js, 22, 5)) +>f2 : Symbol(f2, Decl(a.js, 10, 63)) +>a : Symbol(a, Decl(a.js, 22, 15)) +>b : Symbol(b, Decl(a.js, 22, 21)) +>d : Symbol(d, Decl(a.js, 22, 29)) +>f : Symbol(f, Decl(a.js, 22, 49)) + +/** + * @template const T + * @param {T} x + * @returns {T[]} + */ +function f3(x) { +>f3 : Symbol(f3, Decl(a.js, 22, 63)) +>x : Symbol(x, Decl(a.js, 29, 12)) + + return [x]; +>x : Symbol(x, Decl(a.js, 29, 12)) +} +const t7 = f3("hello"); +>t7 : Symbol(t7, Decl(a.js, 32, 5)) +>f3 : Symbol(f3, Decl(a.js, 22, 63)) + +const t8 = f3("hello"); +>t8 : Symbol(t8, Decl(a.js, 33, 5)) +>f3 : Symbol(f3, Decl(a.js, 22, 63)) + +/** + * @template const T + * @param {[T, T]} x + * @returns {T} + */ +function f4(x) { +>f4 : Symbol(f4, Decl(a.js, 33, 23)) +>x : Symbol(x, Decl(a.js, 40, 12)) + + return x[0]; +>x : Symbol(x, Decl(a.js, 40, 12)) +>0 : Symbol(0) +} +const t9 = f4([[1, "x"], [2, "y"]]); +>t9 : Symbol(t9, Decl(a.js, 43, 5)) +>f4 : Symbol(f4, Decl(a.js, 33, 23)) + +const t10 = f4([{ a: 1, b: "x" }, { a: 2, b: "y" }]); +>t10 : Symbol(t10, Decl(a.js, 44, 5)) +>f4 : Symbol(f4, Decl(a.js, 33, 23)) +>a : Symbol(a, Decl(a.js, 44, 17)) +>b : Symbol(b, Decl(a.js, 44, 23)) +>a : Symbol(a, Decl(a.js, 44, 35)) +>b : Symbol(b, Decl(a.js, 44, 41)) + +/** + * @template const T + * @param {{ x: T, y: T}} obj + * @returns {T} + */ +function f5(obj) { +>f5 : Symbol(f5, Decl(a.js, 44, 53)) +>obj : Symbol(obj, Decl(a.js, 51, 12)) + + return obj.x; +>obj.x : Symbol(x, Decl(a.js, 48, 12)) +>obj : Symbol(obj, Decl(a.js, 51, 12)) +>x : Symbol(x, Decl(a.js, 48, 12)) +} +const t11 = f5({ x: [1, "x"], y: [2, "y"] }); +>t11 : Symbol(t11, Decl(a.js, 54, 5)) +>f5 : Symbol(f5, Decl(a.js, 44, 53)) +>x : Symbol(x, Decl(a.js, 54, 16)) +>y : Symbol(y, Decl(a.js, 54, 29)) + +const t12 = f5({ x: { a: 1, b: "x" }, y: { a: 2, b: "y" } }); +>t12 : Symbol(t12, Decl(a.js, 55, 5)) +>f5 : Symbol(f5, Decl(a.js, 44, 53)) +>x : Symbol(x, Decl(a.js, 55, 16)) +>a : Symbol(a, Decl(a.js, 55, 21)) +>b : Symbol(b, Decl(a.js, 55, 27)) +>y : Symbol(y, Decl(a.js, 55, 37)) +>a : Symbol(a, Decl(a.js, 55, 42)) +>b : Symbol(b, Decl(a.js, 55, 48)) + +/** + * @template const T + */ +class C { +>C : Symbol(C, Decl(a.js, 55, 61)) + + /** + * @param {T} x + */ + constructor(x) {} +>x : Symbol(x, Decl(a.js, 64, 16)) + + /** + * @template const U + * @param {U} x + */ + foo(x) { +>foo : Symbol(C.foo, Decl(a.js, 64, 21)) +>x : Symbol(x, Decl(a.js, 70, 8)) + + return x; +>x : Symbol(x, Decl(a.js, 70, 8)) + } +} + +const t13 = new C({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>t13 : Symbol(t13, Decl(a.js, 75, 5)) +>C : Symbol(C, Decl(a.js, 55, 61)) +>a : Symbol(a, Decl(a.js, 75, 19)) +>b : Symbol(b, Decl(a.js, 75, 25)) +>d : Symbol(d, Decl(a.js, 75, 33)) +>f : Symbol(f, Decl(a.js, 75, 53)) + +const t14 = t13.foo(["a", ["b", "c"]]); +>t14 : Symbol(t14, Decl(a.js, 76, 5)) +>t13.foo : Symbol(C.foo, Decl(a.js, 64, 21)) +>t13 : Symbol(t13, Decl(a.js, 75, 5)) +>foo : Symbol(C.foo, Decl(a.js, 64, 21)) + +/** + * @template {readonly unknown[]} const T + * @param {T} args + * @returns {T} + */ +function f6(...args) { +>f6 : Symbol(f6, Decl(a.js, 76, 39)) +>args : Symbol(args, Decl(a.js, 83, 12)) + + return args; +>args : Symbol(args, Decl(a.js, 83, 12)) +} +const t15 = f6(1, 'b', { a: 1, b: 'x' }); +>t15 : Symbol(t15, Decl(a.js, 86, 5)) +>f6 : Symbol(f6, Decl(a.js, 76, 39)) +>a : Symbol(a, Decl(a.js, 86, 24)) +>b : Symbol(b, Decl(a.js, 86, 30)) + diff --git a/tests/baselines/reference/jsdocTemplateTag6.types b/tests/baselines/reference/jsdocTemplateTag6.types new file mode 100644 index 00000000000..2ba325b6856 --- /dev/null +++ b/tests/baselines/reference/jsdocTemplateTag6.types @@ -0,0 +1,288 @@ +//// [tests/cases/conformance/jsdoc/jsdocTemplateTag6.ts] //// + +=== a.js === +/** + * @template const T + * @param {T} x + * @returns {T} + */ +function f1(x) { +>f1 : (x: T) => T +>x : T + + return x; +>x : T +} +const t1 = f1("a"); +>t1 : "a" +>f1("a") : "a" +>f1 : (x: T) => T +>"a" : "a" + +const t2 = f1(["a", ["b", "c"]]); +>t2 : readonly ["a", readonly ["b", "c"]] +>f1(["a", ["b", "c"]]) : readonly ["a", readonly ["b", "c"]] +>f1 : (x: T) => T +>["a", ["b", "c"]] : ["a", ["b", "c"]] +>"a" : "a" +>["b", "c"] : ["b", "c"] +>"b" : "b" +>"c" : "c" + +const t3 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>t3 : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } +>f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } +>f1 : (x: T) => T +>{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; } +>a : 1 +>1 : 1 +>b : "c" +>"c" : "c" +>d : ["e", 2, true, { f: "g"; }] +>["e", 2, true, { f: "g" }] : ["e", 2, true, { f: "g"; }] +>"e" : "e" +>2 : 2 +>true : true +>{ f: "g" } : { f: "g"; } +>f : "g" +>"g" : "g" + +/** + * @template const T, U + * @param {T} x + * @returns {T} + */ +function f2(x) { +>f2 : (x: T) => T +>x : T + + return x; +>x : T + +}; +const t4 = f2('a'); +>t4 : "a" +>f2('a') : "a" +>f2 : (x: T) => T +>'a' : "a" + +const t5 = f2(['a', ['b', 'c']]); +>t5 : readonly ["a", readonly ["b", "c"]] +>f2(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]] +>f2 : (x: T) => T +>['a', ['b', 'c']] : ["a", ["b", "c"]] +>'a' : "a" +>['b', 'c'] : ["b", "c"] +>'b' : "b" +>'c' : "c" + +const t6 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>t6 : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } +>f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } +>f2 : (x: T) => T +>{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; } +>a : 1 +>1 : 1 +>b : "c" +>"c" : "c" +>d : ["e", 2, true, { f: "g"; }] +>["e", 2, true, { f: "g" }] : ["e", 2, true, { f: "g"; }] +>"e" : "e" +>2 : 2 +>true : true +>{ f: "g" } : { f: "g"; } +>f : "g" +>"g" : "g" + +/** + * @template const T + * @param {T} x + * @returns {T[]} + */ +function f3(x) { +>f3 : (x: T) => T[] +>x : T + + return [x]; +>[x] : T[] +>x : T +} +const t7 = f3("hello"); +>t7 : "hello"[] +>f3("hello") : "hello"[] +>f3 : (x: T) => T[] +>"hello" : "hello" + +const t8 = f3("hello"); +>t8 : "hello"[] +>f3("hello") : "hello"[] +>f3 : (x: T) => T[] +>"hello" : "hello" + +/** + * @template const T + * @param {[T, T]} x + * @returns {T} + */ +function f4(x) { +>f4 : (x: [T, T]) => T +>x : [T, T] + + return x[0]; +>x[0] : T +>x : [T, T] +>0 : 0 +} +const t9 = f4([[1, "x"], [2, "y"]]); +>t9 : readonly [1, "x"] | readonly [2, "y"] +>f4([[1, "x"], [2, "y"]]) : readonly [1, "x"] | readonly [2, "y"] +>f4 : (x: [T, T]) => T +>[[1, "x"], [2, "y"]] : [[1, "x"], [2, "y"]] +>[1, "x"] : [1, "x"] +>1 : 1 +>"x" : "x" +>[2, "y"] : [2, "y"] +>2 : 2 +>"y" : "y" + +const t10 = f4([{ a: 1, b: "x" }, { a: 2, b: "y" }]); +>t10 : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } +>f4([{ a: 1, b: "x" }, { a: 2, b: "y" }]) : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } +>f4 : (x: [T, T]) => T +>[{ a: 1, b: "x" }, { a: 2, b: "y" }] : [{ a: 1; b: "x"; }, { a: 2; b: "y"; }] +>{ a: 1, b: "x" } : { a: 1; b: "x"; } +>a : 1 +>1 : 1 +>b : "x" +>"x" : "x" +>{ a: 2, b: "y" } : { a: 2; b: "y"; } +>a : 2 +>2 : 2 +>b : "y" +>"y" : "y" + +/** + * @template const T + * @param {{ x: T, y: T}} obj + * @returns {T} + */ +function f5(obj) { +>f5 : (obj: { x: T; y: T;}) => T +>obj : { x: T; y: T; } + + return obj.x; +>obj.x : T +>obj : { x: T; y: T; } +>x : T +} +const t11 = f5({ x: [1, "x"], y: [2, "y"] }); +>t11 : readonly [1, "x"] | readonly [2, "y"] +>f5({ x: [1, "x"], y: [2, "y"] }) : readonly [1, "x"] | readonly [2, "y"] +>f5 : (obj: { x: T; y: T; }) => T +>{ x: [1, "x"], y: [2, "y"] } : { x: [1, "x"]; y: [2, "y"]; } +>x : [1, "x"] +>[1, "x"] : [1, "x"] +>1 : 1 +>"x" : "x" +>y : [2, "y"] +>[2, "y"] : [2, "y"] +>2 : 2 +>"y" : "y" + +const t12 = f5({ x: { a: 1, b: "x" }, y: { a: 2, b: "y" } }); +>t12 : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } +>f5({ x: { a: 1, b: "x" }, y: { a: 2, b: "y" } }) : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } +>f5 : (obj: { x: T; y: T; }) => T +>{ x: { a: 1, b: "x" }, y: { a: 2, b: "y" } } : { x: { a: 1; b: "x"; }; y: { a: 2; b: "y"; }; } +>x : { a: 1; b: "x"; } +>{ a: 1, b: "x" } : { a: 1; b: "x"; } +>a : 1 +>1 : 1 +>b : "x" +>"x" : "x" +>y : { a: 2; b: "y"; } +>{ a: 2, b: "y" } : { a: 2; b: "y"; } +>a : 2 +>2 : 2 +>b : "y" +>"y" : "y" + +/** + * @template const T + */ +class C { +>C : C + + /** + * @param {T} x + */ + constructor(x) {} +>x : T + + /** + * @template const U + * @param {U} x + */ + foo(x) { +>foo : (x: U) => U +>x : U + + return x; +>x : U + } +} + +const t13 = new C({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>t13 : C<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }> +>new C({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : C<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }> +>C : typeof C +>{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; } +>a : 1 +>1 : 1 +>b : "c" +>"c" : "c" +>d : ["e", 2, true, { f: "g"; }] +>["e", 2, true, { f: "g" }] : ["e", 2, true, { f: "g"; }] +>"e" : "e" +>2 : 2 +>true : true +>{ f: "g" } : { f: "g"; } +>f : "g" +>"g" : "g" + +const t14 = t13.foo(["a", ["b", "c"]]); +>t14 : readonly ["a", readonly ["b", "c"]] +>t13.foo(["a", ["b", "c"]]) : readonly ["a", readonly ["b", "c"]] +>t13.foo : (x: U) => U +>t13 : C<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }> +>foo : (x: U) => U +>["a", ["b", "c"]] : ["a", ["b", "c"]] +>"a" : "a" +>["b", "c"] : ["b", "c"] +>"b" : "b" +>"c" : "c" + +/** + * @template {readonly unknown[]} const T + * @param {T} args + * @returns {T} + */ +function f6(...args) { +>f6 : (...args: T) => T +>args : T + + return args; +>args : T +} +const t15 = f6(1, 'b', { a: 1, b: 'x' }); +>t15 : readonly [1, "b", { readonly a: 1; readonly b: "x"; }] +>f6(1, 'b', { a: 1, b: 'x' }) : readonly [1, "b", { readonly a: 1; readonly b: "x"; }] +>f6 : (...args: T) => T +>1 : 1 +>'b' : "b" +>{ a: 1, b: 'x' } : { a: 1; b: "x"; } +>a : 1 +>1 : 1 +>b : "x" +>'x' : "x" + diff --git a/tests/baselines/reference/jsdocTemplateTag7.errors.txt b/tests/baselines/reference/jsdocTemplateTag7.errors.txt new file mode 100644 index 00000000000..6d5770242ed --- /dev/null +++ b/tests/baselines/reference/jsdocTemplateTag7.errors.txt @@ -0,0 +1,28 @@ +a.js(2,14): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class +a.js(12,14): error TS1273: 'private' modifier cannot appear on a type parameter + + +==== a.js (2 errors) ==== + /** + * @template const T + ~~~~~ +!!! error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class + * @typedef {[T]} X + */ + + /** + * @template const T + */ + class C { } + + /** + * @template private T + ~~~~~~~ +!!! error TS1273: 'private' modifier cannot appear on a type parameter + * @param {T} x + * @returns {T} + */ + function f(x) { + return x; + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocTemplateTag7.symbols b/tests/baselines/reference/jsdocTemplateTag7.symbols new file mode 100644 index 00000000000..2d734a70fbb --- /dev/null +++ b/tests/baselines/reference/jsdocTemplateTag7.symbols @@ -0,0 +1,27 @@ +//// [tests/cases/conformance/jsdoc/jsdocTemplateTag7.ts] //// + +=== a.js === +/** + * @template const T + * @typedef {[T]} X + */ + +/** + * @template const T + */ +class C { } +>C : Symbol(C, Decl(a.js, 0, 0)) + +/** + * @template private T + * @param {T} x + * @returns {T} + */ +function f(x) { +>f : Symbol(f, Decl(a.js, 8, 11)) +>x : Symbol(x, Decl(a.js, 15, 11)) + + return x; +>x : Symbol(x, Decl(a.js, 15, 11)) +} + diff --git a/tests/baselines/reference/jsdocTemplateTag7.types b/tests/baselines/reference/jsdocTemplateTag7.types new file mode 100644 index 00000000000..7a49d72b4a4 --- /dev/null +++ b/tests/baselines/reference/jsdocTemplateTag7.types @@ -0,0 +1,27 @@ +//// [tests/cases/conformance/jsdoc/jsdocTemplateTag7.ts] //// + +=== a.js === +/** + * @template const T + * @typedef {[T]} X + */ + +/** + * @template const T + */ +class C { } +>C : C + +/** + * @template private T + * @param {T} x + * @returns {T} + */ +function f(x) { +>f : (x: T) => T +>x : T + + return x; +>x : T +} + diff --git a/tests/baselines/reference/jsdocTemplateTag8.errors.txt b/tests/baselines/reference/jsdocTemplateTag8.errors.txt new file mode 100644 index 00000000000..1c592ae2318 --- /dev/null +++ b/tests/baselines/reference/jsdocTemplateTag8.errors.txt @@ -0,0 +1,97 @@ +a.js(18,1): error TS2322: Type 'Covariant' is not assignable to type 'Covariant'. + Type 'unknown' is not assignable to type 'string'. +a.js(36,1): error TS2322: Type 'Contravariant' is not assignable to type 'Contravariant'. + Type 'unknown' is not assignable to type 'string'. +a.js(55,1): error TS2322: Type 'Invariant' is not assignable to type 'Invariant'. + Types of property 'f' are incompatible. + Type '(x: string) => string' is not assignable to type '(x: unknown) => unknown'. + Types of parameters 'x' and 'x' are incompatible. + Type 'unknown' is not assignable to type 'string'. +a.js(56,1): error TS2322: Type 'Invariant' is not assignable to type 'Invariant'. + The types returned by 'f(...)' are incompatible between these types. + Type 'unknown' is not assignable to type 'string'. +a.js(59,14): error TS1274: 'in' modifier can only appear on a type parameter of a class, interface or type alias + + +==== a.js (5 errors) ==== + /** + * @template out T + * @typedef {Object} Covariant + * @property {T} x + */ + + /** + * @type {Covariant} + */ + let super_covariant = { x: 1 }; + + /** + * @type {Covariant} + */ + let sub_covariant = { x: '' }; + + super_covariant = sub_covariant; + sub_covariant = super_covariant; // Error + ~~~~~~~~~~~~~ +!!! error TS2322: Type 'Covariant' is not assignable to type 'Covariant'. +!!! error TS2322: Type 'unknown' is not assignable to type 'string'. + + /** + * @template in T + * @typedef {Object} Contravariant + * @property {(x: T) => void} f + */ + + /** + * @type {Contravariant} + */ + let super_contravariant = { f: (x) => {} }; + + /** + * @type {Contravariant} + */ + let sub_contravariant = { f: (x) => {} }; + + super_contravariant = sub_contravariant; // Error + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'Contravariant' is not assignable to type 'Contravariant'. +!!! error TS2322: Type 'unknown' is not assignable to type 'string'. + sub_contravariant = super_contravariant; + + /** + * @template in out T + * @typedef {Object} Invariant + * @property {(x: T) => T} f + */ + + /** + * @type {Invariant} + */ + let super_invariant = { f: (x) => {} }; + + /** + * @type {Invariant} + */ + let sub_invariant = { f: (x) => { return "" } }; + + super_invariant = sub_invariant; // Error + ~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'Invariant' is not assignable to type 'Invariant'. +!!! error TS2322: Types of property 'f' are incompatible. +!!! error TS2322: Type '(x: string) => string' is not assignable to type '(x: unknown) => unknown'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'unknown' is not assignable to type 'string'. + sub_invariant = super_invariant; // Error + ~~~~~~~~~~~~~ +!!! error TS2322: Type 'Invariant' is not assignable to type 'Invariant'. +!!! error TS2322: The types returned by 'f(...)' are incompatible between these types. +!!! error TS2322: Type 'unknown' is not assignable to type 'string'. + + /** + * @template in T + ~~ +!!! error TS1274: 'in' modifier can only appear on a type parameter of a class, interface or type alias + * @param {T} x + */ + function f(x) {} + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocTemplateTag8.symbols b/tests/baselines/reference/jsdocTemplateTag8.symbols new file mode 100644 index 00000000000..5b6d103ed02 --- /dev/null +++ b/tests/baselines/reference/jsdocTemplateTag8.symbols @@ -0,0 +1,99 @@ +//// [tests/cases/conformance/jsdoc/jsdocTemplateTag8.ts] //// + +=== a.js === +/** + * @template out T + * @typedef {Object} Covariant + * @property {T} x + */ + +/** + * @type {Covariant} + */ +let super_covariant = { x: 1 }; +>super_covariant : Symbol(super_covariant, Decl(a.js, 9, 3)) +>x : Symbol(x, Decl(a.js, 9, 23)) + +/** + * @type {Covariant} + */ +let sub_covariant = { x: '' }; +>sub_covariant : Symbol(sub_covariant, Decl(a.js, 14, 3)) +>x : Symbol(x, Decl(a.js, 14, 21)) + +super_covariant = sub_covariant; +>super_covariant : Symbol(super_covariant, Decl(a.js, 9, 3)) +>sub_covariant : Symbol(sub_covariant, Decl(a.js, 14, 3)) + +sub_covariant = super_covariant; // Error +>sub_covariant : Symbol(sub_covariant, Decl(a.js, 14, 3)) +>super_covariant : Symbol(super_covariant, Decl(a.js, 9, 3)) + +/** + * @template in T + * @typedef {Object} Contravariant + * @property {(x: T) => void} f + */ + +/** + * @type {Contravariant} + */ +let super_contravariant = { f: (x) => {} }; +>super_contravariant : Symbol(super_contravariant, Decl(a.js, 28, 3)) +>f : Symbol(f, Decl(a.js, 28, 27)) +>x : Symbol(x, Decl(a.js, 28, 32)) + +/** + * @type {Contravariant} + */ +let sub_contravariant = { f: (x) => {} }; +>sub_contravariant : Symbol(sub_contravariant, Decl(a.js, 33, 3)) +>f : Symbol(f, Decl(a.js, 33, 25)) +>x : Symbol(x, Decl(a.js, 33, 30)) + +super_contravariant = sub_contravariant; // Error +>super_contravariant : Symbol(super_contravariant, Decl(a.js, 28, 3)) +>sub_contravariant : Symbol(sub_contravariant, Decl(a.js, 33, 3)) + +sub_contravariant = super_contravariant; +>sub_contravariant : Symbol(sub_contravariant, Decl(a.js, 33, 3)) +>super_contravariant : Symbol(super_contravariant, Decl(a.js, 28, 3)) + +/** + * @template in out T + * @typedef {Object} Invariant + * @property {(x: T) => T} f + */ + +/** + * @type {Invariant} + */ +let super_invariant = { f: (x) => {} }; +>super_invariant : Symbol(super_invariant, Decl(a.js, 47, 3)) +>f : Symbol(f, Decl(a.js, 47, 23)) +>x : Symbol(x, Decl(a.js, 47, 28)) + +/** + * @type {Invariant} + */ +let sub_invariant = { f: (x) => { return "" } }; +>sub_invariant : Symbol(sub_invariant, Decl(a.js, 52, 3)) +>f : Symbol(f, Decl(a.js, 52, 21)) +>x : Symbol(x, Decl(a.js, 52, 26)) + +super_invariant = sub_invariant; // Error +>super_invariant : Symbol(super_invariant, Decl(a.js, 47, 3)) +>sub_invariant : Symbol(sub_invariant, Decl(a.js, 52, 3)) + +sub_invariant = super_invariant; // Error +>sub_invariant : Symbol(sub_invariant, Decl(a.js, 52, 3)) +>super_invariant : Symbol(super_invariant, Decl(a.js, 47, 3)) + +/** + * @template in T + * @param {T} x + */ +function f(x) {} +>f : Symbol(f, Decl(a.js, 55, 32)) +>x : Symbol(x, Decl(a.js, 61, 11)) + diff --git a/tests/baselines/reference/jsdocTemplateTag8.types b/tests/baselines/reference/jsdocTemplateTag8.types new file mode 100644 index 00000000000..d085ff77d0e --- /dev/null +++ b/tests/baselines/reference/jsdocTemplateTag8.types @@ -0,0 +1,118 @@ +//// [tests/cases/conformance/jsdoc/jsdocTemplateTag8.ts] //// + +=== a.js === +/** + * @template out T + * @typedef {Object} Covariant + * @property {T} x + */ + +/** + * @type {Covariant} + */ +let super_covariant = { x: 1 }; +>super_covariant : Covariant +>{ x: 1 } : { x: number; } +>x : number +>1 : 1 + +/** + * @type {Covariant} + */ +let sub_covariant = { x: '' }; +>sub_covariant : Covariant +>{ x: '' } : { x: string; } +>x : string +>'' : "" + +super_covariant = sub_covariant; +>super_covariant = sub_covariant : Covariant +>super_covariant : Covariant +>sub_covariant : Covariant + +sub_covariant = super_covariant; // Error +>sub_covariant = super_covariant : Covariant +>sub_covariant : Covariant +>super_covariant : Covariant + +/** + * @template in T + * @typedef {Object} Contravariant + * @property {(x: T) => void} f + */ + +/** + * @type {Contravariant} + */ +let super_contravariant = { f: (x) => {} }; +>super_contravariant : Contravariant +>{ f: (x) => {} } : { f: (x: unknown) => void; } +>f : (x: unknown) => void +>(x) => {} : (x: unknown) => void +>x : unknown + +/** + * @type {Contravariant} + */ +let sub_contravariant = { f: (x) => {} }; +>sub_contravariant : Contravariant +>{ f: (x) => {} } : { f: (x: string) => void; } +>f : (x: string) => void +>(x) => {} : (x: string) => void +>x : string + +super_contravariant = sub_contravariant; // Error +>super_contravariant = sub_contravariant : Contravariant +>super_contravariant : Contravariant +>sub_contravariant : Contravariant + +sub_contravariant = super_contravariant; +>sub_contravariant = super_contravariant : Contravariant +>sub_contravariant : Contravariant +>super_contravariant : Contravariant + +/** + * @template in out T + * @typedef {Object} Invariant + * @property {(x: T) => T} f + */ + +/** + * @type {Invariant} + */ +let super_invariant = { f: (x) => {} }; +>super_invariant : Invariant +>{ f: (x) => {} } : { f: (x: unknown) => void; } +>f : (x: unknown) => void +>(x) => {} : (x: unknown) => void +>x : unknown + +/** + * @type {Invariant} + */ +let sub_invariant = { f: (x) => { return "" } }; +>sub_invariant : Invariant +>{ f: (x) => { return "" } } : { f: (x: string) => string; } +>f : (x: string) => string +>(x) => { return "" } : (x: string) => string +>x : string +>"" : "" + +super_invariant = sub_invariant; // Error +>super_invariant = sub_invariant : Invariant +>super_invariant : Invariant +>sub_invariant : Invariant + +sub_invariant = super_invariant; // Error +>sub_invariant = super_invariant : Invariant +>sub_invariant : Invariant +>super_invariant : Invariant + +/** + * @template in T + * @param {T} x + */ +function f(x) {} +>f : (x: T) => void +>x : T + diff --git a/tests/cases/conformance/jsdoc/jsdocTemplateTag6.ts b/tests/cases/conformance/jsdoc/jsdocTemplateTag6.ts new file mode 100644 index 00000000000..7555c691781 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocTemplateTag6.ts @@ -0,0 +1,93 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @strict: true +// @Filename: a.js + +/** + * @template const T + * @param {T} x + * @returns {T} + */ +function f1(x) { + return x; +} +const t1 = f1("a"); +const t2 = f1(["a", ["b", "c"]]); +const t3 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); + +/** + * @template const T, U + * @param {T} x + * @returns {T} + */ +function f2(x) { + return x; +}; +const t4 = f2('a'); +const t5 = f2(['a', ['b', 'c']]); +const t6 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); + +/** + * @template const T + * @param {T} x + * @returns {T[]} + */ +function f3(x) { + return [x]; +} +const t7 = f3("hello"); +const t8 = f3("hello"); + +/** + * @template const T + * @param {[T, T]} x + * @returns {T} + */ +function f4(x) { + return x[0]; +} +const t9 = f4([[1, "x"], [2, "y"]]); +const t10 = f4([{ a: 1, b: "x" }, { a: 2, b: "y" }]); + +/** + * @template const T + * @param {{ x: T, y: T}} obj + * @returns {T} + */ +function f5(obj) { + return obj.x; +} +const t11 = f5({ x: [1, "x"], y: [2, "y"] }); +const t12 = f5({ x: { a: 1, b: "x" }, y: { a: 2, b: "y" } }); + +/** + * @template const T + */ +class C { + /** + * @param {T} x + */ + constructor(x) {} + + /** + * @template const U + * @param {U} x + */ + foo(x) { + return x; + } +} + +const t13 = new C({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +const t14 = t13.foo(["a", ["b", "c"]]); + +/** + * @template {readonly unknown[]} const T + * @param {T} args + * @returns {T} + */ +function f6(...args) { + return args; +} +const t15 = f6(1, 'b', { a: 1, b: 'x' }); diff --git a/tests/cases/conformance/jsdoc/jsdocTemplateTag7.ts b/tests/cases/conformance/jsdoc/jsdocTemplateTag7.ts new file mode 100644 index 00000000000..b4f85fb71a1 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocTemplateTag7.ts @@ -0,0 +1,24 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @strict: true +// @Filename: a.js + +/** + * @template const T + * @typedef {[T]} X + */ + +/** + * @template const T + */ +class C { } + +/** + * @template private T + * @param {T} x + * @returns {T} + */ +function f(x) { + return x; +} diff --git a/tests/cases/conformance/jsdoc/jsdocTemplateTag8.ts b/tests/cases/conformance/jsdoc/jsdocTemplateTag8.ts new file mode 100644 index 00000000000..3e6c25d2e46 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocTemplateTag8.ts @@ -0,0 +1,68 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @strict: true +// @Filename: a.js + +/** + * @template out T + * @typedef {Object} Covariant + * @property {T} x + */ + +/** + * @type {Covariant} + */ +let super_covariant = { x: 1 }; + +/** + * @type {Covariant} + */ +let sub_covariant = { x: '' }; + +super_covariant = sub_covariant; +sub_covariant = super_covariant; // Error + +/** + * @template in T + * @typedef {Object} Contravariant + * @property {(x: T) => void} f + */ + +/** + * @type {Contravariant} + */ +let super_contravariant = { f: (x) => {} }; + +/** + * @type {Contravariant} + */ +let sub_contravariant = { f: (x) => {} }; + +super_contravariant = sub_contravariant; // Error +sub_contravariant = super_contravariant; + +/** + * @template in out T + * @typedef {Object} Invariant + * @property {(x: T) => T} f + */ + +/** + * @type {Invariant} + */ +let super_invariant = { f: (x) => {} }; + +/** + * @type {Invariant} + */ +let sub_invariant = { f: (x) => { return "" } }; + +super_invariant = sub_invariant; // Error +sub_invariant = super_invariant; // Error + +/** + * @template in T + * @param {T} x + */ +function f(x) {}