mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-23 10:29:01 -06:00
Template tag allows specification of constraints (#24600)
* Parse (and mostly support) template tag constraints A bunch of tests hit the asserts I added though. * Messy version is finished. Need to add a few tests * Refactor to be smaller * Small refactor + Add one test * Another test * Minor cleanup * Fix error reporting on type parameters on ctors * Simplify syntax of `@template` tag This is a breaking change, but in my sample, nobody except webpack used the erroneous syntax. I need to improve the error message, so jsdocTemplateTag3 currently fails to remind me of that. * Better error message for template tag * Fix fourslash baselines * Another fourslash update * Address PR comments * Simplify getEffectiveTypeParameterDeclarations Make checkGrammarConstructorTypeParameters do a little more work
This commit is contained in:
parent
2ce7e5f0cd
commit
34e68efdae
@ -28421,9 +28421,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) {
|
||||
const typeParameters = getEffectiveTypeParameterDeclarations(node);
|
||||
if (isNodeArray(typeParameters)) {
|
||||
const { pos, end } = typeParameters;
|
||||
const jsdocTypeParameters = isInJavaScriptFile(node) && getJSDocTypeParameterDeclarations(node);
|
||||
if (node.typeParameters || jsdocTypeParameters && jsdocTypeParameters.length) {
|
||||
const { pos, end } = node.typeParameters || jsdocTypeParameters && jsdocTypeParameters[0] || node;
|
||||
return grammarErrorAtPos(node, pos, end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,6 +219,10 @@
|
||||
"category": "Error",
|
||||
"code": 1068
|
||||
},
|
||||
"Unexpected token. A type parameter name was expected without curly braces.": {
|
||||
"category": "Error",
|
||||
"code": 1069
|
||||
},
|
||||
"'{0}' modifier cannot appear on a type member.": {
|
||||
"category": "Error",
|
||||
"code": 1070
|
||||
|
||||
@ -6993,29 +6993,27 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag | undefined {
|
||||
if (some(tags, isJSDocTemplateTag)) {
|
||||
parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
|
||||
// the template tag looks like '@template {Constraint} T,U,V'
|
||||
let constraint: JSDocTypeExpression | undefined;
|
||||
if (token() === SyntaxKind.OpenBraceToken) {
|
||||
constraint = parseJSDocTypeExpression();
|
||||
skipWhitespace();
|
||||
}
|
||||
|
||||
// Type parameter list looks like '@template T,U,V'
|
||||
const typeParameters = [];
|
||||
const typeParametersPos = getNodePos();
|
||||
|
||||
while (true) {
|
||||
const typeParameter = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter);
|
||||
const name = parseJSDocIdentifierNameWithOptionalBraces();
|
||||
skipWhitespace();
|
||||
if (!name) {
|
||||
parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected);
|
||||
if (!tokenIsIdentifierOrKeyword(token())) {
|
||||
parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
typeParameter.name = name;
|
||||
typeParameter.name = parseJSDocIdentifierName()!;
|
||||
skipWhitespace();
|
||||
finishNode(typeParameter);
|
||||
|
||||
typeParameters.push(typeParameter);
|
||||
|
||||
if (token() === SyntaxKind.CommaToken) {
|
||||
// need to look for more type parameters
|
||||
nextJSDocToken();
|
||||
skipWhitespace();
|
||||
}
|
||||
@ -7024,6 +7022,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (constraint) {
|
||||
first(typeParameters).constraint = constraint.type;
|
||||
}
|
||||
|
||||
const result = <JSDocTemplateTag>createNode(SyntaxKind.JSDocTemplateTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
@ -7032,15 +7034,6 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function parseJSDocIdentifierNameWithOptionalBraces(): Identifier | undefined {
|
||||
const parsedBrace = parseOptional(SyntaxKind.OpenBraceToken);
|
||||
const res = parseJSDocIdentifierName();
|
||||
if (parsedBrace) {
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function nextJSDocToken(): JsDocSyntaxKind {
|
||||
return currentToken = scanner.scanJSDocToken();
|
||||
}
|
||||
|
||||
@ -3164,21 +3164,18 @@ namespace ts {
|
||||
}
|
||||
if (isJSDocTypeAlias(node)) {
|
||||
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
|
||||
const templateTags = flatMap(filter(node.parent.tags, isJSDocTemplateTag), tag => tag.typeParameters) as ReadonlyArray<TypeParameterDeclaration>;
|
||||
const templateTagNodes = templateTags as NodeArray<TypeParameterDeclaration>;
|
||||
templateTagNodes.pos = templateTagNodes.length > 0 ? first(templateTagNodes).pos : node.pos;
|
||||
templateTagNodes.end = templateTagNodes.length > 0 ? last(templateTagNodes).end : node.end;
|
||||
templateTagNodes.hasTrailingComma = false;
|
||||
return templateTagNodes;
|
||||
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
|
||||
}
|
||||
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray);
|
||||
}
|
||||
|
||||
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
|
||||
// template tags are only available when a typedef isn't already using them
|
||||
const tag = find(getJSDocTags(node), (tag): tag is JSDocTemplateTag =>
|
||||
isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDocComment && tag.parent.tags!.some(isJSDocTypeAlias)));
|
||||
return (tag && tag.typeParameters) || emptyArray;
|
||||
return flatMap(getJSDocTags(node), tag => isNonTypeAliasTemplate(tag) ? tag.typeParameters : undefined);
|
||||
}
|
||||
|
||||
/** template tags are only available when a typedef isn't already using them */
|
||||
function isNonTypeAliasTemplate(tag: JSDocTag): tag is JSDocTemplateTag {
|
||||
return isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDocComment && tag.parent.tags!.some(isJSDocTypeAlias));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -3,7 +3,7 @@ tests/cases/conformance/jsdoc/templateTagOnClasses.js(25,1): error TS2322: Type
|
||||
|
||||
==== tests/cases/conformance/jsdoc/templateTagOnClasses.js (1 errors) ====
|
||||
/**
|
||||
* @template {T}
|
||||
* @template T
|
||||
* @typedef {(t: T) => T} Id
|
||||
*/
|
||||
/** @template T */
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagOnClasses.js ===
|
||||
/**
|
||||
* @template {T}
|
||||
* @template T
|
||||
* @typedef {(t: T) => T} Id
|
||||
*/
|
||||
/** @template T */
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagOnClasses.js ===
|
||||
/**
|
||||
* @template {T}
|
||||
* @template T
|
||||
* @typedef {(t: T) => T} Id
|
||||
*/
|
||||
/** @template T */
|
||||
|
||||
@ -3,12 +3,12 @@ tests/cases/conformance/jsdoc/templateTagOnConstructorFunctions.js(24,1): error
|
||||
|
||||
==== tests/cases/conformance/jsdoc/templateTagOnConstructorFunctions.js (1 errors) ====
|
||||
/**
|
||||
* @template {U}
|
||||
* @template U
|
||||
* @typedef {(u: U) => U} Id
|
||||
*/
|
||||
/**
|
||||
* @param {T} t
|
||||
* @template {T}
|
||||
* @template T
|
||||
*/
|
||||
function Zet(t) {
|
||||
/** @type {T} */
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagOnConstructorFunctions.js ===
|
||||
/**
|
||||
* @template {U}
|
||||
* @template U
|
||||
* @typedef {(u: U) => U} Id
|
||||
*/
|
||||
/**
|
||||
* @param {T} t
|
||||
* @template {T}
|
||||
* @template T
|
||||
*/
|
||||
function Zet(t) {
|
||||
>Zet : Symbol(Zet, Decl(templateTagOnConstructorFunctions.js, 0, 0))
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagOnConstructorFunctions.js ===
|
||||
/**
|
||||
* @template {U}
|
||||
* @template U
|
||||
* @typedef {(u: U) => U} Id
|
||||
*/
|
||||
/**
|
||||
* @param {T} t
|
||||
* @template {T}
|
||||
* @template T
|
||||
*/
|
||||
function Zet(t) {
|
||||
>Zet : typeof Zet
|
||||
|
||||
@ -5,7 +5,7 @@ tests/cases/conformance/jsdoc/templateTagWithNestedTypeLiteral.js(26,15): error
|
||||
==== tests/cases/conformance/jsdoc/templateTagWithNestedTypeLiteral.js (2 errors) ====
|
||||
/**
|
||||
* @param {T} t
|
||||
* @template {T}
|
||||
* @template T
|
||||
*/
|
||||
function Zet(t) {
|
||||
/** @type {T} */
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagWithNestedTypeLiteral.js ===
|
||||
/**
|
||||
* @param {T} t
|
||||
* @template {T}
|
||||
* @template T
|
||||
*/
|
||||
function Zet(t) {
|
||||
>Zet : Symbol(Zet, Decl(templateTagWithNestedTypeLiteral.js, 0, 0))
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
=== tests/cases/conformance/jsdoc/templateTagWithNestedTypeLiteral.js ===
|
||||
/**
|
||||
* @param {T} t
|
||||
* @template {T}
|
||||
* @template T
|
||||
*/
|
||||
function Zet(t) {
|
||||
>Zet : typeof Zet
|
||||
|
||||
47
tests/baselines/reference/jsdocTemplateTag3.errors.txt
Normal file
47
tests/baselines/reference/jsdocTemplateTag3.errors.txt
Normal file
@ -0,0 +1,47 @@
|
||||
tests/cases/conformance/jsdoc/a.js(14,29): error TS2339: Property 'a' does not exist on type 'U'.
|
||||
tests/cases/conformance/jsdoc/a.js(14,35): error TS2339: Property 'b' does not exist on type 'U'.
|
||||
tests/cases/conformance/jsdoc/a.js(21,3): error TS2345: Argument of type '{ a: number; }' is not assignable to parameter of type '{ a: number; b: string; }'.
|
||||
Property 'b' is missing in type '{ a: number; }'.
|
||||
tests/cases/conformance/jsdoc/a.js(25,2): error TS1069: Unexpected token. A type parameter name was expected without curly braces.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/a.js (4 errors) ====
|
||||
/**
|
||||
* @template {{ a: number, b: string }} T,U A Comment
|
||||
* @template {{ c: boolean }} V uh ... are comments even supported??
|
||||
* @template W
|
||||
* @template X That last one had no comment
|
||||
* @param {T} t
|
||||
* @param {U} u
|
||||
* @param {V} v
|
||||
* @param {W} w
|
||||
* @param {X} x
|
||||
* @return {W | X}
|
||||
*/
|
||||
function f(t, u, v, w, x) {
|
||||
if(t.a + t.b.length > u.a - u.b.length && v.c) {
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'U'.
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'U'.
|
||||
return w;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
f({ a: 12, b: 'hi', c: null }, undefined, { c: false, d: 12, b: undefined }, 101, 'nope');
|
||||
f({ a: 12 }, undefined, undefined, 101, 'nope');
|
||||
~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '{ a: number; }' is not assignable to parameter of type '{ a: number; b: string; }'.
|
||||
!!! error TS2345: Property 'b' is missing in type '{ a: number; }'.
|
||||
|
||||
/**
|
||||
* @template {NoLongerAllowed}
|
||||
* @template T preceding line's syntax is no longer allowed
|
||||
~
|
||||
!!! error TS1069: Unexpected token. A type parameter name was expected without curly braces.
|
||||
* @param {T} x
|
||||
*/
|
||||
function g(x) { }
|
||||
|
||||
|
||||
70
tests/baselines/reference/jsdocTemplateTag3.symbols
Normal file
70
tests/baselines/reference/jsdocTemplateTag3.symbols
Normal file
@ -0,0 +1,70 @@
|
||||
=== tests/cases/conformance/jsdoc/a.js ===
|
||||
/**
|
||||
* @template {{ a: number, b: string }} T,U A Comment
|
||||
* @template {{ c: boolean }} V uh ... are comments even supported??
|
||||
* @template W
|
||||
* @template X That last one had no comment
|
||||
* @param {T} t
|
||||
* @param {U} u
|
||||
* @param {V} v
|
||||
* @param {W} w
|
||||
* @param {X} x
|
||||
* @return {W | X}
|
||||
*/
|
||||
function f(t, u, v, w, x) {
|
||||
>f : Symbol(f, Decl(a.js, 0, 0))
|
||||
>t : Symbol(t, Decl(a.js, 12, 11))
|
||||
>u : Symbol(u, Decl(a.js, 12, 13))
|
||||
>v : Symbol(v, Decl(a.js, 12, 16))
|
||||
>w : Symbol(w, Decl(a.js, 12, 19))
|
||||
>x : Symbol(x, Decl(a.js, 12, 22))
|
||||
|
||||
if(t.a + t.b.length > u.a - u.b.length && v.c) {
|
||||
>t.a : Symbol(a, Decl(a.js, 1, 15))
|
||||
>t : Symbol(t, Decl(a.js, 12, 11))
|
||||
>a : Symbol(a, Decl(a.js, 1, 15))
|
||||
>t.b.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>t.b : Symbol(b, Decl(a.js, 1, 26))
|
||||
>t : Symbol(t, Decl(a.js, 12, 11))
|
||||
>b : Symbol(b, Decl(a.js, 1, 26))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>u : Symbol(u, Decl(a.js, 12, 13))
|
||||
>u : Symbol(u, Decl(a.js, 12, 13))
|
||||
>v.c : Symbol(c, Decl(a.js, 2, 15))
|
||||
>v : Symbol(v, Decl(a.js, 12, 16))
|
||||
>c : Symbol(c, Decl(a.js, 2, 15))
|
||||
|
||||
return w;
|
||||
>w : Symbol(w, Decl(a.js, 12, 19))
|
||||
}
|
||||
return x;
|
||||
>x : Symbol(x, Decl(a.js, 12, 22))
|
||||
}
|
||||
|
||||
f({ a: 12, b: 'hi', c: null }, undefined, { c: false, d: 12, b: undefined }, 101, 'nope');
|
||||
>f : Symbol(f, Decl(a.js, 0, 0))
|
||||
>a : Symbol(a, Decl(a.js, 19, 3))
|
||||
>b : Symbol(b, Decl(a.js, 19, 10))
|
||||
>c : Symbol(c, Decl(a.js, 19, 19))
|
||||
>undefined : Symbol(undefined)
|
||||
>c : Symbol(c, Decl(a.js, 19, 43))
|
||||
>d : Symbol(d, Decl(a.js, 19, 53))
|
||||
>b : Symbol(b, Decl(a.js, 19, 60))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
f({ a: 12 }, undefined, undefined, 101, 'nope');
|
||||
>f : Symbol(f, Decl(a.js, 0, 0))
|
||||
>a : Symbol(a, Decl(a.js, 20, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
/**
|
||||
* @template {NoLongerAllowed}
|
||||
* @template T preceding line's syntax is no longer allowed
|
||||
* @param {T} x
|
||||
*/
|
||||
function g(x) { }
|
||||
>g : Symbol(g, Decl(a.js, 20, 49))
|
||||
>x : Symbol(x, Decl(a.js, 27, 11))
|
||||
|
||||
|
||||
95
tests/baselines/reference/jsdocTemplateTag3.types
Normal file
95
tests/baselines/reference/jsdocTemplateTag3.types
Normal file
@ -0,0 +1,95 @@
|
||||
=== tests/cases/conformance/jsdoc/a.js ===
|
||||
/**
|
||||
* @template {{ a: number, b: string }} T,U A Comment
|
||||
* @template {{ c: boolean }} V uh ... are comments even supported??
|
||||
* @template W
|
||||
* @template X That last one had no comment
|
||||
* @param {T} t
|
||||
* @param {U} u
|
||||
* @param {V} v
|
||||
* @param {W} w
|
||||
* @param {X} x
|
||||
* @return {W | X}
|
||||
*/
|
||||
function f(t, u, v, w, x) {
|
||||
>f : <T extends { a: number; b: string; }, U, V extends { c: boolean; }, W, X>(t: T, u: U, v: V, w: W, x: X) => W | X
|
||||
>t : T
|
||||
>u : U
|
||||
>v : V
|
||||
>w : W
|
||||
>x : X
|
||||
|
||||
if(t.a + t.b.length > u.a - u.b.length && v.c) {
|
||||
>t.a + t.b.length > u.a - u.b.length && v.c : boolean
|
||||
>t.a + t.b.length > u.a - u.b.length : boolean
|
||||
>t.a + t.b.length : number
|
||||
>t.a : number
|
||||
>t : T
|
||||
>a : number
|
||||
>t.b.length : number
|
||||
>t.b : string
|
||||
>t : T
|
||||
>b : string
|
||||
>length : number
|
||||
>u.a - u.b.length : number
|
||||
>u.a : any
|
||||
>u : U
|
||||
>a : any
|
||||
>u.b.length : any
|
||||
>u.b : any
|
||||
>u : U
|
||||
>b : any
|
||||
>length : any
|
||||
>v.c : boolean
|
||||
>v : V
|
||||
>c : boolean
|
||||
|
||||
return w;
|
||||
>w : W
|
||||
}
|
||||
return x;
|
||||
>x : X
|
||||
}
|
||||
|
||||
f({ a: 12, b: 'hi', c: null }, undefined, { c: false, d: 12, b: undefined }, 101, 'nope');
|
||||
>f({ a: 12, b: 'hi', c: null }, undefined, { c: false, d: 12, b: undefined }, 101, 'nope') : string | number
|
||||
>f : <T extends { a: number; b: string; }, U, V extends { c: boolean; }, W, X>(t: T, u: U, v: V, w: W, x: X) => W | X
|
||||
>{ a: 12, b: 'hi', c: null } : { a: number; b: string; c: null; }
|
||||
>a : number
|
||||
>12 : 12
|
||||
>b : string
|
||||
>'hi' : "hi"
|
||||
>c : null
|
||||
>null : null
|
||||
>undefined : undefined
|
||||
>{ c: false, d: 12, b: undefined } : { c: false; d: number; b: undefined; }
|
||||
>c : false
|
||||
>false : false
|
||||
>d : number
|
||||
>12 : 12
|
||||
>b : undefined
|
||||
>undefined : undefined
|
||||
>101 : 101
|
||||
>'nope' : "nope"
|
||||
|
||||
f({ a: 12 }, undefined, undefined, 101, 'nope');
|
||||
>f({ a: 12 }, undefined, undefined, 101, 'nope') : any
|
||||
>f : <T extends { a: number; b: string; }, U, V extends { c: boolean; }, W, X>(t: T, u: U, v: V, w: W, x: X) => W | X
|
||||
>{ a: 12 } : { a: number; }
|
||||
>a : number
|
||||
>12 : 12
|
||||
>undefined : undefined
|
||||
>undefined : undefined
|
||||
>101 : 101
|
||||
>'nope' : "nope"
|
||||
|
||||
/**
|
||||
* @template {NoLongerAllowed}
|
||||
* @template T preceding line's syntax is no longer allowed
|
||||
* @param {T} x
|
||||
*/
|
||||
function g(x) { }
|
||||
>g : <T>(x: T) => void
|
||||
>x : T
|
||||
|
||||
|
||||
@ -2,13 +2,13 @@
|
||||
{
|
||||
"marker": {
|
||||
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags.ts",
|
||||
"position": 258
|
||||
"position": 256
|
||||
},
|
||||
"quickInfo": {
|
||||
"kind": "function",
|
||||
"kindModifiers": "",
|
||||
"textSpan": {
|
||||
"start": 258,
|
||||
"start": 256,
|
||||
"length": 3
|
||||
},
|
||||
"displayParts": [
|
||||
@ -78,7 +78,7 @@
|
||||
},
|
||||
{
|
||||
"name": "template",
|
||||
"text": "{T} A template"
|
||||
"text": "T A template"
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
tests/cases/conformance/jsdoc/a.js(16,12): error TS2314: Generic type 'Everything' requires 5 type argument(s).
|
||||
tests/cases/conformance/jsdoc/test.ts(1,34): error TS2344: Type '{ a: number; }' does not satisfy the constraint '{ a: number; b: string; }'.
|
||||
Property 'b' is missing in type '{ a: number; }'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/a.js (1 errors) ====
|
||||
/**
|
||||
* @template {{ a: number, b: string }} T,U A Comment
|
||||
* @template {{ c: boolean }} V uh ... are comments even supported??
|
||||
* @template W
|
||||
* @template X That last one had no comment
|
||||
* @typedef {{ t: T, u: U, v: V, w: W, x: X }} Everything
|
||||
*/
|
||||
|
||||
/** @type {Everything<{ a: number, b: 'hi', c: never }, undefined, { c: true, d: 1 }, number, string>} */
|
||||
var tuvwx;
|
||||
|
||||
// TODO: will error when #24592 is fixed
|
||||
/** @type {Everything<{ a: number }, undefined, { c: 1, d: 1 }, number, string>} */
|
||||
var wrong;
|
||||
|
||||
/** @type {Everything<{ a: number }>} */
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2314: Generic type 'Everything' requires 5 type argument(s).
|
||||
var insufficient;
|
||||
|
||||
==== tests/cases/conformance/jsdoc/test.ts (1 errors) ====
|
||||
declare var actually: Everything<{ a: number }, undefined, { c: 1, d: 1 }, number, string>;
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2344: Type '{ a: number; }' does not satisfy the constraint '{ a: number; b: string; }'.
|
||||
!!! error TS2344: Property 'b' is missing in type '{ a: number; }'.
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
=== tests/cases/conformance/jsdoc/a.js ===
|
||||
/**
|
||||
* @template {{ a: number, b: string }} T,U A Comment
|
||||
* @template {{ c: boolean }} V uh ... are comments even supported??
|
||||
* @template W
|
||||
* @template X That last one had no comment
|
||||
* @typedef {{ t: T, u: U, v: V, w: W, x: X }} Everything
|
||||
*/
|
||||
|
||||
/** @type {Everything<{ a: number, b: 'hi', c: never }, undefined, { c: true, d: 1 }, number, string>} */
|
||||
var tuvwx;
|
||||
>tuvwx : Symbol(tuvwx, Decl(a.js, 9, 3))
|
||||
|
||||
// TODO: will error when #24592 is fixed
|
||||
/** @type {Everything<{ a: number }, undefined, { c: 1, d: 1 }, number, string>} */
|
||||
var wrong;
|
||||
>wrong : Symbol(wrong, Decl(a.js, 13, 3))
|
||||
|
||||
/** @type {Everything<{ a: number }>} */
|
||||
var insufficient;
|
||||
>insufficient : Symbol(insufficient, Decl(a.js, 16, 3))
|
||||
|
||||
=== tests/cases/conformance/jsdoc/test.ts ===
|
||||
declare var actually: Everything<{ a: number }, undefined, { c: 1, d: 1 }, number, string>;
|
||||
>actually : Symbol(actually, Decl(test.ts, 0, 11))
|
||||
>Everything : Symbol(Everything, Decl(a.js, 5, 3))
|
||||
>a : Symbol(a, Decl(test.ts, 0, 34))
|
||||
>c : Symbol(c, Decl(test.ts, 0, 61))
|
||||
>d : Symbol(d, Decl(test.ts, 0, 67))
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
=== tests/cases/conformance/jsdoc/a.js ===
|
||||
/**
|
||||
* @template {{ a: number, b: string }} T,U A Comment
|
||||
* @template {{ c: boolean }} V uh ... are comments even supported??
|
||||
* @template W
|
||||
* @template X That last one had no comment
|
||||
* @typedef {{ t: T, u: U, v: V, w: W, x: X }} Everything
|
||||
*/
|
||||
|
||||
/** @type {Everything<{ a: number, b: 'hi', c: never }, undefined, { c: true, d: 1 }, number, string>} */
|
||||
var tuvwx;
|
||||
>tuvwx : { t: { a: number; b: "hi"; c: never; }; u: undefined; v: { c: true; d: 1; }; w: number; x: string; }
|
||||
|
||||
// TODO: will error when #24592 is fixed
|
||||
/** @type {Everything<{ a: number }, undefined, { c: 1, d: 1 }, number, string>} */
|
||||
var wrong;
|
||||
>wrong : { t: { a: number; }; u: undefined; v: { c: 1; d: 1; }; w: number; x: string; }
|
||||
|
||||
/** @type {Everything<{ a: number }>} */
|
||||
var insufficient;
|
||||
>insufficient : any
|
||||
|
||||
=== tests/cases/conformance/jsdoc/test.ts ===
|
||||
declare var actually: Everything<{ a: number }, undefined, { c: 1, d: 1 }, number, string>;
|
||||
>actually : { t: { a: number; }; u: undefined; v: { c: 1; d: 1; }; w: number; x: string; }
|
||||
>Everything : { t: T; u: U; v: V; w: W; x: X; }
|
||||
>a : number
|
||||
>c : 1
|
||||
>d : 1
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
// @Filename: templateTagOnClasses.js
|
||||
|
||||
/**
|
||||
* @template {T}
|
||||
* @template T
|
||||
* @typedef {(t: T) => T} Id
|
||||
*/
|
||||
/** @template T */
|
||||
|
||||
@ -4,12 +4,12 @@
|
||||
// @Filename: templateTagOnConstructorFunctions.js
|
||||
|
||||
/**
|
||||
* @template {U}
|
||||
* @template U
|
||||
* @typedef {(u: U) => U} Id
|
||||
*/
|
||||
/**
|
||||
* @param {T} t
|
||||
* @template {T}
|
||||
* @template T
|
||||
*/
|
||||
function Zet(t) {
|
||||
/** @type {T} */
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
/**
|
||||
* @param {T} t
|
||||
* @template {T}
|
||||
* @template T
|
||||
*/
|
||||
function Zet(t) {
|
||||
/** @type {T} */
|
||||
|
||||
33
tests/cases/conformance/jsdoc/jsdocTemplateTag3.ts
Normal file
33
tests/cases/conformance/jsdoc/jsdocTemplateTag3.ts
Normal file
@ -0,0 +1,33 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noEmit: true
|
||||
// @Filename: a.js
|
||||
/**
|
||||
* @template {{ a: number, b: string }} T,U A Comment
|
||||
* @template {{ c: boolean }} V uh ... are comments even supported??
|
||||
* @template W
|
||||
* @template X That last one had no comment
|
||||
* @param {T} t
|
||||
* @param {U} u
|
||||
* @param {V} v
|
||||
* @param {W} w
|
||||
* @param {X} x
|
||||
* @return {W | X}
|
||||
*/
|
||||
function f(t, u, v, w, x) {
|
||||
if(t.a + t.b.length > u.a - u.b.length && v.c) {
|
||||
return w;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
f({ a: 12, b: 'hi', c: null }, undefined, { c: false, d: 12, b: undefined }, 101, 'nope');
|
||||
f({ a: 12 }, undefined, undefined, 101, 'nope');
|
||||
|
||||
/**
|
||||
* @template {NoLongerAllowed}
|
||||
* @template T preceding line's syntax is no longer allowed
|
||||
* @param {T} x
|
||||
*/
|
||||
function g(x) { }
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noEmit: true
|
||||
// @Filename: a.js
|
||||
/**
|
||||
* @template {{ a: number, b: string }} T,U A Comment
|
||||
* @template {{ c: boolean }} V uh ... are comments even supported??
|
||||
* @template W
|
||||
* @template X That last one had no comment
|
||||
* @typedef {{ t: T, u: U, v: V, w: W, x: X }} Everything
|
||||
*/
|
||||
|
||||
/** @type {Everything<{ a: number, b: 'hi', c: never }, undefined, { c: true, d: 1 }, number, string>} */
|
||||
var tuvwx;
|
||||
|
||||
// TODO: will error when #24592 is fixed
|
||||
/** @type {Everything<{ a: number }, undefined, { c: 1, d: 1 }, number, string>} */
|
||||
var wrong;
|
||||
|
||||
/** @type {Everything<{ a: number }>} */
|
||||
var insufficient;
|
||||
|
||||
// @Filename: test.ts
|
||||
declare var actually: Everything<{ a: number }, undefined, { c: 1, d: 1 }, number, string>;
|
||||
@ -1,7 +1,7 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
/////**
|
||||
//// * @template {T}
|
||||
//// * @template T
|
||||
//// * @param {T} x
|
||||
//// * @returns {T}
|
||||
//// */
|
||||
@ -11,7 +11,7 @@ verify.codeFix({
|
||||
description: "Annotate with type from JSDoc",
|
||||
newFileContent:
|
||||
`/**
|
||||
* @template {T}
|
||||
* @template T
|
||||
* @param {T} x
|
||||
* @returns {T}
|
||||
*/
|
||||
|
||||
@ -17,7 +17,7 @@ verify.signatureHelp({
|
||||
text: "find<T>(l: T[], x: T): T",
|
||||
docComment: "Find an item",
|
||||
tags: [
|
||||
// TODO: GH#24130
|
||||
// TODO: GH#24130 (see PR #24600's commits for potential fix)
|
||||
{ name: "template", text: "T\n " },
|
||||
{ name: "param", text: "l" },
|
||||
{ name: "param", text: "x" },
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
//// * Doc
|
||||
//// * @author Me
|
||||
//// * @augments {C<T>} Augments it
|
||||
//// * @template {T} A template
|
||||
//// * @template T A template
|
||||
//// * @type {number | string} A type
|
||||
//// * @typedef {number | string} NumOrStr
|
||||
//// * @property {number} x The prop
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user