mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Fix unassignable properties by adding undefined with exactOptionalPropertyTypes (#45032)
* Simple first version Doesn't cover or test any complicated variations. * Lots of cases work Destructuring does not. But - skipping node_modules and lib.* does. - call expressions does - property access, including with private identifiers, does * Support variable declarations, property assignments, destructuring As long as it's not nested * More cleanup * skip all d.ts, not just node_modules/lib * Offer a codefix for a lot more cases * remove incorrect tuple check * Use getSymbolId instead of converting to string Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com> * add test + switch to tracking number symbol ids * Address PR comments * Exclude tuples from suggestion * Better way to get error node Plus add a check that errorNode is an argument to the call, not the call's expression. * fix semicolon lint * fix another crash * Simplify: add undefined to all optional propertie whether or not somebody tried to assign undefined to them in the erroneous assignment * remove fix-all Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com>
This commit is contained in:
co-authored by
Andrew Branch
parent
92e7fb521f
commit
8d4fe5a0fb
+49
-14
@@ -635,6 +635,7 @@ namespace ts {
|
||||
isTupleType,
|
||||
isArrayLikeType,
|
||||
isTypeInvalidDueToUnionDiscriminant,
|
||||
getExactOptionalProperties,
|
||||
getAllPossiblePropertiesOfTypes,
|
||||
getSuggestedSymbolForNonexistentProperty,
|
||||
getSuggestionForNonexistentProperty,
|
||||
@@ -16768,24 +16769,29 @@ namespace ts {
|
||||
let sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType);
|
||||
if (!sourcePropType) continue;
|
||||
const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined);
|
||||
const targetIsOptional = !!(propName && (getPropertyOfType(target, propName) || unknownSymbol).flags & SymbolFlags.Optional);
|
||||
const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional);
|
||||
targetPropType = removeMissingType(targetPropType, targetIsOptional);
|
||||
sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional);
|
||||
if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) {
|
||||
const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer);
|
||||
if (elaborated) {
|
||||
reportedError = true;
|
||||
}
|
||||
else {
|
||||
reportedError = true;
|
||||
if (!elaborated) {
|
||||
// Issue error on the prop itself, since the prop couldn't elaborate the error
|
||||
const resultObj: { errors?: Diagnostic[] } = errorOutputContainer || {};
|
||||
// Use the expression type, if available
|
||||
const specificSource = next ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType;
|
||||
const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj);
|
||||
if (result && specificSource !== sourcePropType) {
|
||||
// If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType
|
||||
checkTypeRelatedTo(sourcePropType, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj);
|
||||
if (exactOptionalPropertyTypes && isExactOptionalPropertyMismatch(specificSource, targetPropType)) {
|
||||
const diag = createDiagnosticForNode(prop, Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, typeToString(specificSource), typeToString(targetPropType));
|
||||
diagnostics.add(diag);
|
||||
resultObj.errors = [diag];
|
||||
}
|
||||
else {
|
||||
const targetIsOptional = !!(propName && (getPropertyOfType(target, propName) || unknownSymbol).flags & SymbolFlags.Optional);
|
||||
const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional);
|
||||
targetPropType = removeMissingType(targetPropType, targetIsOptional);
|
||||
sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional);
|
||||
const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj);
|
||||
if (result && specificSource !== sourcePropType) {
|
||||
// If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType
|
||||
checkTypeRelatedTo(sourcePropType, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj);
|
||||
}
|
||||
}
|
||||
if (resultObj.errors) {
|
||||
const reportedDiag = resultObj.errors[resultObj.errors.length - 1];
|
||||
@@ -16813,7 +16819,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
reportedError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17679,10 +17684,18 @@ namespace ts {
|
||||
else if (sourceType === targetType) {
|
||||
message = Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated;
|
||||
}
|
||||
else if (exactOptionalPropertyTypes && getExactOptionalUnassignableProperties(source, target).length) {
|
||||
message = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties;
|
||||
}
|
||||
else {
|
||||
message = Diagnostics.Type_0_is_not_assignable_to_type_1;
|
||||
}
|
||||
}
|
||||
else if (message === Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1
|
||||
&& exactOptionalPropertyTypes
|
||||
&& getExactOptionalUnassignableProperties(source, target).length) {
|
||||
message = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties;
|
||||
}
|
||||
|
||||
reportError(message, generalizedSourceType, targetType);
|
||||
}
|
||||
@@ -19598,6 +19611,20 @@ namespace ts {
|
||||
return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral);
|
||||
}
|
||||
|
||||
function getExactOptionalUnassignableProperties(source: Type, target: Type) {
|
||||
if (isTupleType(source) && isTupleType(target)) return emptyArray;
|
||||
return getPropertiesOfType(target)
|
||||
.filter(targetProp => isExactOptionalPropertyMismatch(getTypeOfPropertyOfType(source, targetProp.escapedName), getTypeOfSymbol(targetProp)));
|
||||
}
|
||||
|
||||
function isExactOptionalPropertyMismatch(source: Type | undefined, target: Type | undefined) {
|
||||
return !!source && !!target && maybeTypeOfKind(source, TypeFlags.Undefined) && !!containsMissingType(target);
|
||||
}
|
||||
|
||||
function getExactOptionalProperties(type: Type) {
|
||||
return getPropertiesOfType(type).filter(targetProp => containsMissingType(getTypeOfSymbol(targetProp)));
|
||||
}
|
||||
|
||||
function getBestMatchingType(source: Type, target: UnionOrIntersectionType, isRelatedTo = compareTypesAssignable) {
|
||||
return findMatchingDiscriminantType(source, target, isRelatedTo, /*skipPartial*/ true) ||
|
||||
findMatchingTypeReferenceOrTypeAliasReference(source, target) ||
|
||||
@@ -32479,8 +32506,16 @@ namespace ts {
|
||||
Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access,
|
||||
Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access)
|
||||
&& (!isIdentifier(left) || unescapeLeadingUnderscores(left.escapedText) !== "exports")) {
|
||||
|
||||
let headMessage: DiagnosticMessage | undefined;
|
||||
if (exactOptionalPropertyTypes && isPropertyAccessExpression(left) && maybeTypeOfKind(valueType, TypeFlags.Undefined)) {
|
||||
const target = getTypeOfPropertyOfType(getTypeOfExpression(left.expression), left.name.escapedText);
|
||||
if (isExactOptionalPropertyMismatch(valueType, target)) {
|
||||
headMessage = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target;
|
||||
}
|
||||
}
|
||||
// to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported
|
||||
checkTypeAssignableToAndOptionallyElaborate(valueType, leftType, left, right);
|
||||
checkTypeAssignableToAndOptionallyElaborate(valueType, leftType, left, right, headMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1738,6 +1738,10 @@
|
||||
"category": "Error",
|
||||
"code": 2374
|
||||
},
|
||||
"Type '{0}' is not assignable to type '{1}' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.": {
|
||||
"category": "Error",
|
||||
"code": 2375
|
||||
},
|
||||
"A 'super' call must be the first statement in the constructor when a class contains initialized properties, parameter properties, or private identifiers.": {
|
||||
"category": "Error",
|
||||
"code": 2376
|
||||
@@ -1750,6 +1754,10 @@
|
||||
"category": "Error",
|
||||
"code": 2378
|
||||
},
|
||||
"Argument of type '{0}' is not assignable to parameter of type '{1}' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.": {
|
||||
"category": "Error",
|
||||
"code": 2379
|
||||
},
|
||||
"The return type of a 'get' accessor must be assignable to its 'set' accessor type": {
|
||||
"category": "Error",
|
||||
"code": 2380
|
||||
@@ -1874,6 +1882,10 @@
|
||||
"category": "Error",
|
||||
"code": 2410
|
||||
},
|
||||
"Type '{0}' is not assignable to type '{1}' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.": {
|
||||
"category": "Error",
|
||||
"code": 2412
|
||||
},
|
||||
"Property '{0}' of type '{1}' is not assignable to '{2}' index type '{3}'.": {
|
||||
"category": "Error",
|
||||
"code": 2411
|
||||
@@ -7118,6 +7130,10 @@
|
||||
"category": "Message",
|
||||
"code": 95168
|
||||
},
|
||||
"Add 'undefined' to optional property type": {
|
||||
"category": "Message",
|
||||
"code": 95169
|
||||
},
|
||||
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -4308,6 +4308,7 @@ namespace ts {
|
||||
* e.g. it specifies `kind: "a"` and obj has `kind: "b"`.
|
||||
*/
|
||||
/* @internal */ isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression | JsxAttributes): boolean;
|
||||
/* @internal */ getExactOptionalProperties(type: Type): Symbol[];
|
||||
/**
|
||||
* For a union, will include a property if it's defined in *any* of the member types.
|
||||
* So for `{ a } | { b }`, this will include both `a` and `b`.
|
||||
|
||||
@@ -641,7 +641,8 @@ namespace FourSlash {
|
||||
if (errors.length) {
|
||||
this.printErrorLog(/*expectErrors*/ false, errors);
|
||||
const error = errors[0];
|
||||
this.raiseError(`Found an error: ${this.formatPosition(error.file!, error.start!)}: ${error.messageText}`);
|
||||
const message = typeof error.messageText === "string" ? error.messageText : error.messageText.messageText;
|
||||
this.raiseError(`Found an error: ${this.formatPosition(error.file!, error.start!)}: ${message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace ts.codefix {
|
||||
errorCodes,
|
||||
getCodeActions: context => {
|
||||
const { sourceFile, errorCode, span, cancellationToken, program } = context;
|
||||
const expression = getFixableErrorSpanExpression(sourceFile, errorCode, span, cancellationToken, program);
|
||||
const expression = getAwaitErrorSpanExpression(sourceFile, errorCode, span, cancellationToken, program);
|
||||
if (!expression) {
|
||||
return;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace ts.codefix {
|
||||
const checker = context.program.getTypeChecker();
|
||||
const fixedDeclarations = new Set<number>();
|
||||
return codeFixAll(context, errorCodes, (t, diagnostic) => {
|
||||
const expression = getFixableErrorSpanExpression(sourceFile, diagnostic.code, diagnostic, cancellationToken, program);
|
||||
const expression = getAwaitErrorSpanExpression(sourceFile, diagnostic.code, diagnostic, cancellationToken, program);
|
||||
if (!expression) {
|
||||
return;
|
||||
}
|
||||
@@ -59,6 +59,13 @@ namespace ts.codefix {
|
||||
},
|
||||
});
|
||||
|
||||
function getAwaitErrorSpanExpression(sourceFile: SourceFile, errorCode: number, span: TextSpan, cancellationToken: CancellationToken, program: Program) {
|
||||
const expression = getFixableErrorSpanExpression(sourceFile, span);
|
||||
return expression
|
||||
&& isMissingAwaitError(sourceFile, errorCode, span, cancellationToken, program)
|
||||
&& isInsideAwaitableBody(expression) ? expression : undefined;
|
||||
}
|
||||
|
||||
function getDeclarationSiteFix(context: CodeFixContext | CodeFixAllContext, expression: Expression, errorCode: number, checker: TypeChecker, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Set<number>) {
|
||||
const { sourceFile, program, cancellationToken } = context;
|
||||
const awaitableInitializers = findAwaitableInitializers(expression, sourceFile, cancellationToken, program, checker);
|
||||
@@ -95,23 +102,6 @@ namespace ts.codefix {
|
||||
some(relatedInformation, related => related.code === Diagnostics.Did_you_forget_to_use_await.code));
|
||||
}
|
||||
|
||||
function getFixableErrorSpanExpression(sourceFile: SourceFile, errorCode: number, span: TextSpan, cancellationToken: CancellationToken, program: Program): Expression | undefined {
|
||||
const token = getTokenAtPosition(sourceFile, span.start);
|
||||
// Checker has already done work to determine that await might be possible, and has attached
|
||||
// related info to the node, so start by finding the expression that exactly matches up
|
||||
// with the diagnostic range.
|
||||
const expression = findAncestor(token, node => {
|
||||
if (node.getStart(sourceFile) < span.start || node.getEnd() > textSpanEnd(span)) {
|
||||
return "quit";
|
||||
}
|
||||
return isExpression(node) && textSpansEqual(span, createTextSpanFromNode(node, sourceFile));
|
||||
}) as Expression | undefined;
|
||||
|
||||
return expression
|
||||
&& isMissingAwaitError(sourceFile, errorCode, span, cancellationToken, program)
|
||||
&& isInsideAwaitableBody(expression) ? expression : undefined;
|
||||
}
|
||||
|
||||
interface AwaitableInitializer {
|
||||
expression: Expression;
|
||||
declarationSymbol: Symbol;
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
const addOptionalPropertyUndefined = "addOptionalPropertyUndefined";
|
||||
|
||||
const errorCodes = [
|
||||
Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target.code,
|
||||
Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code,
|
||||
Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code,
|
||||
];
|
||||
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
getCodeActions(context) {
|
||||
const typeChecker = context.program.getTypeChecker();
|
||||
const toAdd = getPropertiesToAdd(context.sourceFile, context.span, typeChecker);
|
||||
if (!toAdd.length) {
|
||||
return undefined;
|
||||
}
|
||||
const changes = textChanges.ChangeTracker.with(context, t => addUndefinedToOptionalProperty(t, toAdd));
|
||||
return [createCodeFixActionWithoutFixAll(addOptionalPropertyUndefined, changes, Diagnostics.Add_undefined_to_optional_property_type)];
|
||||
},
|
||||
fixIds: [addOptionalPropertyUndefined],
|
||||
});
|
||||
|
||||
function getPropertiesToAdd(file: SourceFile, span: TextSpan, checker: TypeChecker): Symbol[] {
|
||||
const sourceTarget = getSourceTarget(getFixableErrorSpanExpression(file, span), checker);
|
||||
if (!sourceTarget) {
|
||||
return emptyArray;
|
||||
}
|
||||
const { source: sourceNode, target: targetNode } = sourceTarget;
|
||||
const target = shouldUseParentTypeOfProperty(sourceNode, targetNode, checker)
|
||||
? checker.getTypeAtLocation(targetNode.expression)
|
||||
: checker.getTypeAtLocation(targetNode);
|
||||
if (target.symbol?.declarations?.some(d => getSourceFileOfNode(d).fileName.match(/\.d\.ts$/))) {
|
||||
return emptyArray;
|
||||
}
|
||||
return checker.getExactOptionalProperties(target);
|
||||
}
|
||||
|
||||
function shouldUseParentTypeOfProperty(sourceNode: Node, targetNode: Node, checker: TypeChecker): targetNode is PropertyAccessExpression {
|
||||
return isPropertyAccessExpression(targetNode)
|
||||
&& !!checker.getExactOptionalProperties(checker.getTypeAtLocation(targetNode.expression)).length
|
||||
&& checker.getTypeAtLocation(sourceNode) === checker.getUndefinedType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the source and target of the incorrect assignment.
|
||||
* The call is recursive for property assignments.
|
||||
*/
|
||||
function getSourceTarget(errorNode: Node | undefined, checker: TypeChecker): { source: Node, target: Node } | undefined {
|
||||
if (!errorNode) {
|
||||
return undefined;
|
||||
}
|
||||
else if (isBinaryExpression(errorNode.parent) && errorNode.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
return { source: errorNode.parent.right, target: errorNode.parent.left };
|
||||
}
|
||||
else if (isVariableDeclaration(errorNode.parent) && errorNode.parent.initializer) {
|
||||
return { source: errorNode.parent.initializer, target: errorNode.parent.name };
|
||||
}
|
||||
else if (isCallExpression(errorNode.parent)) {
|
||||
const n = checker.getSymbolAtLocation(errorNode.parent.expression);
|
||||
if (!n?.valueDeclaration || !isFunctionLikeKind(n.valueDeclaration.kind)) return undefined;
|
||||
if (!isExpression(errorNode)) return undefined;
|
||||
const i = errorNode.parent.arguments.indexOf(errorNode);
|
||||
if (i === -1) return undefined;
|
||||
const name = (n.valueDeclaration as any as SignatureDeclaration).parameters[i].name;
|
||||
if (isIdentifier(name)) return { source: errorNode, target: name };
|
||||
}
|
||||
else if (isPropertyAssignment(errorNode.parent) && isIdentifier(errorNode.parent.name) ||
|
||||
isShorthandPropertyAssignment(errorNode.parent)) {
|
||||
const parentTarget = getSourceTarget(errorNode.parent.parent, checker);
|
||||
if (!parentTarget) return undefined;
|
||||
const prop = checker.getPropertyOfType(checker.getTypeAtLocation(parentTarget.target), (errorNode.parent.name as Identifier).text);
|
||||
const declaration = prop?.declarations?.[0];
|
||||
if (!declaration) return undefined;
|
||||
return {
|
||||
source: isPropertyAssignment(errorNode.parent) ? errorNode.parent.initializer : errorNode.parent.name,
|
||||
target: declaration
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function addUndefinedToOptionalProperty(changes: textChanges.ChangeTracker, toAdd: Symbol[]) {
|
||||
for (const add of toAdd) {
|
||||
const d = add.valueDeclaration;
|
||||
if (d && (isPropertySignature(d) || isPropertyDeclaration(d)) && d.type) {
|
||||
const t = factory.createUnionTypeNode([
|
||||
...d.type.kind === SyntaxKind.UnionType ? (d.type as UnionTypeNode).types : [d.type],
|
||||
factory.createTypeReferenceNode("undefined")
|
||||
]);
|
||||
changes.replaceNode(d.getSourceFile(), d.type, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,7 @@
|
||||
"codefixes/addMissingDeclareProperty.ts",
|
||||
"codefixes/addMissingInvocationForDecorator.ts",
|
||||
"codefixes/addNameToNamelessParameter.ts",
|
||||
"codefixes/addOptionalPropertyUndefined.ts",
|
||||
"codefixes/annotateWithTypeFromJSDoc.ts",
|
||||
"codefixes/convertFunctionToEs6Class.ts",
|
||||
"codefixes/convertToAsyncFunction.ts",
|
||||
|
||||
@@ -3085,6 +3085,22 @@ namespace ts {
|
||||
return createTextSpanFromBounds(startPosition, endPosition === undefined ? startPosition : endPosition);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getFixableErrorSpanExpression(sourceFile: SourceFile, span: TextSpan): Expression | undefined {
|
||||
const token = getTokenAtPosition(sourceFile, span.start);
|
||||
// Checker has already done work to determine that await might be possible, and has attached
|
||||
// related info to the node, so start by finding the expression that exactly matches up
|
||||
// with the diagnostic range.
|
||||
const expression = findAncestor(token, node => {
|
||||
if (node.getStart(sourceFile) < span.start || node.getEnd() > textSpanEnd(span)) {
|
||||
return "quit";
|
||||
}
|
||||
return isExpression(node) && textSpansEqual(span, createTextSpanFromNode(node, sourceFile));
|
||||
}) as Expression | undefined;
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the provided value is an array, the mapping function is applied to each element; otherwise, the mapping function is applied
|
||||
* to the provided value itself.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(6,5): error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(12,5): error TS2322: Type 'string | undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(6,5): error TS2412: Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(12,5): error TS2412: Type 'string | undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(20,9): error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(28,9): error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(53,5): error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(20,9): error TS2412: Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(28,9): error TS2412: Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(53,5): error TS2412: Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(60,5): error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(64,5): error TS2322: Type '[number, string?, string?]' is not assignable to type '[number, string?]'.
|
||||
Target allows only 2 element(s) but source may have more.
|
||||
@@ -11,24 +11,43 @@ tests/cases/compiler/strictOptionalProperties1.ts(73,5): error TS2322: Type '[nu
|
||||
Target allows only 3 element(s) but source may have more.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(74,5): error TS2322: Type '[never?, never?, true?]' is not assignable to type '[number, string?, boolean?]'.
|
||||
Source provides no match for required element at position 0 in target.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(75,14): error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(99,34): error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(105,45): error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(106,55): error TS2322: Type 'undefined' is not assignable to type 'boolean'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(107,45): error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(107,56): error TS2322: Type 'undefined' is not assignable to type 'boolean'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(111,31): error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(75,5): error TS2322: Type '[number, undefined, true]' is not assignable to type '[number, string?, boolean?]'.
|
||||
Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(99,7): error TS2375: Type '{ foo: undefined; bar: string; }' is not assignable to type 'InputProps' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
|
||||
Types of property 'foo' are incompatible.
|
||||
Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(105,7): error TS2322: Type '[number, undefined]' is not assignable to type '[number, string?, boolean?]'.
|
||||
Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(106,7): error TS2322: Type '[number, string, undefined]' is not assignable to type '[number, string?, boolean?]'.
|
||||
Type at position 2 in source is not compatible with type at position 2 in target.
|
||||
Type 'undefined' is not assignable to type 'boolean'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(107,7): error TS2322: Type '[number, undefined, undefined]' is not assignable to type '[number, string?, boolean?]'.
|
||||
Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
Type 'undefined' is not assignable to type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(111,7): error TS2375: Type '{ foo: undefined; }' is not assignable to type '{ foo?: number; }' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
|
||||
Types of property 'foo' are incompatible.
|
||||
Type 'undefined' is not assignable to type 'number'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(119,5): error TS2411: Property 'bar' of type 'string | undefined' is not assignable to 'string' index type 'string'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(192,1): error TS2322: Type '{ a: number; b: string | undefined; }' is not assignable to type '{ [x: string]: string | number; }'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(190,15): error TS2451: Cannot redeclare block-scoped variable 'e'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type 'string | boolean | undefined' is not assignable to type 'string | number | undefined'.
|
||||
Type 'false' is not assignable to type 'string | number | undefined'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(194,1): error TS2412: Type 'string | boolean | undefined' is not assignable to type 'string | number' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
Type 'undefined' is not assignable to type 'string | number'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(195,1): error TS2375: Type '{ name: string; email: undefined; }' is not assignable to type 'U2' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
|
||||
Types of property 'email' are incompatible.
|
||||
Type 'undefined' is not assignable to type 'string | number'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(206,13): error TS2451: Cannot redeclare block-scoped variable 'e'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(210,1): error TS2322: Type '{ a: number; b: string | undefined; }' is not assignable to type '{ [x: string]: string | number; }'.
|
||||
Property 'b' is incompatible with index signature.
|
||||
Type 'string | undefined' is not assignable to type 'string | number'.
|
||||
Type 'undefined' is not assignable to type 'string | number'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{ a: number; b?: string | undefined; }' is not assignable to type '{ [x: string]: string | number; }'.
|
||||
Property 'b' is incompatible with index signature.
|
||||
Type 'string | undefined' is not assignable to type 'string | number'.
|
||||
tests/cases/compiler/strictOptionalProperties1.ts(211,1): error TS2322: Type 'string | boolean | undefined' is not assignable to type '{ [x: string]: string | number; }'.
|
||||
Type 'undefined' is not assignable to type '{ [x: string]: string | number; }'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/strictOptionalProperties1.ts (19 errors) ====
|
||||
==== tests/cases/compiler/strictOptionalProperties1.ts (23 errors) ====
|
||||
function f1(obj: { a?: string, b?: string | undefined }) {
|
||||
let a = obj.a; // string | undefined
|
||||
let b = obj.b; // string | undefined
|
||||
@@ -36,7 +55,7 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
obj.b = 'hello';
|
||||
obj.a = undefined; // Error
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
!!! error TS2412: Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
obj.b = undefined;
|
||||
}
|
||||
|
||||
@@ -44,8 +63,8 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
obj = obj;
|
||||
obj.a = obj.a; // Error
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'string | undefined' is not assignable to type 'string'.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
!!! error TS2412: Type 'string | undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
!!! error TS2412: Type 'undefined' is not assignable to type 'string'.
|
||||
obj.b = obj.b;
|
||||
if ('a' in obj) {
|
||||
obj.a;
|
||||
@@ -55,7 +74,7 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
obj.a;
|
||||
obj.a = obj.a; // Error
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
!!! error TS2412: Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
}
|
||||
if (obj.hasOwnProperty('a')) {
|
||||
obj.a;
|
||||
@@ -65,7 +84,7 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
obj.a;
|
||||
obj.a = obj.a; // Error
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
!!! error TS2412: Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
}
|
||||
if ('b' in obj) {
|
||||
obj.b;
|
||||
@@ -92,7 +111,7 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
obj.b = 'hello';
|
||||
obj.a = undefined; // Error
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
!!! error TS2412: Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
obj.b = undefined;
|
||||
}
|
||||
|
||||
@@ -126,8 +145,10 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
!!! error TS2322: Type '[never?, never?, true?]' is not assignable to type '[number, string?, boolean?]'.
|
||||
!!! error TS2322: Source provides no match for required element at position 0 in target.
|
||||
t = [42, undefined, true]; // Error
|
||||
~~~~~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
~
|
||||
!!! error TS2322: Type '[number, undefined, true]' is not assignable to type '[number, string?, boolean?]'.
|
||||
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
}
|
||||
|
||||
function f6() {
|
||||
@@ -152,32 +173,38 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
|
||||
const defaultProps: Pick<Props, 'foo'> = { foo: 'foo' };
|
||||
const inputProps: InputProps = { foo: undefined, bar: 'bar' };
|
||||
~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
!!! related TS6500 tests/cases/compiler/strictOptionalProperties1.ts:94:5: The expected type comes from property 'foo' which is declared here on type 'InputProps'
|
||||
~~~~~~~~~~
|
||||
!!! error TS2375: Type '{ foo: undefined; bar: string; }' is not assignable to type 'InputProps' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
|
||||
!!! error TS2375: Types of property 'foo' are incompatible.
|
||||
!!! error TS2375: Type 'undefined' is not assignable to type 'string'.
|
||||
const completeProps: Props = { ...defaultProps, ...inputProps };
|
||||
|
||||
// Example from #13195
|
||||
|
||||
const t1: [number, string?, boolean?] = [1];
|
||||
const t2: [number, string?, boolean?] = [1, undefined];
|
||||
~~~~~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
~~
|
||||
!!! error TS2322: Type '[number, undefined]' is not assignable to type '[number, string?, boolean?]'.
|
||||
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
const t3: [number, string?, boolean?] = [1, "string", undefined];
|
||||
~~~~~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'boolean'.
|
||||
~~
|
||||
!!! error TS2322: Type '[number, string, undefined]' is not assignable to type '[number, string?, boolean?]'.
|
||||
!!! error TS2322: Type at position 2 in source is not compatible with type at position 2 in target.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'boolean'.
|
||||
const t4: [number, string?, boolean?] = [1, undefined, undefined];
|
||||
~~~~~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
~~~~~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'boolean'.
|
||||
~~
|
||||
!!! error TS2322: Type '[number, undefined, undefined]' is not assignable to type '[number, string?, boolean?]'.
|
||||
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
|
||||
|
||||
// Example from #13195
|
||||
|
||||
const x: { foo?: number } = { foo: undefined };
|
||||
~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
!!! related TS6500 tests/cases/compiler/strictOptionalProperties1.ts:111:12: The expected type comes from property 'foo' which is declared here on type '{ foo?: number; }'
|
||||
~
|
||||
!!! error TS2375: Type '{ foo: undefined; }' is not assignable to type '{ foo?: number; }' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
|
||||
!!! error TS2375: Types of property 'foo' are incompatible.
|
||||
!!! error TS2375: Type 'undefined' is not assignable to type 'number'.
|
||||
const y: { foo: number } = { foo: 123, ...x };
|
||||
|
||||
// Index signatures and strict optional properties
|
||||
@@ -250,6 +277,36 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
|
||||
declare function bb(input: number): void;
|
||||
|
||||
interface U1 {
|
||||
name: string
|
||||
email?: string | number | undefined
|
||||
}
|
||||
interface U2 {
|
||||
name: string
|
||||
email?: string | number
|
||||
}
|
||||
declare const e: string | boolean | undefined
|
||||
~
|
||||
!!! error TS2451: Cannot redeclare block-scoped variable 'e'.
|
||||
declare const u1: U1
|
||||
declare let u2: U2
|
||||
u1.email = e // error, but only because boolean isn't in email's type
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type 'string | boolean | undefined' is not assignable to type 'string | number | undefined'.
|
||||
!!! error TS2322: Type 'false' is not assignable to type 'string | number | undefined'.
|
||||
u2.email = e // error, and suggest adding undefined
|
||||
~~~~~~~~
|
||||
!!! error TS2412: Type 'string | boolean | undefined' is not assignable to type 'string | number' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
|
||||
!!! error TS2412: Type 'undefined' is not assignable to type 'string | number'.
|
||||
u2 = {
|
||||
~~
|
||||
!!! error TS2375: Type '{ name: string; email: undefined; }' is not assignable to type 'U2' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
|
||||
!!! error TS2375: Types of property 'email' are incompatible.
|
||||
!!! error TS2375: Type 'undefined' is not assignable to type 'string | number'.
|
||||
name: 'hi',
|
||||
email: undefined
|
||||
}
|
||||
|
||||
// Repro from #44437
|
||||
|
||||
declare var a: {[x: string]: number | string }
|
||||
@@ -257,6 +314,8 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
declare var c: {a: number, b?: string}
|
||||
declare var d: {a: number, b: string | undefined }
|
||||
declare var e: {a: number, b?: string | undefined }
|
||||
~
|
||||
!!! error TS2451: Cannot redeclare block-scoped variable 'e'.
|
||||
|
||||
a = b;
|
||||
a = c;
|
||||
@@ -268,7 +327,6 @@ tests/cases/compiler/strictOptionalProperties1.ts(193,1): error TS2322: Type '{
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'.
|
||||
a = e; // Error
|
||||
~
|
||||
!!! error TS2322: Type '{ a: number; b?: string | undefined; }' is not assignable to type '{ [x: string]: string | number; }'.
|
||||
!!! error TS2322: Property 'b' is incompatible with index signature.
|
||||
!!! error TS2322: Type 'string | undefined' is not assignable to type 'string | number'.
|
||||
!!! error TS2322: Type 'string | boolean | undefined' is not assignable to type '{ [x: string]: string | number; }'.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type '{ [x: string]: string | number; }'.
|
||||
|
||||
@@ -180,6 +180,24 @@ function aa(input: Bar): void {
|
||||
|
||||
declare function bb(input: number): void;
|
||||
|
||||
interface U1 {
|
||||
name: string
|
||||
email?: string | number | undefined
|
||||
}
|
||||
interface U2 {
|
||||
name: string
|
||||
email?: string | number
|
||||
}
|
||||
declare const e: string | boolean | undefined
|
||||
declare const u1: U1
|
||||
declare let u2: U2
|
||||
u1.email = e // error, but only because boolean isn't in email's type
|
||||
u2.email = e // error, and suggest adding undefined
|
||||
u2 = {
|
||||
name: 'hi',
|
||||
email: undefined
|
||||
}
|
||||
|
||||
// Repro from #44437
|
||||
|
||||
declare var a: {[x: string]: number | string }
|
||||
@@ -322,6 +340,12 @@ function aa(input) {
|
||||
var notUndefinedVal = expectNotUndefined(input.bar);
|
||||
bb(notUndefinedVal);
|
||||
}
|
||||
u1.email = e; // error, but only because boolean isn't in email's type
|
||||
u2.email = e; // error, and suggest adding undefined
|
||||
u2 = {
|
||||
name: 'hi',
|
||||
email: undefined
|
||||
};
|
||||
a = b;
|
||||
a = c;
|
||||
a = d; // Error
|
||||
@@ -399,6 +423,17 @@ interface Bar {
|
||||
}
|
||||
declare function aa(input: Bar): void;
|
||||
declare function bb(input: number): void;
|
||||
interface U1 {
|
||||
name: string;
|
||||
email?: string | number | undefined;
|
||||
}
|
||||
interface U2 {
|
||||
name: string;
|
||||
email?: string | number;
|
||||
}
|
||||
declare const e: string | boolean | undefined;
|
||||
declare const u1: U1;
|
||||
declare let u2: U2;
|
||||
declare var a: {
|
||||
[x: string]: number | string;
|
||||
};
|
||||
|
||||
@@ -571,45 +571,97 @@ declare function bb(input: number): void;
|
||||
>bb : Symbol(bb, Decl(strictOptionalProperties1.ts, 177, 1))
|
||||
>input : Symbol(input, Decl(strictOptionalProperties1.ts, 179, 20))
|
||||
|
||||
interface U1 {
|
||||
>U1 : Symbol(U1, Decl(strictOptionalProperties1.ts, 179, 41))
|
||||
|
||||
name: string
|
||||
>name : Symbol(U1.name, Decl(strictOptionalProperties1.ts, 181, 14))
|
||||
|
||||
email?: string | number | undefined
|
||||
>email : Symbol(U1.email, Decl(strictOptionalProperties1.ts, 182, 16))
|
||||
}
|
||||
interface U2 {
|
||||
>U2 : Symbol(U2, Decl(strictOptionalProperties1.ts, 184, 1))
|
||||
|
||||
name: string
|
||||
>name : Symbol(U2.name, Decl(strictOptionalProperties1.ts, 185, 14))
|
||||
|
||||
email?: string | number
|
||||
>email : Symbol(U2.email, Decl(strictOptionalProperties1.ts, 186, 16))
|
||||
}
|
||||
declare const e: string | boolean | undefined
|
||||
>e : Symbol(e, Decl(strictOptionalProperties1.ts, 189, 13))
|
||||
|
||||
declare const u1: U1
|
||||
>u1 : Symbol(u1, Decl(strictOptionalProperties1.ts, 190, 13))
|
||||
>U1 : Symbol(U1, Decl(strictOptionalProperties1.ts, 179, 41))
|
||||
|
||||
declare let u2: U2
|
||||
>u2 : Symbol(u2, Decl(strictOptionalProperties1.ts, 191, 11))
|
||||
>U2 : Symbol(U2, Decl(strictOptionalProperties1.ts, 184, 1))
|
||||
|
||||
u1.email = e // error, but only because boolean isn't in email's type
|
||||
>u1.email : Symbol(U1.email, Decl(strictOptionalProperties1.ts, 182, 16))
|
||||
>u1 : Symbol(u1, Decl(strictOptionalProperties1.ts, 190, 13))
|
||||
>email : Symbol(U1.email, Decl(strictOptionalProperties1.ts, 182, 16))
|
||||
>e : Symbol(e, Decl(strictOptionalProperties1.ts, 189, 13))
|
||||
|
||||
u2.email = e // error, and suggest adding undefined
|
||||
>u2.email : Symbol(U2.email, Decl(strictOptionalProperties1.ts, 186, 16))
|
||||
>u2 : Symbol(u2, Decl(strictOptionalProperties1.ts, 191, 11))
|
||||
>email : Symbol(U2.email, Decl(strictOptionalProperties1.ts, 186, 16))
|
||||
>e : Symbol(e, Decl(strictOptionalProperties1.ts, 189, 13))
|
||||
|
||||
u2 = {
|
||||
>u2 : Symbol(u2, Decl(strictOptionalProperties1.ts, 191, 11))
|
||||
|
||||
name: 'hi',
|
||||
>name : Symbol(name, Decl(strictOptionalProperties1.ts, 194, 6))
|
||||
|
||||
email: undefined
|
||||
>email : Symbol(email, Decl(strictOptionalProperties1.ts, 195, 15))
|
||||
>undefined : Symbol(undefined)
|
||||
}
|
||||
|
||||
// Repro from #44437
|
||||
|
||||
declare var a: {[x: string]: number | string }
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 183, 11))
|
||||
>x : Symbol(x, Decl(strictOptionalProperties1.ts, 183, 17))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 201, 11))
|
||||
>x : Symbol(x, Decl(strictOptionalProperties1.ts, 201, 17))
|
||||
|
||||
declare var b: {a: number, b: string}
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 184, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 184, 16))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 184, 26))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 202, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 202, 16))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 202, 26))
|
||||
|
||||
declare var c: {a: number, b?: string}
|
||||
>c : Symbol(c, Decl(strictOptionalProperties1.ts, 185, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 185, 16))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 185, 26))
|
||||
>c : Symbol(c, Decl(strictOptionalProperties1.ts, 203, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 203, 16))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 203, 26))
|
||||
|
||||
declare var d: {a: number, b: string | undefined }
|
||||
>d : Symbol(d, Decl(strictOptionalProperties1.ts, 186, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 186, 16))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 186, 26))
|
||||
>d : Symbol(d, Decl(strictOptionalProperties1.ts, 204, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 204, 16))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 204, 26))
|
||||
|
||||
declare var e: {a: number, b?: string | undefined }
|
||||
>e : Symbol(e, Decl(strictOptionalProperties1.ts, 187, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 187, 16))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 187, 26))
|
||||
>e : Symbol(e, Decl(strictOptionalProperties1.ts, 205, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 205, 16))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 205, 26))
|
||||
|
||||
a = b;
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 183, 11))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 184, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 201, 11))
|
||||
>b : Symbol(b, Decl(strictOptionalProperties1.ts, 202, 11))
|
||||
|
||||
a = c;
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 183, 11))
|
||||
>c : Symbol(c, Decl(strictOptionalProperties1.ts, 185, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 201, 11))
|
||||
>c : Symbol(c, Decl(strictOptionalProperties1.ts, 203, 11))
|
||||
|
||||
a = d; // Error
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 183, 11))
|
||||
>d : Symbol(d, Decl(strictOptionalProperties1.ts, 186, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 201, 11))
|
||||
>d : Symbol(d, Decl(strictOptionalProperties1.ts, 204, 11))
|
||||
|
||||
a = e; // Error
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 183, 11))
|
||||
>e : Symbol(e, Decl(strictOptionalProperties1.ts, 187, 11))
|
||||
>a : Symbol(a, Decl(strictOptionalProperties1.ts, 201, 11))
|
||||
>e : Symbol(e, Decl(strictOptionalProperties1.ts, 189, 13))
|
||||
|
||||
|
||||
@@ -683,6 +683,57 @@ declare function bb(input: number): void;
|
||||
>bb : (input: number) => void
|
||||
>input : number
|
||||
|
||||
interface U1 {
|
||||
name: string
|
||||
>name : string
|
||||
|
||||
email?: string | number | undefined
|
||||
>email : string | number | undefined
|
||||
}
|
||||
interface U2 {
|
||||
name: string
|
||||
>name : string
|
||||
|
||||
email?: string | number
|
||||
>email : string | number | undefined
|
||||
}
|
||||
declare const e: string | boolean | undefined
|
||||
>e : string | boolean | undefined
|
||||
|
||||
declare const u1: U1
|
||||
>u1 : U1
|
||||
|
||||
declare let u2: U2
|
||||
>u2 : U2
|
||||
|
||||
u1.email = e // error, but only because boolean isn't in email's type
|
||||
>u1.email = e : string | boolean | undefined
|
||||
>u1.email : string | number | undefined
|
||||
>u1 : U1
|
||||
>email : string | number | undefined
|
||||
>e : string | boolean | undefined
|
||||
|
||||
u2.email = e // error, and suggest adding undefined
|
||||
>u2.email = e : string | boolean | undefined
|
||||
>u2.email : string | number
|
||||
>u2 : U2
|
||||
>email : string | number
|
||||
>e : string | boolean | undefined
|
||||
|
||||
u2 = {
|
||||
>u2 = { name: 'hi', email: undefined} : { name: string; email: undefined; }
|
||||
>u2 : U2
|
||||
>{ name: 'hi', email: undefined} : { name: string; email: undefined; }
|
||||
|
||||
name: 'hi',
|
||||
>name : string
|
||||
>'hi' : "hi"
|
||||
|
||||
email: undefined
|
||||
>email : undefined
|
||||
>undefined : undefined
|
||||
}
|
||||
|
||||
// Repro from #44437
|
||||
|
||||
declare var a: {[x: string]: number | string }
|
||||
@@ -725,7 +776,7 @@ a = d; // Error
|
||||
>d : { a: number; b: string | undefined; }
|
||||
|
||||
a = e; // Error
|
||||
>a = e : { a: number; b?: string | undefined; }
|
||||
>a = e : string | boolean | undefined
|
||||
>a : { [x: string]: string | number; }
|
||||
>e : { a: number; b?: string | undefined; }
|
||||
>e : string | boolean | undefined
|
||||
|
||||
|
||||
@@ -183,6 +183,24 @@ function aa(input: Bar): void {
|
||||
|
||||
declare function bb(input: number): void;
|
||||
|
||||
interface U1 {
|
||||
name: string
|
||||
email?: string | number | undefined
|
||||
}
|
||||
interface U2 {
|
||||
name: string
|
||||
email?: string | number
|
||||
}
|
||||
declare const e: string | boolean | undefined
|
||||
declare const u1: U1
|
||||
declare let u2: U2
|
||||
u1.email = e // error, but only because boolean isn't in email's type
|
||||
u2.email = e // error, and suggest adding undefined
|
||||
u2 = {
|
||||
name: 'hi',
|
||||
email: undefined
|
||||
}
|
||||
|
||||
// Repro from #44437
|
||||
|
||||
declare var a: {[x: string]: number | string }
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface I {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var i: I
|
||||
//// declare var j: J
|
||||
//// i/**/ = j
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface I {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var i: I
|
||||
declare var j: J
|
||||
i = j`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface IF {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// function fi(if_: IF) { return if_ }
|
||||
//// fi(j/**/)
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface IF {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
function fi(if_: IF) { return if_ }
|
||||
fi(j)`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface IC {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// class C {
|
||||
//// ic: IC
|
||||
//// m() { this.ic/**/ = j }
|
||||
//// }
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface IC {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
class C {
|
||||
ic: IC
|
||||
m() { this.ic = j }
|
||||
}`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface IC2 {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// class C {
|
||||
//// ic2: IC2
|
||||
//// }
|
||||
//// var c = new C()
|
||||
//// c.ic2/**/ = j
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface IC2 {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
class C {
|
||||
ic2: IC2
|
||||
}
|
||||
var c = new C()
|
||||
c.ic2 = j`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface ICP {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// class CP {
|
||||
//// #icp: ICP
|
||||
//// m() { this.#icp/**/ = j; console.log(this.#icp) }
|
||||
//// }
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface ICP {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
class CP {
|
||||
#icp: ICP
|
||||
m() { this.#icp = j; console.log(this.#icp) }
|
||||
}`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface ID {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// declare var id: ID
|
||||
//// ({ id/**/ } = { id: j })
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface ID {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
declare var id: ID
|
||||
({ id } = { id: j })`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface More {
|
||||
//// a?: number
|
||||
//// b?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// declare var more: More
|
||||
//// more/**/ = j
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface More {
|
||||
a?: number | undefined
|
||||
b?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
declare var more: More
|
||||
more = j`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface Assignment {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// var assignment/**/: Assignment = j
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface Assignment {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
var assignment: Assignment = j`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface PropertyAssignment {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// var opa/**/: { pa: PropertyAssignment } = { pa: j }
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface PropertyAssignment {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
var opa: { pa: PropertyAssignment } = { pa: j }`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface ShorthandPropertyAssignment {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// var ospa/**/: { j: ShorthandPropertyAssignment } = { j }
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface ShorthandPropertyAssignment {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
var ospa: { j: ShorthandPropertyAssignment } = { j }`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface FPA {
|
||||
//// a?: number
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var j: J
|
||||
//// declare function fpa(fpa: { fpa: FPA }): void
|
||||
//// fpa({ fpa: j }/**/)
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface FPA {
|
||||
a?: number | undefined
|
||||
}
|
||||
interface J {
|
||||
a?: number | undefined
|
||||
}
|
||||
declare var j: J
|
||||
declare function fpa(fpa: { fpa: FPA }): void
|
||||
fpa({ fpa: j })`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
// @Filename: fixExactOptionalUnassignableProperties2.ts
|
||||
//// import { INodeModules } from 'foo'
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var inm: INodeModules
|
||||
//// declare var j: J
|
||||
//// inm/**/ = j
|
||||
//// console.log(inm)
|
||||
// @Filename: node_modules/@types/foo/index.d.ts
|
||||
//// export interface INodeModules {
|
||||
//// a?: number
|
||||
//// }
|
||||
verify.codeFixAvailable([]);
|
||||
@@ -0,0 +1,30 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
// @Filename: fixExactOptionalUnassignableProperties4.ts
|
||||
//// interface User {
|
||||
//// name: string
|
||||
//// email?: string
|
||||
//// }
|
||||
//// const user: User = {
|
||||
//// name: "Andrew",
|
||||
//// email: undefined,
|
||||
//// }
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface User {
|
||||
name: string
|
||||
email?: string | undefined
|
||||
}
|
||||
const user: User = {
|
||||
name: "Andrew",
|
||||
email: undefined,
|
||||
}`,
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
// @Filename: fixExactOptionalUnassignableProperties5.ts
|
||||
//// interface User {
|
||||
//// name: string
|
||||
//// email?: string
|
||||
//// }
|
||||
//// declare const user: User
|
||||
//// user.email = undefined;
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`interface User {
|
||||
name: string
|
||||
email?: string | undefined
|
||||
}
|
||||
declare const user: User
|
||||
user.email = undefined;`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
// @Filename: fixExactOptionalUnassignableProperties6.ts
|
||||
// based on snapshotterInjected.ts in microsoft/playwright
|
||||
//// type Data = {
|
||||
//// f?: (x: number) => void,
|
||||
//// additional?: number,
|
||||
//// nop: string,
|
||||
//// };
|
||||
//// declare function e(o: any): Data;
|
||||
//// e(101).f = undefined
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`type Data = {
|
||||
f?: ((x: number) => void) | undefined,
|
||||
additional?: number | undefined,
|
||||
nop: string,
|
||||
};
|
||||
declare function e(o: any): Data;
|
||||
e(101).f = undefined`,
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
// @Filename: fixExactOptionalUnassignableProperties6.ts
|
||||
// based on snapshotterInjected.ts in microsoft/playwright
|
||||
//// class Feh {
|
||||
//// _requestFinished(error?: string) {
|
||||
//// this._finishedPromiseCallback({ error/**/ });
|
||||
//// }
|
||||
//// private _finishedPromiseCallback: (arg: { error?: string }) => void = () => {};
|
||||
//// }
|
||||
verify.codeFixAvailable([ ]);
|
||||
@@ -0,0 +1,29 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
// @Filename: fixExactOptionalUnassignableProperties6.ts
|
||||
// based on snapshotterInjected.ts in microsoft/playwright
|
||||
//// type Data = {
|
||||
//// x?: {
|
||||
//// y?: number
|
||||
//// }
|
||||
//// }
|
||||
//// declare var d: Data
|
||||
//// d.x = { y: undefined }
|
||||
verify.codeFixAvailable([
|
||||
{ description: ts.Diagnostics.Add_undefined_to_optional_property_type.message }
|
||||
]);
|
||||
verify.codeFix({
|
||||
description: ts.Diagnostics.Add_undefined_to_optional_property_type.message,
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`type Data = {
|
||||
x?: {
|
||||
y?: number | undefined
|
||||
}
|
||||
}
|
||||
declare var d: Data
|
||||
d.x = { y: undefined }`,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @strictNullChecks: true
|
||||
// @exactOptionalPropertyTypes: true
|
||||
//// interface IAny {
|
||||
//// a?: any
|
||||
//// }
|
||||
//// interface J {
|
||||
//// a?: number | undefined
|
||||
//// }
|
||||
//// declare var iany: IAny
|
||||
//// declare var j: J
|
||||
//// iany/**/ = j
|
||||
verify.codeFixAvailable([]);
|
||||
Reference in New Issue
Block a user