mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Fix name resolution in typedef and allow defaults for template tags (#45483)
* Fix name resolution in typedef and allow defaults for template tags * Inline parseBracketNameInTemplateTag * Update baselines * Add js declaration emit tests
This commit is contained in:
parent
8610ff5ebe
commit
cf787e9bcf
@ -3388,7 +3388,7 @@ namespace ts {
|
||||
|
||||
function bindTypeParameter(node: TypeParameterDeclaration) {
|
||||
if (isJSDocTemplateTag(node.parent)) {
|
||||
const container = find((node.parent.parent as JSDoc).tags!, isJSDocTypeAlias) || getHostSignatureFromJSDoc(node.parent); // TODO: GH#18217
|
||||
const container = getEffectiveContainerForJSDocTemplateTag(node.parent);
|
||||
if (container) {
|
||||
if (!container.locals) {
|
||||
container.locals = createSymbolTable();
|
||||
|
||||
@ -2052,7 +2052,9 @@ namespace ts {
|
||||
lastSelfReferenceLocation = location;
|
||||
}
|
||||
lastLocation = location;
|
||||
location = location.parent;
|
||||
location = isJSDocTemplateTag(location) ?
|
||||
getEffectiveContainerForJSDocTemplateTag(location) || location.parent :
|
||||
location.parent;
|
||||
}
|
||||
|
||||
// We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`.
|
||||
@ -12901,7 +12903,7 @@ namespace ts {
|
||||
|
||||
function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol | undefined {
|
||||
const tp = getDeclarationOfKind<TypeParameterDeclaration>(typeParameter.symbol, SyntaxKind.TypeParameter)!;
|
||||
const host = isJSDocTemplateTag(tp.parent) ? getHostSignatureFromJSDoc(tp.parent) : tp.parent;
|
||||
const host = isJSDocTemplateTag(tp.parent) ? getEffectiveContainerForJSDocTemplateTag(tp.parent) : tp.parent;
|
||||
return host && getSymbolOfNode(host);
|
||||
}
|
||||
|
||||
@ -33673,7 +33675,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
checkTypeParameters(node.typeParameters);
|
||||
checkTypeParameters(getEffectiveTypeParameterDeclarations(node));
|
||||
|
||||
forEach(node.parameters, checkParameter);
|
||||
|
||||
@ -35306,6 +35308,7 @@ namespace ts {
|
||||
checkTypeNameIsReserved(node.name, Diagnostics.Type_alias_name_cannot_be_0);
|
||||
}
|
||||
checkSourceElement(node.typeExpression);
|
||||
checkTypeParameters(getEffectiveTypeParameterDeclarations(node));
|
||||
}
|
||||
|
||||
function checkJSDocTemplateTag(node: JSDocTemplateTag): void {
|
||||
|
||||
@ -8441,11 +8441,24 @@ namespace ts {
|
||||
|
||||
function parseTemplateTagTypeParameter() {
|
||||
const typeParameterPos = getNodePos();
|
||||
const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);
|
||||
if (isBracketed) {
|
||||
skipWhitespace();
|
||||
}
|
||||
const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
|
||||
|
||||
let defaultType: TypeNode | undefined;
|
||||
if (isBracketed) {
|
||||
skipWhitespace();
|
||||
parseExpected(SyntaxKind.EqualsToken);
|
||||
defaultType = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
}
|
||||
|
||||
if (nodeIsMissing(name)) {
|
||||
return undefined;
|
||||
}
|
||||
return finishNode(factory.createTypeParameterDeclaration(name, /*constraint*/ undefined, /*defaultType*/ undefined), typeParameterPos);
|
||||
return finishNode(factory.createTypeParameterDeclaration(name, /*constraint*/ undefined, defaultType), typeParameterPos);
|
||||
}
|
||||
|
||||
function parseTemplateTagTypeParameters() {
|
||||
|
||||
@ -2723,6 +2723,18 @@ namespace ts {
|
||||
return parameter && parameter.symbol;
|
||||
}
|
||||
|
||||
export function getEffectiveContainerForJSDocTemplateTag(node: JSDocTemplateTag) {
|
||||
if (isJSDoc(node.parent) && node.parent.tags) {
|
||||
// A @template tag belongs to any @typedef, @callback, or @enum tags in the same comment block, if they exist.
|
||||
const typeAlias = find(node.parent.tags, isJSDocTypeAlias);
|
||||
if (typeAlias) {
|
||||
return typeAlias;
|
||||
}
|
||||
}
|
||||
// otherwise it belongs to the host it annotates
|
||||
return getHostSignatureFromJSDoc(node);
|
||||
}
|
||||
|
||||
export function getHostSignatureFromJSDoc(node: Node): SignatureDeclaration | undefined {
|
||||
const host = getEffectiveJSDocHost(node);
|
||||
return host && isFunctionLike(host) ? host : undefined;
|
||||
|
||||
90
tests/baselines/reference/jsdocTemplateTagDefault.errors.txt
Normal file
90
tests/baselines/reference/jsdocTemplateTagDefault.errors.txt
Normal file
@ -0,0 +1,90 @@
|
||||
tests/cases/conformance/jsdoc/file.js(9,20): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsdoc/file.js(22,34): error TS1005: '=' expected.
|
||||
tests/cases/conformance/jsdoc/file.js(27,35): error TS1110: Type expected.
|
||||
tests/cases/conformance/jsdoc/file.js(33,14): error TS2706: Required type parameters may not follow optional type parameters.
|
||||
tests/cases/conformance/jsdoc/file.js(38,17): error TS2744: Type parameter defaults can only reference previously declared type parameters.
|
||||
tests/cases/conformance/jsdoc/file.js(53,14): error TS2706: Required type parameters may not follow optional type parameters.
|
||||
tests/cases/conformance/jsdoc/file.js(60,17): error TS2744: Type parameter defaults can only reference previously declared type parameters.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/file.js (7 errors) ====
|
||||
/**
|
||||
* @template {string | number} [T=string] - ok: defaults are permitted
|
||||
* @typedef {[T]} A
|
||||
*/
|
||||
|
||||
/** @type {A} */ // ok, default for `T` in `A` is `string`
|
||||
const aDefault1 = [""];
|
||||
/** @type {A} */ // error: `number` is not assignable to string`
|
||||
const aDefault2 = [0];
|
||||
~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
/** @type {A<string>} */ // ok, `T` is provided for `A`
|
||||
const aString = [""];
|
||||
/** @type {A<number>} */ // ok, `T` is provided for `A`
|
||||
const aNumber = [0];
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @typedef {[T, U]} B
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T] - error: default requires an `=type`
|
||||
~
|
||||
!!! error TS1005: '=' expected.
|
||||
* @typedef {[T]} C
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=] - error: default requires a `type`
|
||||
~
|
||||
!!! error TS1110: Type expected.
|
||||
* @typedef {[T]} D
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
~
|
||||
!!! error TS2706: Required type parameters may not follow optional type parameters.
|
||||
* @typedef {[T, U]} E
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
~
|
||||
!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @typedef {[T, U]} G
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f1(a, b) {}
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
~
|
||||
!!! error TS2706: Required type parameters may not follow optional type parameters.
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f2(a, b) {}
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
~
|
||||
!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f3(a, b) {}
|
||||
|
||||
186
tests/baselines/reference/jsdocTemplateTagDefault.js
Normal file
186
tests/baselines/reference/jsdocTemplateTagDefault.js
Normal file
@ -0,0 +1,186 @@
|
||||
//// [file.js]
|
||||
/**
|
||||
* @template {string | number} [T=string] - ok: defaults are permitted
|
||||
* @typedef {[T]} A
|
||||
*/
|
||||
|
||||
/** @type {A} */ // ok, default for `T` in `A` is `string`
|
||||
const aDefault1 = [""];
|
||||
/** @type {A} */ // error: `number` is not assignable to string`
|
||||
const aDefault2 = [0];
|
||||
/** @type {A<string>} */ // ok, `T` is provided for `A`
|
||||
const aString = [""];
|
||||
/** @type {A<number>} */ // ok, `T` is provided for `A`
|
||||
const aNumber = [0];
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @typedef {[T, U]} B
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T] - error: default requires an `=type`
|
||||
* @typedef {[T]} C
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=] - error: default requires a `type`
|
||||
* @typedef {[T]} D
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @typedef {[T, U]} E
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @typedef {[T, U]} G
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f1(a, b) {}
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f2(a, b) {}
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f3(a, b) {}
|
||||
|
||||
|
||||
//// [file.js]
|
||||
/**
|
||||
* @template {string | number} [T=string] - ok: defaults are permitted
|
||||
* @typedef {[T]} A
|
||||
*/
|
||||
/** @type {A} */ // ok, default for `T` in `A` is `string`
|
||||
var aDefault1 = [""];
|
||||
/** @type {A} */ // error: `number` is not assignable to string`
|
||||
var aDefault2 = [0];
|
||||
/** @type {A<string>} */ // ok, `T` is provided for `A`
|
||||
var aString = [""];
|
||||
/** @type {A<number>} */ // ok, `T` is provided for `A`
|
||||
var aNumber = [0];
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @typedef {[T, U]} B
|
||||
*/
|
||||
/**
|
||||
* @template {string | number} [T] - error: default requires an `=type`
|
||||
* @typedef {[T]} C
|
||||
*/
|
||||
/**
|
||||
* @template {string | number} [T=] - error: default requires a `type`
|
||||
* @typedef {[T]} D
|
||||
*/
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @typedef {[T, U]} E
|
||||
*/
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @typedef {[T, U]} G
|
||||
*/
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f1(a, b) { }
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f2(a, b) { }
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f3(a, b) { }
|
||||
|
||||
|
||||
//// [file.d.ts]
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @typedef {[T, U]} B
|
||||
*/
|
||||
/**
|
||||
* @template {string | number} [T] - error: default requires an `=type`
|
||||
* @typedef {[T]} C
|
||||
*/
|
||||
/**
|
||||
* @template {string | number} [T=] - error: default requires a `type`
|
||||
* @typedef {[T]} D
|
||||
*/
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @typedef {[T, U]} E
|
||||
*/
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @typedef {[T, U]} G
|
||||
*/
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
declare function f1<T, U = T>(a: T, b: U): void;
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
declare function f2<T extends string | number = string, U>(a: T, b: U): void;
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
declare function f3<T = U, U = T>(a: T, b: U): void;
|
||||
/**
|
||||
* @template {string | number} [T=string] - ok: defaults are permitted
|
||||
* @typedef {[T]} A
|
||||
*/
|
||||
/** @type {A} */ declare const aDefault1: A<string>;
|
||||
/** @type {A} */ declare const aDefault2: A<string>;
|
||||
/** @type {A<string>} */ declare const aString: A<string>;
|
||||
/** @type {A<number>} */ declare const aNumber: A<number>;
|
||||
type B<T, U = T> = [T, U];
|
||||
type C<T extends string | number = any> = [T];
|
||||
type D<T extends string | number = any> = [T];
|
||||
type E<T extends string | number = string, U> = [T, U];
|
||||
type G<T = U, U = T> = [T, U];
|
||||
type A<T extends string | number = string> = [T];
|
||||
83
tests/baselines/reference/jsdocTemplateTagDefault.symbols
Normal file
83
tests/baselines/reference/jsdocTemplateTagDefault.symbols
Normal file
@ -0,0 +1,83 @@
|
||||
=== tests/cases/conformance/jsdoc/file.js ===
|
||||
/**
|
||||
* @template {string | number} [T=string] - ok: defaults are permitted
|
||||
* @typedef {[T]} A
|
||||
*/
|
||||
|
||||
/** @type {A} */ // ok, default for `T` in `A` is `string`
|
||||
const aDefault1 = [""];
|
||||
>aDefault1 : Symbol(aDefault1, Decl(file.js, 6, 5))
|
||||
|
||||
/** @type {A} */ // error: `number` is not assignable to string`
|
||||
const aDefault2 = [0];
|
||||
>aDefault2 : Symbol(aDefault2, Decl(file.js, 8, 5))
|
||||
|
||||
/** @type {A<string>} */ // ok, `T` is provided for `A`
|
||||
const aString = [""];
|
||||
>aString : Symbol(aString, Decl(file.js, 10, 5))
|
||||
|
||||
/** @type {A<number>} */ // ok, `T` is provided for `A`
|
||||
const aNumber = [0];
|
||||
>aNumber : Symbol(aNumber, Decl(file.js, 12, 5))
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @typedef {[T, U]} B
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T] - error: default requires an `=type`
|
||||
* @typedef {[T]} C
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=] - error: default requires a `type`
|
||||
* @typedef {[T]} D
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @typedef {[T, U]} E
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @typedef {[T, U]} G
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f1(a, b) {}
|
||||
>f1 : Symbol(f1, Decl(file.js, 12, 20))
|
||||
>a : Symbol(a, Decl(file.js, 48, 12))
|
||||
>b : Symbol(b, Decl(file.js, 48, 14))
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f2(a, b) {}
|
||||
>f2 : Symbol(f2, Decl(file.js, 48, 20))
|
||||
>a : Symbol(a, Decl(file.js, 56, 12))
|
||||
>b : Symbol(b, Decl(file.js, 56, 14))
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f3(a, b) {}
|
||||
>f3 : Symbol(f3, Decl(file.js, 56, 20))
|
||||
>a : Symbol(a, Decl(file.js, 64, 12))
|
||||
>b : Symbol(b, Decl(file.js, 64, 14))
|
||||
|
||||
91
tests/baselines/reference/jsdocTemplateTagDefault.types
Normal file
91
tests/baselines/reference/jsdocTemplateTagDefault.types
Normal file
@ -0,0 +1,91 @@
|
||||
=== tests/cases/conformance/jsdoc/file.js ===
|
||||
/**
|
||||
* @template {string | number} [T=string] - ok: defaults are permitted
|
||||
* @typedef {[T]} A
|
||||
*/
|
||||
|
||||
/** @type {A} */ // ok, default for `T` in `A` is `string`
|
||||
const aDefault1 = [""];
|
||||
>aDefault1 : A<string>
|
||||
>[""] : [string]
|
||||
>"" : ""
|
||||
|
||||
/** @type {A} */ // error: `number` is not assignable to string`
|
||||
const aDefault2 = [0];
|
||||
>aDefault2 : A<string>
|
||||
>[0] : [number]
|
||||
>0 : 0
|
||||
|
||||
/** @type {A<string>} */ // ok, `T` is provided for `A`
|
||||
const aString = [""];
|
||||
>aString : A<string>
|
||||
>[""] : [string]
|
||||
>"" : ""
|
||||
|
||||
/** @type {A<number>} */ // ok, `T` is provided for `A`
|
||||
const aNumber = [0];
|
||||
>aNumber : A<number>
|
||||
>[0] : [number]
|
||||
>0 : 0
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @typedef {[T, U]} B
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T] - error: default requires an `=type`
|
||||
* @typedef {[T]} C
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=] - error: default requires a `type`
|
||||
* @typedef {[T]} D
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @typedef {[T, U]} E
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @typedef {[T, U]} G
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f1(a, b) {}
|
||||
>f1 : <T, U = T>(a: T, b: U) => void
|
||||
>a : T
|
||||
>b : U
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f2(a, b) {}
|
||||
>f2 : <T extends string | number = string, U>(a: T, b: U) => void
|
||||
>a : T
|
||||
>b : U
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f3(a, b) {}
|
||||
>f3 : <T = U, U = T>(a: T, b: U) => void
|
||||
>a : T
|
||||
>b : U
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
tests/cases/conformance/jsdoc/file.js(10,7): error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/file.js (1 errors) ====
|
||||
/**
|
||||
* @template T
|
||||
* @template {keyof T} K
|
||||
* @typedef {T[K]} Foo
|
||||
*/
|
||||
|
||||
const x = { a: 1 };
|
||||
|
||||
/** @type {Foo<typeof x, "a">} */
|
||||
const y = "a";
|
||||
~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
30
tests/baselines/reference/jsdocTemplateTagNameResolution.js
Normal file
30
tests/baselines/reference/jsdocTemplateTagNameResolution.js
Normal file
@ -0,0 +1,30 @@
|
||||
//// [file.js]
|
||||
/**
|
||||
* @template T
|
||||
* @template {keyof T} K
|
||||
* @typedef {T[K]} Foo
|
||||
*/
|
||||
|
||||
const x = { a: 1 };
|
||||
|
||||
/** @type {Foo<typeof x, "a">} */
|
||||
const y = "a";
|
||||
|
||||
//// [file.js]
|
||||
/**
|
||||
* @template T
|
||||
* @template {keyof T} K
|
||||
* @typedef {T[K]} Foo
|
||||
*/
|
||||
var x = { a: 1 };
|
||||
/** @type {Foo<typeof x, "a">} */
|
||||
var y = "a";
|
||||
|
||||
|
||||
//// [file.d.ts]
|
||||
declare namespace x {
|
||||
const a: number;
|
||||
}
|
||||
/** @type {Foo<typeof x, "a">} */
|
||||
declare const y: Foo<typeof x, "a">;
|
||||
type Foo<T, K extends keyof T> = T[K];
|
||||
@ -0,0 +1,15 @@
|
||||
=== tests/cases/conformance/jsdoc/file.js ===
|
||||
/**
|
||||
* @template T
|
||||
* @template {keyof T} K
|
||||
* @typedef {T[K]} Foo
|
||||
*/
|
||||
|
||||
const x = { a: 1 };
|
||||
>x : Symbol(x, Decl(file.js, 6, 5))
|
||||
>a : Symbol(a, Decl(file.js, 6, 11))
|
||||
|
||||
/** @type {Foo<typeof x, "a">} */
|
||||
const y = "a";
|
||||
>y : Symbol(y, Decl(file.js, 9, 5))
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
=== tests/cases/conformance/jsdoc/file.js ===
|
||||
/**
|
||||
* @template T
|
||||
* @template {keyof T} K
|
||||
* @typedef {T[K]} Foo
|
||||
*/
|
||||
|
||||
const x = { a: 1 };
|
||||
>x : { a: number; }
|
||||
>{ a: 1 } : { a: number; }
|
||||
>a : number
|
||||
>1 : 1
|
||||
|
||||
/** @type {Foo<typeof x, "a">} */
|
||||
const y = "a";
|
||||
>y : number
|
||||
>"a" : "a"
|
||||
|
||||
71
tests/cases/conformance/jsdoc/jsdocTemplateTagDefault.ts
Normal file
71
tests/cases/conformance/jsdoc/jsdocTemplateTagDefault.ts
Normal file
@ -0,0 +1,71 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @declaration: true
|
||||
// @outDir: out
|
||||
// @Filename: file.js
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string] - ok: defaults are permitted
|
||||
* @typedef {[T]} A
|
||||
*/
|
||||
|
||||
/** @type {A} */ // ok, default for `T` in `A` is `string`
|
||||
const aDefault1 = [""];
|
||||
/** @type {A} */ // error: `number` is not assignable to string`
|
||||
const aDefault2 = [0];
|
||||
/** @type {A<string>} */ // ok, `T` is provided for `A`
|
||||
const aString = [""];
|
||||
/** @type {A<number>} */ // ok, `T` is provided for `A`
|
||||
const aNumber = [0];
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @typedef {[T, U]} B
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T] - error: default requires an `=type`
|
||||
* @typedef {[T]} C
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=] - error: default requires a `type`
|
||||
* @typedef {[T]} D
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @typedef {[T, U]} E
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @typedef {[T, U]} G
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template [U=T] - ok: default can reference earlier type parameter
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f1(a, b) {}
|
||||
|
||||
/**
|
||||
* @template {string | number} [T=string]
|
||||
* @template U - error: Required type parameters cannot follow optional type parameters
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f2(a, b) {}
|
||||
|
||||
/**
|
||||
* @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters.
|
||||
* @template [U=T]
|
||||
* @param {T} a
|
||||
* @param {U} b
|
||||
*/
|
||||
function f3(a, b) {}
|
||||
@ -0,0 +1,16 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @outDir: out
|
||||
// @declaration: true
|
||||
// @Filename: file.js
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template {keyof T} K
|
||||
* @typedef {T[K]} Foo
|
||||
*/
|
||||
|
||||
const x = { a: 1 };
|
||||
|
||||
/** @type {Foo<typeof x, "a">} */
|
||||
const y = "a";
|
||||
Loading…
x
Reference in New Issue
Block a user