Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16173,7 +16173,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function getSubstitutionType(baseType: Type, constraint: Type) {
return constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || baseType.flags & TypeFlags.Any ?
return constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || baseType.flags & TypeFlags.Any || !isGenericType(constraint) && !isGenericType(baseType) && isTypeAssignableTo(baseType, constraint) ?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

alternatively, substitution types could get some improved handling in getPropertyTypeForIndexType

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I think I'd prefer getPropertyNameFromIndex + getPropertyTypeForIndexType being updated to handle substitutions - the more places we recognize them as transparently their original type (if the substituted version isn't useful), the better, since it makes it easier on us to broaden the scope of how we use substitution types to support other features.

As far as this approach goes... instantiateTypeWorker has similar logic to this - honestly, a lot of that logic should probably get moved into here, so it happens on initial construction and instantiation, rather than just instantiation.

Copy link
Member

Choose a reason for hiding this comment

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

I agree, the right approach is to erase them where needed. Omitting the substitution type just because the constraint is assignable isn't right and will definitely have adverse effects as the constraint may be a more specific type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I pushed out the requested change. I decided to use a similar approach of unwrapping the substation type early in getPropertyTypeForIndexType like it was done in #58292

baseType :
getOrCreateSubstitutionType(baseType, constraint);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [tests/cases/compiler/nonGenericIndexedAccessInConditionalTrueBranch1.ts] ////

=== nonGenericIndexedAccessInConditionalTrueBranch1.ts ===
// https://github.com/microsoft/TypeScript/issues/57109

type A = {
>A : Symbol(A, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 0, 0))

k: symbol;
>k : Symbol(k, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 2, 10))

};

type B = "k" extends keyof A ? A["k"] : never;
>B : Symbol(B, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 4, 2))
>A : Symbol(A, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 0, 0))
>A : Symbol(A, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 0, 0))

type C = {
>C : Symbol(C, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 6, 46))

k: symbol;
>k : Symbol(k, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 8, 10))

other: boolean;
>other : Symbol(other, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 9, 12))

};

type D = "k" extends keyof C ? C["k"] : never;
>D : Symbol(D, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 11, 2))
>C : Symbol(C, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 6, 46))
>C : Symbol(C, Decl(nonGenericIndexedAccessInConditionalTrueBranch1.ts, 6, 46))

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//// [tests/cases/compiler/nonGenericIndexedAccessInConditionalTrueBranch1.ts] ////

=== nonGenericIndexedAccessInConditionalTrueBranch1.ts ===
// https://github.com/microsoft/TypeScript/issues/57109

type A = {
>A : { k: symbol; }

k: symbol;
>k : symbol

};

type B = "k" extends keyof A ? A["k"] : never;
>B : symbol

type C = {
>C : { k: symbol; other: boolean; }

k: symbol;
>k : symbol

other: boolean;
>other : boolean

};

type D = "k" extends keyof C ? C["k"] : never;
>D : symbol

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @strict: true
// @noEmit: true

// https://github.com/microsoft/TypeScript/issues/57109

type A = {
k: symbol;
};

type B = "k" extends keyof A ? A["k"] : never;

type C = {
k: symbol;
other: boolean;
};

type D = "k" extends keyof C ? C["k"] : never;