@@ -222,6 +222,7 @@ import {
222
222
GetAccessorDeclaration,
223
223
getAliasDeclarationFromName,
224
224
getAllAccessorDeclarations,
225
+ getAllJSDocTags,
225
226
getAllowSyntheticDefaultImports,
226
227
getAncestor,
227
228
getAssignedExpandoInitializer,
@@ -284,6 +285,7 @@ import {
284
285
getJSDocHost,
285
286
getJSDocParameterTags,
286
287
getJSDocRoot,
288
+ getJSDocSatisfiesExpressionType,
287
289
getJSDocTags,
288
290
getJSDocThisTag,
289
291
getJSDocType,
@@ -557,6 +559,8 @@ import {
557
559
isJSDocPropertyLikeTag,
558
560
isJSDocPropertyTag,
559
561
isJSDocReturnTag,
562
+ isJSDocSatisfiesExpression,
563
+ isJSDocSatisfiesTag,
560
564
isJSDocSignature,
561
565
isJSDocTemplateTag,
562
566
isJSDocTypeAlias,
@@ -732,6 +736,7 @@ import {
732
736
JSDocPropertyTag,
733
737
JSDocProtectedTag,
734
738
JSDocPublicTag,
739
+ JSDocSatisfiesTag,
735
740
JSDocSignature,
736
741
JSDocTemplateTag,
737
742
JSDocTypedefTag,
@@ -972,6 +977,7 @@ import {
972
977
tryExtractTSExtension,
973
978
tryGetClassImplementingOrExtendingExpressionWithTypeArguments,
974
979
tryGetExtensionFromPath,
980
+ tryGetJSDocSatisfiesTypeNode,
975
981
tryGetModuleSpecifierFromDeclaration,
976
982
tryGetPropertyAccessOrIdentifierToString,
977
983
TryStatement,
@@ -28201,7 +28207,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
28201
28207
}
28202
28208
28203
28209
function getContextualTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, contextFlags: ContextFlags | undefined): Type | undefined {
28204
- const typeNode = getEffectiveTypeAnnotationNode(declaration);
28210
+ const typeNode = getEffectiveTypeAnnotationNode(declaration) || (isInJSFile(declaration) ? tryGetJSDocSatisfiesTypeNode(declaration) : undefined) ;
28205
28211
if (typeNode) {
28206
28212
return getTypeFromTypeNode(typeNode);
28207
28213
}
@@ -28884,11 +28890,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
28884
28890
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
28885
28891
return getContextualTypeForSubstitutionExpression(parent.parent as TemplateExpression, node);
28886
28892
case SyntaxKind.ParenthesizedExpression: {
28887
- // Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
28888
- const tag = isInJSFile(parent) ? getJSDocTypeTag(parent) : undefined;
28889
- return !tag ? getContextualType(parent as ParenthesizedExpression, contextFlags) :
28890
- isJSDocTypeTag(tag) && isConstTypeReference(tag.typeExpression.type) ? getContextualType(parent as ParenthesizedExpression, contextFlags) :
28891
- getTypeFromTypeNode(tag.typeExpression.type);
28893
+ if (isInJSFile(parent)) {
28894
+ if (isJSDocSatisfiesExpression(parent)) {
28895
+ return getTypeFromTypeNode(getJSDocSatisfiesExpressionType(parent));
28896
+ }
28897
+ // Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
28898
+ const typeTag = getJSDocTypeTag(parent);
28899
+ if (typeTag && !isConstTypeReference(typeTag.typeExpression.type)) {
28900
+ return getTypeFromTypeNode(typeTag.typeExpression.type);
28901
+ }
28902
+ }
28903
+ return getContextualType(parent as ParenthesizedExpression, contextFlags);
28892
28904
}
28893
28905
case SyntaxKind.NonNullExpression:
28894
28906
return getContextualType(parent as NonNullExpression, contextFlags);
@@ -33908,15 +33920,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
33908
33920
33909
33921
function checkSatisfiesExpression(node: SatisfiesExpression) {
33910
33922
checkSourceElement(node.type);
33911
- const exprType = checkExpression(node.expression);
33923
+ return checkSatisfiesExpressionWorker(node.expression, node.type);
33924
+ }
33912
33925
33913
- const targetType = getTypeFromTypeNode(node.type);
33926
+ function checkSatisfiesExpressionWorker(expression: Expression, target: TypeNode, checkMode?: CheckMode) {
33927
+ const exprType = checkExpression(expression, checkMode);
33928
+ const targetType = getTypeFromTypeNode(target);
33914
33929
if (isErrorType(targetType)) {
33915
33930
return targetType;
33916
33931
}
33917
-
33918
- checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, node.type, node.expression, Diagnostics.Type_0_does_not_satisfy_the_expected_type_1);
33919
-
33932
+ checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, target, expression, Diagnostics.Type_0_does_not_satisfy_the_expected_type_1);
33920
33933
return exprType;
33921
33934
}
33922
33935
@@ -36254,6 +36267,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
36254
36267
contextualType?: Type | undefined
36255
36268
) {
36256
36269
const initializer = getEffectiveInitializer(declaration)!;
36270
+ if (isInJSFile(declaration)) {
36271
+ const typeNode = tryGetJSDocSatisfiesTypeNode(declaration);
36272
+ if (typeNode) {
36273
+ return checkSatisfiesExpressionWorker(initializer, typeNode, checkMode);
36274
+ }
36275
+ }
36257
36276
const type = getQuickTypeOfExpression(initializer) ||
36258
36277
(contextualType ?
36259
36278
checkExpressionWithContextualType(initializer, contextualType, /*inferenceContext*/ undefined, checkMode || CheckMode.Normal)
@@ -36636,9 +36655,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
36636
36655
}
36637
36656
36638
36657
function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type {
36639
- if (hasJSDocNodes(node) && isJSDocTypeAssertion(node)) {
36640
- const type = getJSDocTypeAssertionType(node);
36641
- return checkAssertionWorker(type, type, node.expression, checkMode);
36658
+ if (hasJSDocNodes(node)) {
36659
+ if (isJSDocSatisfiesExpression(node)) {
36660
+ return checkSatisfiesExpressionWorker(node.expression, getJSDocSatisfiesExpressionType(node), checkMode);
36661
+ }
36662
+ if (isJSDocTypeAssertion(node)) {
36663
+ const type = getJSDocTypeAssertionType(node);
36664
+ return checkAssertionWorker(type, type, node.expression, checkMode);
36665
+ }
36642
36666
}
36643
36667
return checkExpression(node.expression, checkMode);
36644
36668
}
@@ -38873,6 +38897,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
38873
38897
checkSourceElement(node.typeExpression);
38874
38898
}
38875
38899
38900
+ function checkJSDocSatisfiesTag(node: JSDocSatisfiesTag) {
38901
+ checkSourceElement(node.typeExpression);
38902
+ const host = getEffectiveJSDocHost(node);
38903
+ if (host) {
38904
+ const tags = getAllJSDocTags(host, isJSDocSatisfiesTag);
38905
+ if (length(tags) > 1) {
38906
+ for (let i = 1; i < length(tags); i++) {
38907
+ const tagName = tags[i].tagName;
38908
+ error(tagName, Diagnostics._0_tag_already_specified, idText(tagName));
38909
+ }
38910
+ }
38911
+ }
38912
+ }
38913
+
38876
38914
function checkJSDocLinkLikeTag(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain) {
38877
38915
if (node.name) {
38878
38916
resolveJSDocMemberName(node.name, /*ignoreErrors*/ true);
@@ -43386,6 +43424,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
43386
43424
case SyntaxKind.JSDocProtectedTag:
43387
43425
case SyntaxKind.JSDocPrivateTag:
43388
43426
return checkJSDocAccessibilityModifiers(node as JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag);
43427
+ case SyntaxKind.JSDocSatisfiesTag:
43428
+ return checkJSDocSatisfiesTag(node as JSDocSatisfiesTag);
43389
43429
case SyntaxKind.IndexedAccessType:
43390
43430
return checkIndexedAccessType(node as IndexedAccessTypeNode);
43391
43431
case SyntaxKind.MappedType:
0 commit comments