fix(58166): Class parameter property with initializer before required property emits non-nullable parameter for declaration emit (#58177)
This commit is contained in:
Родитель
f04672842b
Коммит
7049af5f4f
|
@ -8316,7 +8316,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
* @param symbol - The symbol is used both to find an existing annotation if declaration is not provided, and to determine if `unique symbol` should be printed
|
||||
*/
|
||||
function serializeTypeForDeclaration(context: NodeBuilderContext, declaration: Declaration | undefined, type: Type, symbol: Symbol) {
|
||||
const addUndefinedForParameter = declaration && (isParameter(declaration) || isJSDocParameterTag(declaration)) && requiresAddingImplicitUndefined(declaration);
|
||||
const addUndefinedForParameter = declaration && (isParameter(declaration) || isJSDocParameterTag(declaration)) && requiresAddingImplicitUndefined(declaration, context.enclosingDeclaration);
|
||||
const enclosingDeclaration = context.enclosingDeclaration;
|
||||
const restoreFlags = saveRestoreFlags(context);
|
||||
if (declaration && hasInferredType(declaration) && !(context.internalFlags & InternalNodeBuilderFlags.NoSyntacticPrinter)) {
|
||||
|
@ -49591,16 +49591,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
const type = getTypeFromTypeNode(typeNode);
|
||||
return containsUndefinedType(type);
|
||||
}
|
||||
function requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag) {
|
||||
return (isRequiredInitializedParameter(parameter) || isOptionalUninitializedParameterProperty(parameter)) && !declaredParameterTypeContainsUndefined(parameter);
|
||||
|
||||
function requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag, enclosingDeclaration: Node | undefined) {
|
||||
return (isRequiredInitializedParameter(parameter, enclosingDeclaration) || isOptionalUninitializedParameterProperty(parameter)) && !declaredParameterTypeContainsUndefined(parameter);
|
||||
}
|
||||
|
||||
function isRequiredInitializedParameter(parameter: ParameterDeclaration | JSDocParameterTag): boolean {
|
||||
return !!strictNullChecks &&
|
||||
!isOptionalParameter(parameter) &&
|
||||
!isJSDocParameterTag(parameter) &&
|
||||
!!parameter.initializer &&
|
||||
!hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier);
|
||||
function isRequiredInitializedParameter(parameter: ParameterDeclaration | JSDocParameterTag, enclosingDeclaration: Node | undefined): boolean {
|
||||
if (!strictNullChecks || isOptionalParameter(parameter) || isJSDocParameterTag(parameter) || !parameter.initializer) {
|
||||
return false;
|
||||
}
|
||||
if (hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier)) {
|
||||
return !!enclosingDeclaration && isFunctionLikeDeclaration(enclosingDeclaration);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isOptionalUninitializedParameterProperty(parameter: ParameterDeclaration | JSDocParameterTag) {
|
||||
|
|
|
@ -178,7 +178,7 @@ export function createSyntacticTypeNodeBuilder(options: CompilerOptions, resolve
|
|||
return typeFromAccessor(parent, context);
|
||||
}
|
||||
const declaredType = getEffectiveTypeAnnotationNode(node);
|
||||
const addUndefined = resolver.requiresAddingImplicitUndefined(node);
|
||||
const addUndefined = resolver.requiresAddingImplicitUndefined(node, context.enclosingDeclaration);
|
||||
let resultType;
|
||||
if (declaredType) {
|
||||
resultType = serializeExistingTypeAnnotation(declaredType, addUndefined);
|
||||
|
|
|
@ -680,7 +680,7 @@ export function transformDeclarations(context: TransformationContext) {
|
|||
// Literal const declarations will have an initializer ensured rather than a type
|
||||
return;
|
||||
}
|
||||
const shouldAddImplicitUndefined = node.kind === SyntaxKind.Parameter && resolver.requiresAddingImplicitUndefined(node);
|
||||
const shouldAddImplicitUndefined = node.kind === SyntaxKind.Parameter && resolver.requiresAddingImplicitUndefined(node, enclosingDeclaration);
|
||||
if (type && !shouldAddImplicitUndefined) {
|
||||
return visitNode(type, visitDeclarationSubtree, isTypeNode);
|
||||
}
|
||||
|
|
|
@ -767,7 +767,7 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
|
|||
if (isSetAccessor(node.parent)) {
|
||||
return createAccessorTypeError(node.parent);
|
||||
}
|
||||
const addUndefined = resolver.requiresAddingImplicitUndefined(node);
|
||||
const addUndefined = resolver.requiresAddingImplicitUndefined(node, /*enclosingDeclaration*/ undefined);
|
||||
if (!addUndefined && node.initializer) {
|
||||
return createExpressionError(node.initializer);
|
||||
}
|
||||
|
|
|
@ -5293,7 +5293,7 @@ export interface TypeChecker {
|
|||
/** @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken, nodesToCheck?: Node[]): Diagnostic[];
|
||||
/** @internal */ getGlobalDiagnostics(): Diagnostic[];
|
||||
/** @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken, forceDts?: boolean): EmitResolver;
|
||||
/** @internal */ requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag): boolean;
|
||||
/** @internal */ requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag, enclosingDeclaration: Node | undefined): boolean;
|
||||
|
||||
/** @internal */ getNodeCount(): number;
|
||||
/** @internal */ getIdentifierCount(): number;
|
||||
|
@ -5814,7 +5814,7 @@ export interface EmitResolver {
|
|||
collectLinkedAliases(node: ModuleExportName, setVisibility?: boolean): Node[] | undefined;
|
||||
markLinkedReferences(node: Node): void;
|
||||
isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined;
|
||||
requiresAddingImplicitUndefined(node: ParameterDeclaration): boolean;
|
||||
requiresAddingImplicitUndefined(node: ParameterDeclaration, enclosingDeclaration: Node | undefined): boolean;
|
||||
isExpandoFunctionDeclaration(node: FunctionDeclaration | VariableDeclaration): boolean;
|
||||
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
|
||||
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
|
||||
|
@ -10378,6 +10378,6 @@ export interface SyntacticTypeNodeBuilderResolver {
|
|||
isExpandoFunctionDeclaration(name: FunctionDeclaration | VariableDeclaration): boolean;
|
||||
getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations;
|
||||
isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node, shouldComputeAliasToMakeVisible?: boolean): SymbolVisibilityResult;
|
||||
requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag): boolean;
|
||||
requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag, enclosingDeclaration: Node | undefined): boolean;
|
||||
isDefinitelyReferenceToGlobalSymbolObject(node: Node): boolean;
|
||||
}
|
||||
|
|
|
@ -914,11 +914,12 @@ function withContext<T>(
|
|||
type = widenedType;
|
||||
}
|
||||
|
||||
if (isParameter(node) && typeChecker.requiresAddingImplicitUndefined(node)) {
|
||||
const enclosingDeclaration = findAncestor(node, isDeclaration) ?? sourceFile;
|
||||
if (isParameter(node) && typeChecker.requiresAddingImplicitUndefined(node, enclosingDeclaration)) {
|
||||
type = typeChecker.getUnionType([typeChecker.getUndefinedType(), type], UnionReduction.None);
|
||||
}
|
||||
return {
|
||||
typeNode: typeToTypeNode(type, findAncestor(node, isDeclaration) ?? sourceFile, getFlags(type)),
|
||||
typeNode: typeToTypeNode(type, enclosingDeclaration, getFlags(type)),
|
||||
mutatedTarget: false,
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
//// [tests/cases/compiler/parameterPropertyInConstructor4.ts] ////
|
||||
|
||||
//// [parameterPropertyInConstructor4.ts]
|
||||
export class C {
|
||||
constructor(public a: number[] = [], b: number) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [parameterPropertyInConstructor4.js]
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.C = void 0;
|
||||
var C = /** @class */ (function () {
|
||||
function C(a, b) {
|
||||
if (a === void 0) { a = []; }
|
||||
this.a = a;
|
||||
}
|
||||
return C;
|
||||
}());
|
||||
exports.C = C;
|
||||
|
||||
|
||||
//// [parameterPropertyInConstructor4.d.ts]
|
||||
export declare class C {
|
||||
a: number[];
|
||||
constructor(a: number[] | undefined, b: number);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
//// [tests/cases/compiler/parameterPropertyInConstructor4.ts] ////
|
||||
|
||||
=== parameterPropertyInConstructor4.ts ===
|
||||
export class C {
|
||||
>C : Symbol(C, Decl(parameterPropertyInConstructor4.ts, 0, 0))
|
||||
|
||||
constructor(public a: number[] = [], b: number) {
|
||||
>a : Symbol(C.a, Decl(parameterPropertyInConstructor4.ts, 1, 16))
|
||||
>b : Symbol(b, Decl(parameterPropertyInConstructor4.ts, 1, 40))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
//// [tests/cases/compiler/parameterPropertyInConstructor4.ts] ////
|
||||
|
||||
=== parameterPropertyInConstructor4.ts ===
|
||||
export class C {
|
||||
>C : C
|
||||
> : ^
|
||||
|
||||
constructor(public a: number[] = [], b: number) {
|
||||
>a : number[]
|
||||
> : ^^^^^^^^
|
||||
>[] : never[]
|
||||
> : ^^^^^^^
|
||||
>b : number
|
||||
> : ^^^^^^
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// @declaration: true
|
||||
// @strict: true
|
||||
|
||||
export class C {
|
||||
constructor(public a: number[] = [], b: number) {
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче