Add more nodes for inlay hints (#56277)

Adds:
- CallSignature
- MethodSignature
- ObjectBindingPattern
- ArrayBindingPattern
- PrefixUnaryExpression
This commit is contained in:
Pranav Senthilnathan
2023-11-02 13:46:35 -07:00
committed by GitHub
parent cf73e5af5d
commit 9ebd9c4b90
5 changed files with 641 additions and 138 deletions

View File

@@ -1,11 +1,8 @@
import {
__String,
ArrayTypeNode,
ArrowFunction,
CallExpression,
CharacterCodes,
ConditionalTypeNode,
ConstructorTypeNode,
createPrinterWithRemoveComments,
createTextSpanFromNode,
Debug,
@@ -21,7 +18,6 @@ import {
FunctionDeclaration,
FunctionExpression,
FunctionLikeDeclaration,
FunctionTypeNode,
GetAccessorDeclaration,
getEffectiveReturnTypeNode,
getEffectiveTypeAnnotationNode,
@@ -32,59 +28,78 @@ import {
hasContextSensitiveParameters,
Identifier,
idText,
ImportTypeNode,
IndexedAccessTypeNode,
InferTypeNode,
InlayHint,
InlayHintDisplayPart,
InlayHintKind,
InlayHintsContext,
IntersectionTypeNode,
isArrayBindingPattern,
isArrayTypeNode,
isArrowFunction,
isAssertionExpression,
isBindingElement,
isBindingPattern,
isCallExpression,
isCallSignatureDeclaration,
isConditionalTypeNode,
isConstructorTypeNode,
isEnumMember,
isExpressionWithTypeArguments,
isFunctionDeclaration,
isFunctionExpression,
isFunctionLikeDeclaration,
isFunctionTypeNode,
isGetAccessorDeclaration,
isIdentifier,
isIdentifierText,
isImportTypeNode,
isIndexedAccessTypeNode,
isInferTypeNode,
isInfinityOrNaNString,
isIntersectionTypeNode,
isLiteralExpression,
isLiteralTypeNode,
isMappedTypeNode,
isMethodDeclaration,
isMethodSignature,
isNamedTupleMember,
isNewExpression,
isObjectBindingPattern,
isObjectLiteralExpression,
isOptionalTypeNode,
isParameter,
isParameterDeclaration,
isParenthesizedTypeNode,
isPrefixUnaryExpression,
isPropertyAccessExpression,
isPropertyDeclaration,
isPropertySignature,
isQualifiedName,
isRestTypeNode,
isSpreadElement,
isStringLiteral,
isTupleTypeNode,
isTypeLiteralNode,
isTypeNode,
isTypeOperatorNode,
isTypeParameterDeclaration,
isTypePredicateNode,
isTypeQueryNode,
isTypeReferenceNode,
isUnionTypeNode,
isVarConst,
isVariableDeclaration,
LiteralExpression,
LiteralTypeNode,
MappedTypeNode,
MethodDeclaration,
NamedTupleMember,
NewExpression,
Node,
NodeArray,
NodeBuilderFlags,
OptionalTypeNode,
ParameterDeclaration,
ParenthesizedTypeNode,
PrefixUnaryExpression,
PropertyDeclaration,
PropertySignature,
QualifiedName,
QuotePreference,
RestTypeNode,
Signature,
SignatureDeclarationBase,
skipParentheses,
some,
Symbol,
@@ -92,17 +107,9 @@ import {
SyntaxKind,
textSpanIntersectsWith,
tokenToString,
TupleTypeNode,
TupleTypeReference,
Type,
TypeLiteralNode,
TypeOperatorNode,
TypeParameterDeclaration,
TypePredicateNode,
TypeQueryNode,
TypeReferenceNode,
unescapeLeadingUnderscores,
UnionTypeNode,
UserPreferences,
usingSingleLineStringWriter,
VariableDeclaration,
@@ -485,9 +492,9 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
switch (node.kind) {
case SyntaxKind.Identifier:
const identifier = node as Identifier;
const identifierText = idText(identifier);
const name = identifier.symbol && identifier.symbol.declarations && identifier.symbol.declarations.length && getNameOfDeclaration(identifier.symbol.declarations[0]);
Debug.assertNode(node, isIdentifier);
const identifierText = idText(node);
const name = node.symbol && node.symbol.declarations && node.symbol.declarations.length && getNameOfDeclaration(node.symbol.declarations[0]);
if (name) {
parts.push(getNodeDisplayPart(identifierText, name));
}
@@ -496,255 +503,317 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
}
break;
case SyntaxKind.QualifiedName:
const qualifiedName = node as QualifiedName;
visitForDisplayParts(qualifiedName.left);
Debug.assertNode(node, isQualifiedName);
visitForDisplayParts(node.left);
parts.push({ text: "." });
visitForDisplayParts(qualifiedName.right);
visitForDisplayParts(node.right);
break;
case SyntaxKind.TypePredicate:
const predicate = node as TypePredicateNode;
if (predicate.assertsModifier) {
Debug.assertNode(node, isTypePredicateNode);
if (node.assertsModifier) {
parts.push({ text: "asserts " });
}
visitForDisplayParts(predicate.parameterName);
if (predicate.type) {
visitForDisplayParts(node.parameterName);
if (node.type) {
parts.push({ text: " is " });
visitForDisplayParts(predicate.type);
visitForDisplayParts(node.type);
}
break;
case SyntaxKind.TypeReference:
const typeReference = node as TypeReferenceNode;
visitForDisplayParts(typeReference.typeName);
if (typeReference.typeArguments) {
Debug.assertNode(node, isTypeReferenceNode);
visitForDisplayParts(node.typeName);
if (node.typeArguments) {
parts.push({ text: "<" });
visitDisplayPartList(typeReference.typeArguments, ", ");
visitDisplayPartList(node.typeArguments, ", ");
parts.push({ text: ">" });
}
break;
case SyntaxKind.TypeParameter:
const typeParameter = node as TypeParameterDeclaration;
if (typeParameter.modifiers) {
visitDisplayPartList(typeParameter.modifiers, " ");
Debug.assertNode(node, isTypeParameterDeclaration);
if (node.modifiers) {
visitDisplayPartList(node.modifiers, " ");
}
visitForDisplayParts(typeParameter.name);
if (typeParameter.constraint) {
visitForDisplayParts(node.name);
if (node.constraint) {
parts.push({ text: " extends " });
visitForDisplayParts(typeParameter.constraint);
visitForDisplayParts(node.constraint);
}
if (typeParameter.default) {
if (node.default) {
parts.push({ text: " = " });
visitForDisplayParts(typeParameter.default);
visitForDisplayParts(node.default);
}
break;
case SyntaxKind.Parameter:
const parameter = node as ParameterDeclaration;
if (parameter.modifiers) {
visitDisplayPartList(parameter.modifiers, " ");
Debug.assertNode(node, isParameter);
if (node.modifiers) {
visitDisplayPartList(node.modifiers, " ");
}
if (parameter.dotDotDotToken) {
if (node.dotDotDotToken) {
parts.push({ text: "..." });
}
visitForDisplayParts(parameter.name);
if (parameter.questionToken) {
visitForDisplayParts(node.name);
if (node.questionToken) {
parts.push({ text: "?" });
}
if (parameter.type) {
if (node.type) {
parts.push({ text: ": " });
visitForDisplayParts(parameter.type);
visitForDisplayParts(node.type);
}
break;
case SyntaxKind.ConstructorType:
const constructorType = node as ConstructorTypeNode;
Debug.assertNode(node, isConstructorTypeNode);
parts.push({ text: "new " });
if (constructorType.typeParameters) {
parts.push({ text: "<" });
visitDisplayPartList(constructorType.typeParameters, ", ");
parts.push({ text: ">" });
}
parts.push({ text: "(" });
visitDisplayPartList(constructorType.parameters, ", ");
parts.push({ text: ")" });
visitParametersAndTypeParameters(node);
parts.push({ text: " => " });
visitForDisplayParts(constructorType.type);
visitForDisplayParts(node.type);
break;
case SyntaxKind.TypeQuery:
const typeQuery = node as TypeQueryNode;
Debug.assertNode(node, isTypeQueryNode);
parts.push({ text: "typeof " });
visitForDisplayParts(typeQuery.exprName);
if (typeQuery.typeArguments) {
visitForDisplayParts(node.exprName);
if (node.typeArguments) {
parts.push({ text: "<" });
visitDisplayPartList(typeQuery.typeArguments, ", ");
visitDisplayPartList(node.typeArguments, ", ");
parts.push({ text: ">" });
}
break;
case SyntaxKind.TypeLiteral:
const typeLiteral = node as TypeLiteralNode;
Debug.assertNode(node, isTypeLiteralNode);
parts.push({ text: "{" });
if (typeLiteral.members.length) {
if (node.members.length) {
parts.push({ text: " " });
visitDisplayPartList(typeLiteral.members, "; ");
visitDisplayPartList(node.members, "; ");
parts.push({ text: " " });
}
parts.push({ text: "}" });
break;
case SyntaxKind.ArrayType:
visitForDisplayParts((node as ArrayTypeNode).elementType);
Debug.assertNode(node, isArrayTypeNode);
visitForDisplayParts(node.elementType);
parts.push({ text: "[]" });
break;
case SyntaxKind.TupleType:
Debug.assertNode(node, isTupleTypeNode);
parts.push({ text: "[" });
visitDisplayPartList((node as TupleTypeNode).elements, ", ");
visitDisplayPartList(node.elements, ", ");
parts.push({ text: "]" });
break;
case SyntaxKind.NamedTupleMember:
const member = node as NamedTupleMember;
if (member.dotDotDotToken) {
Debug.assertNode(node, isNamedTupleMember);
if (node.dotDotDotToken) {
parts.push({ text: "..." });
}
visitForDisplayParts(member.name);
if (member.questionToken) {
visitForDisplayParts(node.name);
if (node.questionToken) {
parts.push({ text: "?" });
}
parts.push({ text: ": " });
visitForDisplayParts(member.type);
visitForDisplayParts(node.type);
break;
case SyntaxKind.OptionalType:
visitForDisplayParts((node as OptionalTypeNode).type);
Debug.assertNode(node, isOptionalTypeNode);
visitForDisplayParts(node.type);
parts.push({ text: "?" });
break;
case SyntaxKind.RestType:
Debug.assertNode(node, isRestTypeNode);
parts.push({ text: "..." });
visitForDisplayParts((node as RestTypeNode).type);
visitForDisplayParts(node.type);
break;
case SyntaxKind.UnionType:
visitDisplayPartList((node as UnionTypeNode).types, " | ");
Debug.assertNode(node, isUnionTypeNode);
visitDisplayPartList(node.types, " | ");
break;
case SyntaxKind.IntersectionType:
visitDisplayPartList((node as IntersectionTypeNode).types, " & ");
Debug.assertNode(node, isIntersectionTypeNode);
visitDisplayPartList(node.types, " & ");
break;
case SyntaxKind.ConditionalType:
const conditionalType = node as ConditionalTypeNode;
visitForDisplayParts(conditionalType.checkType);
Debug.assertNode(node, isConditionalTypeNode);
visitForDisplayParts(node.checkType);
parts.push({ text: " extends " });
visitForDisplayParts(conditionalType.extendsType);
visitForDisplayParts(node.extendsType);
parts.push({ text: " ? " });
visitForDisplayParts(conditionalType.trueType);
visitForDisplayParts(node.trueType);
parts.push({ text: " : " });
visitForDisplayParts(conditionalType.falseType);
visitForDisplayParts(node.falseType);
break;
case SyntaxKind.InferType:
Debug.assertNode(node, isInferTypeNode);
parts.push({ text: "infer " });
visitForDisplayParts((node as InferTypeNode).typeParameter);
visitForDisplayParts(node.typeParameter);
break;
case SyntaxKind.ParenthesizedType:
Debug.assertNode(node, isParenthesizedTypeNode);
parts.push({ text: "(" });
visitForDisplayParts((node as ParenthesizedTypeNode).type);
visitForDisplayParts(node.type);
parts.push({ text: ")" });
break;
case SyntaxKind.TypeOperator:
const typeOperator = node as TypeOperatorNode;
parts.push({ text: `${tokenToString(typeOperator.operator)} ` });
visitForDisplayParts(typeOperator.type);
Debug.assertNode(node, isTypeOperatorNode);
parts.push({ text: `${tokenToString(node.operator)} ` });
visitForDisplayParts(node.type);
break;
case SyntaxKind.IndexedAccessType:
const indexedAccess = node as IndexedAccessTypeNode;
visitForDisplayParts(indexedAccess.objectType);
Debug.assertNode(node, isIndexedAccessTypeNode);
visitForDisplayParts(node.objectType);
parts.push({ text: "[" });
visitForDisplayParts(indexedAccess.indexType);
visitForDisplayParts(node.indexType);
parts.push({ text: "]" });
break;
case SyntaxKind.MappedType:
const mappedType = node as MappedTypeNode;
Debug.assertNode(node, isMappedTypeNode);
parts.push({ text: "{ " });
if (mappedType.readonlyToken) {
if (mappedType.readonlyToken.kind === SyntaxKind.PlusToken) {
if (node.readonlyToken) {
if (node.readonlyToken.kind === SyntaxKind.PlusToken) {
parts.push({ text: "+" });
}
else if (mappedType.readonlyToken.kind === SyntaxKind.MinusToken) {
else if (node.readonlyToken.kind === SyntaxKind.MinusToken) {
parts.push({ text: "-" });
}
parts.push({ text: "readonly " });
}
parts.push({ text: "[" });
visitForDisplayParts(mappedType.typeParameter);
if (mappedType.nameType) {
visitForDisplayParts(node.typeParameter);
if (node.nameType) {
parts.push({ text: " as " });
visitForDisplayParts(mappedType.nameType);
visitForDisplayParts(node.nameType);
}
parts.push({ text: "]" });
if (mappedType.questionToken) {
if (mappedType.questionToken.kind === SyntaxKind.PlusToken) {
if (node.questionToken) {
if (node.questionToken.kind === SyntaxKind.PlusToken) {
parts.push({ text: "+" });
}
else if (mappedType.questionToken.kind === SyntaxKind.MinusToken) {
else if (node.questionToken.kind === SyntaxKind.MinusToken) {
parts.push({ text: "-" });
}
parts.push({ text: "?" });
}
parts.push({ text: ": " });
if (mappedType.type) {
visitForDisplayParts(mappedType.type);
if (node.type) {
visitForDisplayParts(node.type);
}
parts.push({ text: "; }" });
break;
case SyntaxKind.LiteralType:
visitForDisplayParts((node as LiteralTypeNode).literal);
Debug.assertNode(node, isLiteralTypeNode);
visitForDisplayParts(node.literal);
break;
case SyntaxKind.FunctionType:
const functionType = node as FunctionTypeNode;
if (functionType.typeParameters) {
parts.push({ text: "<" });
visitDisplayPartList(functionType.typeParameters, ", ");
parts.push({ text: ">" });
}
parts.push({ text: "(" });
visitDisplayPartList(functionType.parameters, ", ");
parts.push({ text: ")" });
Debug.assertNode(node, isFunctionTypeNode);
visitParametersAndTypeParameters(node);
parts.push({ text: " => " });
visitForDisplayParts(functionType.type);
visitForDisplayParts(node.type);
break;
case SyntaxKind.ImportType:
const importType = node as ImportTypeNode;
if (importType.isTypeOf) {
Debug.assertNode(node, isImportTypeNode);
if (node.isTypeOf) {
parts.push({ text: "typeof " });
}
parts.push({ text: "import(" });
visitForDisplayParts(importType.argument);
if (importType.assertions) {
visitForDisplayParts(node.argument);
if (node.assertions) {
parts.push({ text: ", { assert: " });
visitDisplayPartList(importType.assertions.assertClause.elements, ", ");
visitDisplayPartList(node.assertions.assertClause.elements, ", ");
parts.push({ text: " }" });
}
parts.push({ text: ")" });
if (importType.qualifier) {
if (node.qualifier) {
parts.push({ text: "." });
visitForDisplayParts(importType.qualifier);
visitForDisplayParts(node.qualifier);
}
if (importType.typeArguments) {
if (node.typeArguments) {
parts.push({ text: "<" });
visitDisplayPartList(importType.typeArguments, ", ");
visitDisplayPartList(node.typeArguments, ", ");
parts.push({ text: ">" });
}
break;
case SyntaxKind.PropertySignature:
const propertySignature = node as PropertySignature;
if (propertySignature.modifiers) {
visitDisplayPartList(propertySignature.modifiers, " ");
Debug.assertNode(node, isPropertySignature);
if (node.modifiers?.length) {
visitDisplayPartList(node.modifiers, " ");
parts.push({ text: " " });
}
visitForDisplayParts(propertySignature.name);
if (propertySignature.questionToken) {
visitForDisplayParts(node.name);
if (node.questionToken) {
parts.push({ text: "?" });
}
if (propertySignature.type) {
if (node.type) {
parts.push({ text: ": " });
visitForDisplayParts(propertySignature.type);
visitForDisplayParts(node.type);
}
break;
case SyntaxKind.MethodSignature:
Debug.assertNode(node, isMethodSignature);
if (node.modifiers?.length) {
visitDisplayPartList(node.modifiers, " ");
parts.push({ text: " " });
}
visitForDisplayParts(node.name);
if (node.questionToken) {
parts.push({ text: "?" });
}
visitParametersAndTypeParameters(node);
if (node.type) {
parts.push({ text: ": " });
visitForDisplayParts(node.type);
}
break;
case SyntaxKind.CallSignature:
Debug.assertNode(node, isCallSignatureDeclaration);
visitParametersAndTypeParameters(node);
if (node.type) {
parts.push({ text: ": " });
visitForDisplayParts(node.type);
}
break;
case SyntaxKind.ArrayBindingPattern:
Debug.assertNode(node, isArrayBindingPattern);
parts.push({ text: "[" });
visitDisplayPartList(node.elements, ", ");
parts.push({ text: "]" });
break;
case SyntaxKind.ObjectBindingPattern:
Debug.assertNode(node, isObjectBindingPattern);
parts.push({ text: "{" });
if (node.elements.length) {
parts.push({ text: " " });
visitDisplayPartList(node.elements, ", ");
parts.push({ text: " " });
}
parts.push({ text: "}" });
break;
case SyntaxKind.BindingElement:
Debug.assertNode(node, isBindingElement);
visitForDisplayParts(node.name);
break;
case SyntaxKind.PrefixUnaryExpression:
Debug.assertNode(node, isPrefixUnaryExpression);
parts.push({ text: tokenToString(node.operator) });
visitForDisplayParts(node.operand);
break;
default:
Debug.failBadSyntaxKind(node);
}
}
/**
* Visits the type parameters and parameters, returning something like:
* <T1, T2>(p1: t1, p2: t2)
* which can be used for signature declaration nodes.
* @param signatureDeclaration Node to visit.
*/
function visitParametersAndTypeParameters(signatureDeclaration: SignatureDeclarationBase) {
if (signatureDeclaration.typeParameters) {
parts.push({ text: "<" });
visitDisplayPartList(signatureDeclaration.typeParameters, ", ");
parts.push({ text: ">" });
}
parts.push({ text: "(" });
visitDisplayPartList(signatureDeclaration.parameters, ", ");
parts.push({ text: ")" });
}
function visitDisplayPartList<T extends Node>(nodes: NodeArray<T>, separator: string) {
nodes.forEach((node, index) => {
if (index > 0) {

View File

@@ -203,6 +203,65 @@
{
"text": " "
},
{
"text": "<"
},
{
"text": "X",
"span": {
"start": 599,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": ", "
},
{
"text": "Y",
"span": {
"start": 602,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": ">"
},
{
"text": "("
},
{
"text": "x"
},
{
"text": ": "
},
{
"text": "X",
"span": {
"start": 599,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": ")"
},
{
"text": ": "
},
{
"text": "Y",
"span": {
"start": 602,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": "; "
},
{
"text": "a"
},
@@ -224,6 +283,180 @@
{
"text": "string"
},
{
"text": "; "
},
{
"text": "readonly"
},
{
"text": " "
},
{
"text": "c"
},
{
"text": ": "
},
{
"text": "boolean"
},
{
"text": "; "
},
{
"text": "d"
},
{
"text": "?"
},
{
"text": ": "
},
{
"text": "number"
},
{
"text": "; "
},
{
"text": "e"
},
{
"text": "("
},
{
"text": ")"
},
{
"text": ": "
},
{
"text": "string"
},
{
"text": "; "
},
{
"text": "f"
},
{
"text": "?"
},
{
"text": "("
},
{
"text": ")"
},
{
"text": ": "
},
{
"text": "boolean"
},
{
"text": "; "
},
{
"text": "g"
},
{
"text": "<"
},
{
"text": "T",
"span": {
"start": 562,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": ">"
},
{
"text": "("
},
{
"text": ")"
},
{
"text": ": "
},
{
"text": "T",
"span": {
"start": 562,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": "; "
},
{
"text": "h"
},
{
"text": "?"
},
{
"text": "<"
},
{
"text": "X",
"span": {
"start": 578,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": ", "
},
{
"text": "Y",
"span": {
"start": 581,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": ">"
},
{
"text": "("
},
{
"text": "x"
},
{
"text": ": "
},
{
"text": "X",
"span": {
"start": 578,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": ")"
},
{
"text": ": "
},
{
"text": "Y",
"span": {
"start": 581,
"length": 1
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
},
{
"text": " "
},
@@ -231,7 +464,33 @@
"text": "}"
}
],
"position": 510,
"position": 646,
"kind": "Type",
"whitespaceBefore": true
}
const foo6: F3 = (a) => { }
^
{
"text": "",
"displayParts": [
{
"text": ": "
},
{
"text": "("
},
{
"text": ")"
},
{
"text": " => "
},
{
"text": "42"
}
],
"position": 716,
"kind": "Type",
"whitespaceBefore": true
}
@@ -247,13 +506,13 @@ foo4(p => {})
{
"text": "Thing",
"span": {
"start": 529,
"start": 735,
"length": 5
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveFunctionParameterTypes1.ts"
}
],
"position": 595,
"position": 801,
"kind": "Type",
"whitespaceBefore": true
}

View File

@@ -23,4 +23,162 @@
"position": 331,
"kind": "Type",
"whitespaceBefore": true
}
const o = () => -1 as const;
^
{
"text": "",
"displayParts": [
{
"text": ": "
},
{
"text": "("
},
{
"text": ")"
},
{
"text": " => "
},
{
"text": "-"
},
{
"text": "1"
}
],
"position": 363,
"kind": "Type",
"whitespaceBefore": true
}
const p = ([a]: Foo[]) => a;
^
{
"text": "",
"displayParts": [
{
"text": ": "
},
{
"text": "("
},
{
"text": "["
},
{
"text": "a"
},
{
"text": "]"
},
{
"text": ": "
},
{
"text": "Foo",
"span": {
"start": 57,
"length": 3
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveVariableTypes1.ts"
},
{
"text": "[]"
},
{
"text": ")"
},
{
"text": " => "
},
{
"text": "Foo",
"span": {
"start": 57,
"length": 3
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveVariableTypes1.ts"
}
],
"position": 393,
"kind": "Type",
"whitespaceBefore": true
}
const q = ({ a }: { a: Foo }) => a;
^
{
"text": "",
"displayParts": [
{
"text": ": "
},
{
"text": "("
},
{
"text": "{"
},
{
"text": " "
},
{
"text": "a"
},
{
"text": " "
},
{
"text": "}"
},
{
"text": ": "
},
{
"text": "{"
},
{
"text": " "
},
{
"text": "a"
},
{
"text": ": "
},
{
"text": "Foo",
"span": {
"start": 57,
"length": 3
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveVariableTypes1.ts"
},
{
"text": " "
},
{
"text": "}"
},
{
"text": ")"
},
{
"text": " => "
},
{
"text": "Foo",
"span": {
"start": 57,
"length": 3
},
"file": "/tests/cases/fourslash/inlayHintsInteractiveVariableTypes1.ts"
}
],
"position": 423,
"kind": "Type",
"whitespaceBefore": true
}

View File

@@ -21,9 +21,22 @@
//// type F2 = (a: {
//// a: number
//// b: string
//// readonly c: boolean
//// d?: number
//// e(): string
//// f?(): boolean
//// g<T>(): T
//// h?<X, Y>(x: X): Y
//// <X, Y>(x: X): Y
//// }) => void
//// const foo5: F2 = (a) => { }
// A callable object with no other members gets turned into a function type:
//// type F3 = (a: {
//// (): 42
//// }) => void
//// const foo6: F3 = (a) => { }
////interface Thing {}
////function foo4(callback: (thing: Thing) => void) {}
////foo4(p => {})

View File

@@ -22,6 +22,10 @@
//// const m = () => 123;
//// const n;
//// const o = () => -1 as const;
//// const p = ([a]: Foo[]) => a;
//// const q = ({ a }: { a: Foo }) => a;
verify.baselineInlayHints(undefined, {
includeInlayVariableTypeHints: true,