Skip to content
Open
56 changes: 35 additions & 21 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import {
ConstructorTypeNode,
ConstructSignatureDeclaration,
contains,
containsNonPublicProperties,
containsParseError,
ContextFlags,
copyEntries,
Expand Down Expand Up @@ -21429,16 +21430,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function getBestMatchIndexedAccessTypeOrUndefined(source: Type, target: Type, nameType: Type) {
const idx = getIndexedAccessTypeOrUndefined(target, nameType);
if (idx) {
return idx;
}
if (target.flags & TypeFlags.Union) {
const best = getBestMatchingType(source, target as UnionType);
const best = getBestMatchingType(source, target as UnionType, /*matchSingleOverlappy*/ false);
if (best) {
return getIndexedAccessTypeOrUndefined(best, nameType);
}
}
const idx = getIndexedAccessTypeOrUndefined(target, nameType);
if (idx) {
return idx;
}
}

function checkExpressionForMutableLocationWithContextualType(next: Expression, sourcePropType: Type) {
Expand Down Expand Up @@ -23089,8 +23090,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
if (reportErrors) {
// Elaborate only if we can find a best matching type in the target union
const bestMatchingType = getBestMatchingType(source, target, isRelatedTo);
// Elaborate only if we can find a best matching type in the target
const bestMatchingType = getBestMatchingType(source, target, /*matchSingleOverlappy*/ true, isRelatedTo);
if (bestMatchingType) {
isRelatedTo(source, bestMatchingType, RecursionFlags.Target, /*reportErrors*/ true, /*headMessage*/ undefined, intersectionState);
}
Expand Down Expand Up @@ -24845,12 +24846,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return getPropertiesOfType(type).filter(targetProp => containsMissingType(getTypeOfSymbol(targetProp)));
}

function getBestMatchingType(source: Type, target: UnionOrIntersectionType, isRelatedTo = compareTypesAssignable) {
function getBestMatchingType(source: Type, target: UnionOrIntersectionType, matchSingleOverlappy: boolean, isRelatedTo = compareTypesAssignable) {
return findMatchingDiscriminantType(source, target, isRelatedTo) ||
findMatchingTypeReferenceOrTypeAliasReference(source, target) ||
findBestTypeForObjectLiteral(source, target) ||
findBestTypeForInvokable(source, target) ||
findMostOverlappyType(source, target);
findMostOverlappyType(source, filterTypesForObjectLiteralMatch(source, target), /*matchSingle*/ matchSingleOverlappy);
}

function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: (readonly [() => Type, __String])[], related: (source: Type, target: Type) => boolean | Ternary) {
Expand Down Expand Up @@ -53410,10 +53410,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}

function findBestTypeForObjectLiteral(source: Type, unionTarget: UnionOrIntersectionType) {
if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && someType(unionTarget, isArrayLikeType)) {
return find(unionTarget.types, t => !isArrayLikeType(t));
function filterTypesForObjectLiteralMatch(source: Type, target: UnionOrIntersectionType) {
if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && target.flags & TypeFlags.Union) {
const filtered = filterType(target, t =>
!(t.flags & TypeFlags.Primitive) &&
!isArrayLikeType(t) &&
!typeHasCallOrConstructSignatures(t) &&
(everyContainedType(t, t => !t.symbol || !(t.symbol.flags & SymbolFlags.Class)) || !containsNonPublicProperties(getAugmentedPropertiesOfType(t))));
if (!(filtered.flags & TypeFlags.Never)) {
return filtered;
}
}
return target;
}

function findBestTypeForInvokable(source: Type, unionTarget: UnionOrIntersectionType) {
Expand All @@ -53425,31 +53433,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}

function findMostOverlappyType(source: Type, unionTarget: UnionOrIntersectionType) {
let bestMatch: Type | undefined;
function findMostOverlappyType(source: Type, target: Type, matchSingle: boolean) {
if (!(target.flags & TypeFlags.UnionOrIntersection)) {
return target;
}
let bestMatches: Type[] = [];
if (!(source.flags & (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive))) {
let matchingCount = 0;
for (const target of unionTarget.types) {
if (!(target.flags & (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive))) {
const overlap = getIntersectionType([getIndexType(source), getIndexType(target)]);
for (const type of (target as UnionOrIntersectionType).types) {
if (!(type.flags & (TypeFlags.Primitive | TypeFlags.InstantiablePrimitive))) {
const overlap = getIntersectionType([getIndexType(source), getIndexType(type)]);
if (overlap.flags & TypeFlags.Index) {
// perfect overlap of keys
return target;
return type;
}
else if (isUnitType(overlap) || overlap.flags & TypeFlags.Union) {
// We only want to account for literal types otherwise.
// If we have a union of index types, it seems likely that we
// needed to elaborate between two generic mapped types anyway.
const len = overlap.flags & TypeFlags.Union ? countWhere((overlap as UnionType).types, isUnitType) : 1;
if (len >= matchingCount) {
bestMatch = target;
if (len > matchingCount || matchSingle) {
bestMatches.length = 0;
}
bestMatches = append(bestMatches, type);
matchingCount = len;
}
}
}
}
}
return bestMatch;
return bestMatches.length ? getUnionType(bestMatches) : undefined;
}

function filterPrimitivesIfContainsNonPrimitive(type: UnionType) {
Expand Down
7 changes: 7 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12364,3 +12364,10 @@ function addEmitFlagsRecursively(node: Node, flag: EmitFlags, getChild: (n: Node
function getFirstChild(node: Node): Node | undefined {
return forEachChild(node, child => child);
}

/** @internal */
export function containsNonPublicProperties(props: Symbol[]): boolean {
return some(props, p =>
!!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier) ||
!!p.valueDeclaration && isNamedDeclaration(p.valueDeclaration) && isPrivateIdentifier(p.valueDeclaration.name));
}
Copy link
Preview

Copilot AI Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The complex boolean expression checking for private identifiers could be extracted into a separate helper function for better readability and reusability.

Suggested change
}
export function containsNonPublicProperties(props: Symbol[]): boolean {
return some(props, p =>
!!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier) ||
hasPrivateIdentifierName(p)
);
}
function hasPrivateIdentifierName(p: Symbol): boolean {
return !!p.valueDeclaration && isNamedDeclaration(p.valueDeclaration) && isPrivateIdentifier(p.valueDeclaration.name);
}

Copilot uses AI. Check for mistakes.

5 changes: 1 addition & 4 deletions src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
CompletionTriggerKind,
concatenate,
ConstructorDeclaration,
containsNonPublicProperties,
ContextFlags,
countWhere,
createModuleSpecifierResolutionHost,
Expand Down Expand Up @@ -5654,10 +5655,6 @@ function getApparentProperties(type: Type, node: ObjectLiteralExpression | JsxAt
|| memberType.isClass() && containsNonPublicProperties(memberType.getApparentProperties()))));
}

function containsNonPublicProperties(props: Symbol[]) {
return some(props, p => !!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier));
}

/**
* Gets all properties on a type, but if that type is a union of several types,
* excludes array-like types or callable/constructable types.
Expand Down
86 changes: 21 additions & 65 deletions tests/baselines/reference/bigintWithLib.errors.txt
Original file line number Diff line number Diff line change
@@ -1,41 +1,23 @@
bigintWithLib.ts(4,1): error TS2350: Only a void function can be called with the 'new' keyword.
bigintWithLib.ts(19,34): error TS2769: No overload matches this call.
bigintWithLib.ts(19,33): error TS2769: No overload matches this call.
The last overload gave the following error.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
bigintWithLib.ts(19,37): error TS2769: No overload matches this call.
The last overload gave the following error.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
bigintWithLib.ts(19,40): error TS2769: No overload matches this call.
The last overload gave the following error.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
Argument of type 'number[]' is not assignable to parameter of type 'ArrayBuffer | ArrayLike<bigint>'.
Type 'number[]' is not assignable to type 'ArrayLike<bigint>'.
'number' index signatures are incompatible.
Type 'number' is not assignable to type 'bigint'.
bigintWithLib.ts(24,13): error TS2540: Cannot assign to 'length' because it is a read-only property.
bigintWithLib.ts(31,36): error TS2769: No overload matches this call.
The last overload gave the following error.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
bigintWithLib.ts(31,39): error TS2769: No overload matches this call.
The last overload gave the following error.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
bigintWithLib.ts(31,42): error TS2769: No overload matches this call.
bigintWithLib.ts(31,35): error TS2769: No overload matches this call.
The last overload gave the following error.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
Type 'number' is not assignable to type 'bigint'.
Argument of type 'number[]' is not assignable to parameter of type 'ArrayBuffer | ArrayLike<bigint>'.
Type 'number[]' is not assignable to type 'ArrayLike<bigint>'.
'number' index signatures are incompatible.
Type 'number' is not assignable to type 'bigint'.
bigintWithLib.ts(36,13): error TS2540: Cannot assign to 'length' because it is a read-only property.
bigintWithLib.ts(43,25): error TS2345: Argument of type 'number' is not assignable to parameter of type 'bigint'.
bigintWithLib.ts(46,26): error TS2345: Argument of type 'number' is not assignable to parameter of type 'bigint'.


==== bigintWithLib.ts (11 errors) ====
==== bigintWithLib.ts (7 errors) ====
// Test BigInt functions
let bigintVal: bigint = BigInt(123);
bigintVal = BigInt("456");
Expand All @@ -57,26 +39,13 @@ bigintWithLib.ts(46,26): error TS2345: Argument of type 'number' is not assignab
bigIntArray = new BigInt64Array(10);
bigIntArray = new BigInt64Array([1n, 2n, 3n]);
bigIntArray = new BigInt64Array([1, 2, 3]); // should error
~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! related TS2771 lib.es2020.bigint.d.ts:--:--: The last overload is declared here.
~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! related TS2771 lib.es2020.bigint.d.ts:--:--: The last overload is declared here.
~
~~~~~~~~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Argument of type 'number[]' is not assignable to parameter of type 'ArrayBuffer | ArrayLike<bigint>'.
!!! error TS2769: Type 'number[]' is not assignable to type 'ArrayLike<bigint>'.
!!! error TS2769: 'number' index signatures are incompatible.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! related TS2771 lib.es2020.bigint.d.ts:--:--: The last overload is declared here.
bigIntArray = new BigInt64Array(new ArrayBuffer(80));
bigIntArray = new BigInt64Array(new ArrayBuffer(80), 8);
Expand All @@ -92,26 +61,13 @@ bigintWithLib.ts(46,26): error TS2345: Argument of type 'number' is not assignab
bigUintArray = new BigUint64Array(10);
bigUintArray = new BigUint64Array([1n, 2n, 3n]);
bigUintArray = new BigUint64Array([1, 2, 3]); // should error
~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! related TS2771 lib.es2020.bigint.d.ts:--:--: The last overload is declared here.
~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! related TS2771 lib.es2020.bigint.d.ts:--:--: The last overload is declared here.
~
~~~~~~~~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! error TS2769: Argument of type 'number[]' is not assignable to parameter of type 'ArrayBuffer | ArrayLike<bigint>'.
!!! error TS2769: Type 'number[]' is not assignable to type 'ArrayLike<bigint>'.
!!! error TS2769: 'number' index signatures are incompatible.
!!! error TS2769: Type 'number' is not assignable to type 'bigint'.
!!! related TS2771 lib.es2020.bigint.d.ts:--:--: The last overload is declared here.
bigUintArray = new BigUint64Array(new ArrayBuffer(80));
bigUintArray = new BigUint64Array(new ArrayBuffer(80), 8);
Expand Down
Loading
Loading