Skip to content

Commit

Permalink
Fixed inlay hints for inferred type predicates (#86341)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist authored Jul 29, 2024
1 parent 6864825 commit d7ff565
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 1 deletion.
38 changes: 37 additions & 1 deletion src/services/inlayHints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ import {
TupleTypeReference,
Type,
TypeFlags,
TypePredicate,
unescapeLeadingUnderscores,
UserPreferences,
usingSingleLineStringWriter,
Expand Down Expand Up @@ -405,6 +406,16 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
return;
}

const typePredicate = checker.getTypePredicateOfSignature(signature);

if (typePredicate?.type) {
const hintParts = typePredicateToInlayHintParts(typePredicate);
if (hintParts) {
addTypeHints(hintParts, getTypeAnnotationPosition(decl));
return;
}
}

const returnType = checker.getReturnTypeOfSignature(signature);
if (isModuleReferenceType(returnType)) {
return;
Expand Down Expand Up @@ -474,17 +485,42 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
});
}

function printTypePredicateInSingleLine(typePredicate: TypePredicate) {
const flags = NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const printer = createPrinterWithRemoveComments();

return usingSingleLineStringWriter(writer => {
const typePredicateNode = checker.typePredicateToTypePredicateNode(typePredicate, /*enclosingDeclaration*/ undefined, flags);
Debug.assertIsDefined(typePredicateNode, "should always get typePredicateNode");
printer.writeNode(EmitHint.Unspecified, typePredicateNode, /*sourceFile*/ file, writer);
});
}

function typeToInlayHintParts(type: Type): InlayHintDisplayPart[] | string {
if (!shouldUseInteractiveInlayHints(preferences)) {
return printTypeInSingleLine(type);
}

const flags = NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const typeNode = checker.typeToTypeNode(type, /*enclosingDeclaration*/ undefined, flags);
Debug.assertIsDefined(typeNode, "should always get typeNode");
return getInlayHintDisplayParts(typeNode);
}

function typePredicateToInlayHintParts(typePredicate: TypePredicate): InlayHintDisplayPart[] | string {
if (!shouldUseInteractiveInlayHints(preferences)) {
return printTypePredicateInSingleLine(typePredicate);
}

const flags = NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const typeNode = checker.typePredicateToTypePredicateNode(typePredicate, /*enclosingDeclaration*/ undefined, flags);
Debug.assertIsDefined(typeNode, "should always get typenode");
return getInlayHintDisplayParts(typeNode);
}

function getInlayHintDisplayParts(node: Node) {
const parts: InlayHintDisplayPart[] = [];
visitForDisplayParts(typeNode);
visitForDisplayParts(node);
return parts;

function visitForDisplayParts(node: Node) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// === Inlay Hints ===
function test(x: unknown) {
^
{
"text": ": x is number",
"position": 25,
"kind": "Type",
"whitespaceBefore": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// === Inlay Hints ===
function test(x: unknown) {
^
{
"text": "",
"displayParts": [
{
"text": ": "
},
{
"text": "x"
},
{
"text": " is "
},
{
"text": "number"
}
],
"position": 25,
"kind": "Type",
"whitespaceBefore": true
}
11 changes: 11 additions & 0 deletions tests/cases/fourslash/inlayHintsInferredTypePredicate1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />

// @strict: true

//// function test(x: unknown) {
//// return typeof x === 'number';
//// }

verify.baselineInlayHints(undefined, {
includeInlayFunctionLikeReturnTypeHints: true,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/// <reference path="fourslash.ts" />

// @strict: true

//// function test(x: unknown) {
//// return typeof x === 'number';
//// }

verify.baselineInlayHints(undefined, {
interactiveInlayHints: true,
includeInlayFunctionLikeReturnTypeHints: true,
});

0 comments on commit d7ff565

Please sign in to comment.