Filter out self-fulfilling completions (#35709)

This commit is contained in:
Andrew Branch 2019-12-19 16:05:23 -06:00 committed by GitHub
parent ec84392f2e
commit 1fd5bd2b4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 3 deletions

View File

@ -2540,11 +2540,12 @@ namespace ts.Completions {
}
function getPropertiesForObjectExpression(contextualType: Type, baseConstrainedType: Type | undefined, obj: ObjectLiteralExpression | JsxAttributes, checker: TypeChecker): Symbol[] {
const type = baseConstrainedType && !(baseConstrainedType.flags & TypeFlags.AnyOrUnknown)
? checker.getUnionType([contextualType, baseConstrainedType])
const hasBaseType = baseConstrainedType && baseConstrainedType !== contextualType;
const type = hasBaseType && !(baseConstrainedType!.flags & TypeFlags.AnyOrUnknown)
? checker.getUnionType([contextualType, baseConstrainedType!])
: contextualType;
return type.isUnion()
const properties = type.isUnion()
? checker.getAllPossiblePropertiesOfTypes(type.types.filter(memberType =>
// If we're providing completions for an object literal, skip primitive, array-like, or callable types since those shouldn't be implemented by object literals.
!(memberType.flags & TypeFlags.Primitive ||
@ -2552,6 +2553,17 @@ namespace ts.Completions {
typeHasCallOrConstructSignatures(memberType, checker) ||
checker.isTypeInvalidDueToUnionDiscriminant(memberType, obj))))
: type.getApparentProperties();
return hasBaseType ? properties.filter(hasDeclarationOtherThanSelf) : properties;
// Filter out members whose only declaration is the object literal itself to avoid
// self-fulfilling completions like:
//
// function f<T>(x: T) {}
// f({ abc/**/: "" }) // `abc` is a member of `T` but only because it declares itself
function hasDeclarationOtherThanSelf(member: Symbol) {
return some(member.declarations, decl => decl.parent !== obj);
}
}
/**

View File

@ -0,0 +1,23 @@
/// <reference path="fourslash.ts" />
////interface Test {
//// keyPath?: string;
//// autoIncrement?: boolean;
////}
////
////function test<T extends Record<string, Test>>(opt: T) { }
////
////test({
//// a: {
//// keyPath: '',
//// a/**/
//// }
////})
verify.completions({
marker: "",
exact: [{
name: "autoIncrement",
sortText: completion.SortText.OptionalMember
}]
});

View File

@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />
////function f1<T>(x: T) {}
////f1({ abc/*1*/ });
////
////function f2<T extends { xyz: number }>(x: T) {}
////f2({ x/*2*/ });
verify.completions({
marker: "1",
exact: []
});
verify.completions({
marker: "2",
exact: ["xyz"]
});

View File

@ -0,0 +1,25 @@
/// <reference path="fourslash.ts" />
////function f<T extends { x: number }>(p: T & (T extends { hello: string } ? { goodbye: number } : {})) {}
////f({ x/*x*/: 0, hello/*hello*/: "", goodbye/*goodbye*/: 0, abc/*abc*/: "" })
verify.completions({
marker: "x",
exact: ["x"]
});
verify.completions({
marker: "hello",
exact: []
});
verify.completions({
marker: "goodbye",
exact: ["goodbye"]
});
verify.completions({
marker: "abc",
exact: []
});