mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
feat(28491): add QF to declare missing properties (#44576)
This commit is contained in:
@@ -393,6 +393,7 @@ namespace ts {
|
||||
getDiagnostics,
|
||||
getGlobalDiagnostics,
|
||||
getRecursionIdentity,
|
||||
getUnmatchedProperties,
|
||||
getTypeOfSymbolAtLocation: (symbol, locationIn) => {
|
||||
const location = getParseTreeNode(locationIn);
|
||||
return location ? getTypeOfSymbolAtLocation(symbol, location) : errorType;
|
||||
|
||||
@@ -7048,6 +7048,14 @@
|
||||
"category": "Message",
|
||||
"code": 95164
|
||||
},
|
||||
"Add missing properties": {
|
||||
"category": "Message",
|
||||
"code": 95165
|
||||
},
|
||||
"Add all missing properties": {
|
||||
"category": "Message",
|
||||
"code": 95166
|
||||
},
|
||||
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -4275,6 +4275,7 @@ namespace ts {
|
||||
/* @internal */ getInstantiationCount(): number;
|
||||
/* @internal */ getRelationCacheSizes(): { assignable: number, identity: number, subtype: number, strictSubtype: number };
|
||||
/* @internal */ getRecursionIdentity(type: Type): object | undefined;
|
||||
/* @internal */ getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator<Symbol>;
|
||||
|
||||
/* @internal */ isArrayType(type: Type): boolean;
|
||||
/* @internal */ isTupleType(type: Type): boolean;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
const fixMissingMember = "fixMissingMember";
|
||||
const fixMissingProperties = "fixMissingProperties";
|
||||
const fixMissingFunctionDeclaration = "fixMissingFunctionDeclaration";
|
||||
|
||||
const errorCodes = [
|
||||
Diagnostics.Property_0_does_not_exist_on_type_1.code,
|
||||
Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2.code,
|
||||
@@ -19,6 +21,10 @@ namespace ts.codefix {
|
||||
if (!info) {
|
||||
return undefined;
|
||||
}
|
||||
if (info.kind === InfoKind.ObjectLiteral) {
|
||||
const changes = textChanges.ChangeTracker.with(context, t => addObjectLiteralProperties(t, context, info));
|
||||
return [createCodeFixAction(fixMissingProperties, changes, Diagnostics.Add_missing_properties, fixMissingProperties, Diagnostics.Add_all_missing_properties)];
|
||||
}
|
||||
if (info.kind === InfoKind.Function) {
|
||||
const changes = textChanges.ChangeTracker.with(context, t => addFunctionDeclaration(t, context, info));
|
||||
return [createCodeFixAction(fixMissingFunctionDeclaration, changes, [Diagnostics.Add_missing_function_declaration_0, info.token.text], fixMissingFunctionDeclaration, Diagnostics.Add_all_missing_function_declarations)];
|
||||
@@ -29,7 +35,7 @@ namespace ts.codefix {
|
||||
}
|
||||
return concatenate(getActionsForMissingMethodDeclaration(context, info), getActionsForMissingMemberDeclaration(context, info));
|
||||
},
|
||||
fixIds: [fixMissingMember, fixMissingFunctionDeclaration],
|
||||
fixIds: [fixMissingMember, fixMissingFunctionDeclaration, fixMissingProperties],
|
||||
getAllCodeActions: context => {
|
||||
const { program, fixId } = context;
|
||||
const checker = program.getTypeChecker();
|
||||
@@ -48,11 +54,15 @@ namespace ts.codefix {
|
||||
addFunctionDeclaration(changes, context, info);
|
||||
}
|
||||
}
|
||||
else if (fixId === fixMissingProperties) {
|
||||
if (info.kind === InfoKind.ObjectLiteral) {
|
||||
addObjectLiteralProperties(changes, context, info);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (info.kind === InfoKind.Enum) {
|
||||
addEnumMemberDeclaration(changes, checker, info);
|
||||
}
|
||||
|
||||
if (info.kind === InfoKind.ClassOrInterface) {
|
||||
const { parentDeclaration, token } = info;
|
||||
const infos = getOrUpdate(typeDeclToMembers, parentDeclaration, () => []);
|
||||
@@ -92,8 +102,8 @@ namespace ts.codefix {
|
||||
},
|
||||
});
|
||||
|
||||
const enum InfoKind { Enum, ClassOrInterface, Function }
|
||||
type Info = EnumInfo | ClassOrInterfaceInfo | FunctionInfo;
|
||||
const enum InfoKind { Enum, ClassOrInterface, Function, ObjectLiteral }
|
||||
type Info = EnumInfo | ClassOrInterfaceInfo | FunctionInfo | ObjectLiteralInfo;
|
||||
|
||||
interface EnumInfo {
|
||||
readonly kind: InfoKind.Enum;
|
||||
@@ -120,6 +130,13 @@ namespace ts.codefix {
|
||||
readonly parentDeclaration: SourceFile | ModuleDeclaration;
|
||||
}
|
||||
|
||||
interface ObjectLiteralInfo {
|
||||
readonly kind: InfoKind.ObjectLiteral;
|
||||
readonly token: Identifier;
|
||||
readonly properties: Symbol[];
|
||||
readonly parentDeclaration: ObjectLiteralExpression;
|
||||
}
|
||||
|
||||
function getInfo(sourceFile: SourceFile, tokenPos: number, checker: TypeChecker, program: Program): Info | undefined {
|
||||
// The identifier of the missing property. eg:
|
||||
// this.missing = 1;
|
||||
@@ -130,6 +147,13 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
const { parent } = token;
|
||||
if (isIdentifier(token) && hasInitializer(parent) && parent.initializer && isObjectLiteralExpression(parent.initializer)) {
|
||||
const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent.initializer), checker.getTypeAtLocation(token), /* requireOptionalProperties */ false, /* matchDiscriminantProperties */ false));
|
||||
if (length(properties)) {
|
||||
return { kind: InfoKind.ObjectLiteral, token, properties, parentDeclaration: parent.initializer };
|
||||
}
|
||||
}
|
||||
|
||||
if (isIdentifier(token) && isCallExpression(parent)) {
|
||||
return { kind: InfoKind.Function, token, call: parent, sourceFile, modifierFlags: ModifierFlags.None, parentDeclaration: sourceFile };
|
||||
}
|
||||
@@ -248,7 +272,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
function initializePropertyToUndefined(obj: Expression, propertyName: string) {
|
||||
return factory.createExpressionStatement(factory.createAssignment(factory.createPropertyAccessExpression(obj, propertyName), factory.createIdentifier("undefined")));
|
||||
return factory.createExpressionStatement(factory.createAssignment(factory.createPropertyAccessExpression(obj, propertyName), createUndefined()));
|
||||
}
|
||||
|
||||
function createActionsForAddMissingMemberInTypeScriptFile(context: CodeFixContext, { parentDeclaration, declSourceFile, modifierFlags, token }: ClassOrInterfaceInfo): CodeFixAction[] | undefined {
|
||||
@@ -405,4 +429,97 @@ namespace ts.codefix {
|
||||
const functionDeclaration = createSignatureDeclarationFromCallExpression(SyntaxKind.FunctionDeclaration, context, importAdder, info.call, idText(info.token), info.modifierFlags, info.parentDeclaration) as FunctionDeclaration;
|
||||
changes.insertNodeAtEndOfScope(info.sourceFile, info.parentDeclaration, functionDeclaration);
|
||||
}
|
||||
|
||||
function addObjectLiteralProperties(changes: textChanges.ChangeTracker, context: CodeFixContextBase, info: ObjectLiteralInfo) {
|
||||
const importAdder = createImportAdder(context.sourceFile, context.program, context.preferences, context.host);
|
||||
const quotePreference = getQuotePreference(context.sourceFile, context.preferences);
|
||||
const checker = context.program.getTypeChecker();
|
||||
const props = map(info.properties, prop => {
|
||||
const initializer = prop.valueDeclaration ? tryGetInitializerValueFromType(context, checker, importAdder, quotePreference, checker.getTypeAtLocation(prop.valueDeclaration)) : createUndefined();
|
||||
return factory.createPropertyAssignment(prop.name, initializer);
|
||||
});
|
||||
changes.replaceNode(context.sourceFile, info.parentDeclaration, factory.createObjectLiteralExpression([...info.parentDeclaration.properties, ...props], /*multiLine*/ true));
|
||||
}
|
||||
|
||||
function tryGetInitializerValueFromType(context: CodeFixContextBase, checker: TypeChecker, importAdder: ImportAdder, quotePreference: QuotePreference, type: Type): Expression {
|
||||
if (type.flags & TypeFlags.AnyOrUnknown) {
|
||||
return createUndefined();
|
||||
}
|
||||
if (type.flags & (TypeFlags.String | TypeFlags.TemplateLiteral)) {
|
||||
return factory.createStringLiteral("", /* isSingleQuote */ quotePreference === QuotePreference.Single);
|
||||
}
|
||||
if (type.flags & TypeFlags.Number) {
|
||||
return factory.createNumericLiteral(0);
|
||||
}
|
||||
if (type.flags & TypeFlags.BigInt) {
|
||||
return factory.createBigIntLiteral("0n");
|
||||
}
|
||||
if (type.flags & TypeFlags.Boolean) {
|
||||
return factory.createFalse();
|
||||
}
|
||||
if (type.flags & TypeFlags.EnumLike) {
|
||||
const enumMember = type.symbol.exports ? firstOrUndefined(arrayFrom(type.symbol.exports.values())) : type.symbol;
|
||||
const name = checker.symbolToExpression(type.symbol.parent ? type.symbol.parent : type.symbol, SymbolFlags.Value, /*enclosingDeclaration*/ undefined, /*flags*/ undefined);
|
||||
return enumMember === undefined || name === undefined ? factory.createNumericLiteral(0) : factory.createPropertyAccessExpression(name, checker.symbolToString(enumMember));
|
||||
}
|
||||
if (type.flags & TypeFlags.NumberLiteral) {
|
||||
return factory.createNumericLiteral((type as NumberLiteralType).value);
|
||||
}
|
||||
if (type.flags & TypeFlags.BigIntLiteral) {
|
||||
return factory.createBigIntLiteral((type as BigIntLiteralType).value);
|
||||
}
|
||||
if (type.flags & TypeFlags.StringLiteral) {
|
||||
return factory.createStringLiteral((type as StringLiteralType).value, /* isSingleQuote */ quotePreference === QuotePreference.Single);
|
||||
}
|
||||
if (type.flags & TypeFlags.BooleanLiteral) {
|
||||
return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) ? factory.createFalse() : factory.createTrue();
|
||||
}
|
||||
if (type.flags & TypeFlags.Null) {
|
||||
return factory.createNull();
|
||||
}
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
const expression = firstDefined((type as UnionType).types, t => tryGetInitializerValueFromType(context, checker, importAdder, quotePreference, t));
|
||||
return expression ?? createUndefined();
|
||||
}
|
||||
if (checker.isArrayLikeType(type)) {
|
||||
return factory.createArrayLiteralExpression();
|
||||
}
|
||||
if (isObjectLiteralType(type)) {
|
||||
const props = map(checker.getPropertiesOfType(type), prop => {
|
||||
const initializer = prop.valueDeclaration ? tryGetInitializerValueFromType(context, checker, importAdder, quotePreference, checker.getTypeAtLocation(prop.valueDeclaration)) : createUndefined();
|
||||
return factory.createPropertyAssignment(prop.name, initializer);
|
||||
});
|
||||
return factory.createObjectLiteralExpression(props, /*multiLine*/ true);
|
||||
}
|
||||
if (getObjectFlags(type) & ObjectFlags.Anonymous) {
|
||||
const decl = find(type.symbol.declarations || emptyArray, or(isFunctionTypeNode, isMethodSignature, isMethodDeclaration));
|
||||
if (decl === undefined) return createUndefined();
|
||||
|
||||
const signature = checker.getSignaturesOfType(type, SignatureKind.Call);
|
||||
if (signature === undefined) return createUndefined();
|
||||
|
||||
const func = createSignatureDeclarationFromSignature(SyntaxKind.FunctionExpression, context, quotePreference, signature[0],
|
||||
createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), /*name*/ undefined, /*modifiers*/ undefined, /*optional*/ undefined, /*enclosingDeclaration*/ undefined, importAdder) as FunctionExpression | undefined;
|
||||
return func ?? createUndefined();
|
||||
}
|
||||
if (getObjectFlags(type) & ObjectFlags.Class) {
|
||||
const classDeclaration = getClassLikeDeclarationOfSymbol(type.symbol);
|
||||
if (classDeclaration === undefined || hasAbstractModifier(classDeclaration)) return createUndefined();
|
||||
|
||||
const constructorDeclaration = getFirstConstructorWithBody(classDeclaration);
|
||||
if (constructorDeclaration && length(constructorDeclaration.parameters)) return createUndefined();
|
||||
|
||||
return factory.createNewExpression(factory.createIdentifier(type.symbol.name), /*typeArguments*/ undefined, /*argumentsArray*/ undefined);
|
||||
}
|
||||
return createUndefined();
|
||||
}
|
||||
|
||||
function createUndefined() {
|
||||
return factory.createIdentifier("undefined");
|
||||
}
|
||||
|
||||
function isObjectLiteralType(type: Type) {
|
||||
return (type.flags & TypeFlags.Object) &&
|
||||
((getObjectFlags(type) & ObjectFlags.ObjectLiteral) || (type.symbol && tryCast(singleOrUndefined(type.symbol.declarations), isTypeLiteralNode)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,27 +145,28 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
function outputMethod(quotePreference: QuotePreference, signature: Signature, modifiers: NodeArray<Modifier> | undefined, name: PropertyName, body?: Block): void {
|
||||
const method = signatureToMethodDeclaration(context, quotePreference, signature, enclosingDeclaration, modifiers, name, optional, body, importAdder);
|
||||
const method = createSignatureDeclarationFromSignature(SyntaxKind.MethodDeclaration, context, quotePreference, signature, body, name, modifiers, optional, enclosingDeclaration, importAdder);
|
||||
if (method) addClassElement(method);
|
||||
}
|
||||
}
|
||||
|
||||
function signatureToMethodDeclaration(
|
||||
export function createSignatureDeclarationFromSignature(
|
||||
kind: SyntaxKind.MethodDeclaration | SyntaxKind.FunctionExpression | SyntaxKind.ArrowFunction,
|
||||
context: TypeConstructionContext,
|
||||
quotePreference: QuotePreference,
|
||||
signature: Signature,
|
||||
enclosingDeclaration: ClassLikeDeclaration,
|
||||
modifiers: NodeArray<Modifier> | undefined,
|
||||
name: PropertyName,
|
||||
optional: boolean,
|
||||
body: Block | undefined,
|
||||
importAdder: ImportAdder | undefined,
|
||||
): MethodDeclaration | undefined {
|
||||
name: PropertyName | undefined,
|
||||
modifiers: NodeArray<Modifier> | undefined,
|
||||
optional: boolean | undefined,
|
||||
enclosingDeclaration: Node | undefined,
|
||||
importAdder: ImportAdder | undefined
|
||||
) {
|
||||
const program = context.program;
|
||||
const checker = program.getTypeChecker();
|
||||
const scriptTarget = getEmitScriptTarget(program.getCompilerOptions());
|
||||
const flags = NodeBuilderFlags.NoTruncation | NodeBuilderFlags.NoUndefinedOptionalParameterType | NodeBuilderFlags.SuppressAnyReturnType | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : 0);
|
||||
const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, flags, getNoopSymbolTrackerWithResolver(context)) as MethodDeclaration;
|
||||
const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, kind, enclosingDeclaration, flags, getNoopSymbolTrackerWithResolver(context)) as ArrowFunction | FunctionExpression | MethodDeclaration;
|
||||
if (!signatureDeclaration) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -233,18 +234,18 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
return factory.updateMethodDeclaration(
|
||||
signatureDeclaration,
|
||||
/*decorators*/ undefined,
|
||||
modifiers,
|
||||
signatureDeclaration.asteriskToken,
|
||||
name,
|
||||
optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined,
|
||||
typeParameters,
|
||||
parameters,
|
||||
type,
|
||||
body
|
||||
);
|
||||
const questionToken = optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined;
|
||||
const asteriskToken = signatureDeclaration.asteriskToken;
|
||||
if (isFunctionExpression(signatureDeclaration)) {
|
||||
return factory.updateFunctionExpression(signatureDeclaration, modifiers, signatureDeclaration.asteriskToken, tryCast(name, isIdentifier), typeParameters, parameters, type, body ?? signatureDeclaration.body);
|
||||
}
|
||||
if (isArrowFunction(signatureDeclaration)) {
|
||||
return factory.updateArrowFunction(signatureDeclaration, modifiers, typeParameters, parameters, type, signatureDeclaration.equalsGreaterThanToken, body ?? signatureDeclaration.body);
|
||||
}
|
||||
if (isMethodDeclaration(signatureDeclaration)) {
|
||||
return factory.updateMethodDeclaration(signatureDeclaration, /* decorators */ undefined, modifiers, asteriskToken, name ?? factory.createIdentifier(""), questionToken, typeParameters, parameters, type, body);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function createSignatureDeclarationFromCallExpression(
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface Foo {
|
||||
//// a: number;
|
||||
//// b: string;
|
||||
//// c: 1;
|
||||
//// d: "d";
|
||||
//// e: "e1" | "e2";
|
||||
//// f(x: number, y: number): void;
|
||||
//// g: (x: number, y: number) => void;
|
||||
//// h: number[];
|
||||
//// i: bigint;
|
||||
//// j: undefined | "special-string";
|
||||
//// k: `--${string}`;
|
||||
////}
|
||||
////[|const foo: Foo = {}|];
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`const foo: Foo = {
|
||||
a: 0,
|
||||
b: "",
|
||||
c: 1,
|
||||
d: "d",
|
||||
e: "e1",
|
||||
f: function(x: number, y: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
},
|
||||
g: function(x: number, y: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
},
|
||||
h: [],
|
||||
i: 0n,
|
||||
j: "special-string",
|
||||
k: ""
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////type T = { x: number; };
|
||||
////interface I {
|
||||
//// a: T
|
||||
////}
|
||||
////[|const foo: I = {};|]
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`const foo: I = {
|
||||
a: {
|
||||
x: 0
|
||||
}
|
||||
};`
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface Foo {
|
||||
//// a: `--${string}`;
|
||||
//// b: string;
|
||||
//// c: "a" | "b"
|
||||
////}
|
||||
////[|const foo: Foo = {}|];
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
preferences: {
|
||||
quotePreference: "single"
|
||||
},
|
||||
newRangeContent:
|
||||
`const foo: Foo = {
|
||||
a: '',
|
||||
b: '',
|
||||
c: 'a'
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface Foo {
|
||||
//// a: number;
|
||||
//// b: string;
|
||||
//// c: any;
|
||||
////}
|
||||
////[|class C {
|
||||
//// public c: Foo = {};
|
||||
////}|]
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`class C {
|
||||
public c: Foo = {
|
||||
a: 0,
|
||||
b: "",
|
||||
c: undefined
|
||||
};
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface Foo {
|
||||
//// a: number;
|
||||
//// b: string;
|
||||
////}
|
||||
////[|function fn(foo: Foo = {}) {
|
||||
////}|]
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`function fn(foo: Foo = {
|
||||
a: 0,
|
||||
b: ""
|
||||
}) {
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface Foo {
|
||||
//// a: number;
|
||||
//// b: string;
|
||||
////}
|
||||
////[|const foo: Foo = { a: 10 }|];
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`const foo: Foo = {
|
||||
a: 10,
|
||||
b: ""
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////type T = {
|
||||
//// a: null;
|
||||
////}
|
||||
////
|
||||
////[|const foo: T = {}|];
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`const foo: T = {
|
||||
a: null
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface I {
|
||||
//// x: number;
|
||||
//// y: number;
|
||||
////}
|
||||
////class C {
|
||||
//// public p: number;
|
||||
//// m(x: number, y: I) {}
|
||||
////}
|
||||
////[|const foo: C = {}|];
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`const foo: C = {
|
||||
p: 0,
|
||||
m: function(x: number, y: I): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////enum E1 {
|
||||
//// A, B
|
||||
////}
|
||||
////enum E2 {
|
||||
//// A
|
||||
////}
|
||||
////enum E3 {
|
||||
////}
|
||||
////interface I {
|
||||
//// x: E1;
|
||||
//// y: E2;
|
||||
//// z: E3;
|
||||
////}
|
||||
////[|const foo: I = {};|]
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`const foo: I = {
|
||||
x: E1.A,
|
||||
y: E2.A,
|
||||
z: 0
|
||||
};`
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////class A {
|
||||
//// constructor() {}
|
||||
////}
|
||||
////
|
||||
////abstract class B {}
|
||||
////
|
||||
////class C {
|
||||
//// constructor(a: string, b: number, c: A) {}
|
||||
////}
|
||||
////
|
||||
////interface I {
|
||||
//// a: A;
|
||||
//// b: B;
|
||||
//// c: C;
|
||||
////}
|
||||
////[|const foo: I = {};|]
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`const foo: I = {
|
||||
a: new A,
|
||||
b: undefined,
|
||||
c: undefined
|
||||
};`
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface I {
|
||||
//// a: {
|
||||
//// x: number;
|
||||
//// y: { z: string; };
|
||||
//// }
|
||||
////}
|
||||
////[|const foo: I = {};|]
|
||||
|
||||
verify.codeFix({
|
||||
index: 0,
|
||||
description: ts.Diagnostics.Add_missing_properties.message,
|
||||
newRangeContent:
|
||||
`const foo: I = {
|
||||
a: {
|
||||
x: 0,
|
||||
y: {
|
||||
z: ""
|
||||
}
|
||||
}
|
||||
};`
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface I1 {
|
||||
//// a: number;
|
||||
//// b: string;
|
||||
//// c: 1;
|
||||
//// d: "d";
|
||||
//// e: "e1" | "e2";
|
||||
//// f(x: number, y: number): void;
|
||||
//// g: (x: number, y: number) => void;
|
||||
////}
|
||||
////interface I2 {
|
||||
//// a: unknown;
|
||||
//// b: any;
|
||||
////}
|
||||
////const a: I1 = {};
|
||||
////const b: I2 = {};
|
||||
////class C {
|
||||
//// public c: I1 = {};
|
||||
////}
|
||||
////function fn(foo: I2 = {}) {
|
||||
////}
|
||||
|
||||
verify.codeFixAll({
|
||||
fixId: "fixMissingProperties",
|
||||
fixAllDescription: ts.Diagnostics.Add_all_missing_properties.message,
|
||||
newFileContent:
|
||||
`interface I1 {
|
||||
a: number;
|
||||
b: string;
|
||||
c: 1;
|
||||
d: "d";
|
||||
e: "e1" | "e2";
|
||||
f(x: number, y: number): void;
|
||||
g: (x: number, y: number) => void;
|
||||
}
|
||||
interface I2 {
|
||||
a: unknown;
|
||||
b: any;
|
||||
}
|
||||
const a: I1 = {
|
||||
a: 0,
|
||||
b: "",
|
||||
c: 1,
|
||||
d: "d",
|
||||
e: "e1",
|
||||
f: function(x: number, y: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
},
|
||||
g: function(x: number, y: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}
|
||||
};
|
||||
const b: I2 = {
|
||||
a: undefined,
|
||||
b: undefined
|
||||
};
|
||||
class C {
|
||||
public c: I1 = {
|
||||
a: 0,
|
||||
b: "",
|
||||
c: 1,
|
||||
d: "d",
|
||||
e: "e1",
|
||||
f: function(x: number, y: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
},
|
||||
g: function(x: number, y: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}
|
||||
};
|
||||
}
|
||||
function fn(foo: I2 = {
|
||||
a: undefined,
|
||||
b: undefined
|
||||
}) {
|
||||
}`
|
||||
});
|
||||
Reference in New Issue
Block a user