mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Add missing mapped type indexed access constraint (#47370)
* Type { [P in K]: E }[X] has constraint E with X substutited for P
* Add regression test
* Fix PragmaMap and ReadonlyPragmaMap declarations
* Explore additional constraint
* Revert previous change
* Add tests
This commit is contained in:
parent
852b1c2b73
commit
4d6dd119d5
@ -11749,6 +11749,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getConstraintFromIndexedAccess(type: IndexedAccessType) {
|
||||
if (isMappedTypeGenericIndexedAccess(type)) {
|
||||
// For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic,
|
||||
// we substitute an instantiation of E where P is replaced with X.
|
||||
return substituteIndexedMappedType(type.objectType as MappedType, type.indexType);
|
||||
}
|
||||
const indexConstraint = getSimplifiedTypeOrConstraint(type.indexType);
|
||||
if (indexConstraint && indexConstraint !== type.indexType) {
|
||||
const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint, type.accessFlags);
|
||||
@ -11962,6 +11967,11 @@ namespace ts {
|
||||
return constraint ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType;
|
||||
}
|
||||
if (t.flags & TypeFlags.IndexedAccess) {
|
||||
if (isMappedTypeGenericIndexedAccess(t)) {
|
||||
// For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic,
|
||||
// we substitute an instantiation of E where P is replaced with X.
|
||||
return getBaseConstraint(substituteIndexedMappedType((t as IndexedAccessType).objectType as MappedType, (t as IndexedAccessType).indexType));
|
||||
}
|
||||
const baseObjectType = getBaseConstraint((t as IndexedAccessType).objectType);
|
||||
const baseIndexType = getBaseConstraint((t as IndexedAccessType).indexType);
|
||||
const baseIndexedAccess = baseObjectType && baseIndexType && getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, (t as IndexedAccessType).accessFlags);
|
||||
@ -12055,13 +12065,7 @@ namespace ts {
|
||||
* type itself.
|
||||
*/
|
||||
function getApparentType(type: Type): Type {
|
||||
// We obtain the base constraint for all instantiable types, except indexed access types of the form
|
||||
// { [P in K]: E }[X], where K is non-generic and X is generic. For those types, we instead substitute an
|
||||
// instantiation of E where P is replaced with X. We do this because getBaseConstraintOfType directly
|
||||
// lowers to an instantiation where X's constraint is substituted for X, which isn't always desirable.
|
||||
const t = !(type.flags & TypeFlags.Instantiable) ? type :
|
||||
isMappedTypeGenericIndexedAccess(type) ? substituteIndexedMappedType((type as IndexedAccessType).objectType as MappedType, (type as IndexedAccessType).indexType) :
|
||||
getBaseConstraintOfType(type) || unknownType;
|
||||
const t = !(type.flags & TypeFlags.Instantiable) ? type : getBaseConstraintOfType(type) || unknownType;
|
||||
return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) :
|
||||
t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType) :
|
||||
t.flags & TypeFlags.StringLike ? globalStringType :
|
||||
@ -19220,6 +19224,17 @@ namespace ts {
|
||||
resetErrorInfo(saveErrorInfo);
|
||||
return result;
|
||||
}
|
||||
if (isMappedTypeGenericIndexedAccess(source)) {
|
||||
// For an indexed access type { [P in K]: E}[X], above we have already explored an instantiation of E with X
|
||||
// substituted for P. We also want to explore type { [P in K]: E }[C], where C is the constraint of X.
|
||||
const indexConstraint = getConstraintOfType((source as IndexedAccessType).indexType);
|
||||
if (indexConstraint) {
|
||||
if (result = isRelatedTo(getIndexedAccessType((source as IndexedAccessType).objectType, indexConstraint), target, RecursionFlags.Source, reportErrors)) {
|
||||
resetErrorInfo(saveErrorInfo);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (source.flags & TypeFlags.Index) {
|
||||
|
||||
@ -157,6 +157,30 @@ function ff1() {
|
||||
const x1 = apply('sum', 1, 2)
|
||||
const x2 = apply('concat', 'str1', 'str2', 'str3' )
|
||||
}
|
||||
|
||||
// Repro from #47368
|
||||
|
||||
type ArgMap = { a: number, b: string };
|
||||
type Func<K extends keyof ArgMap> = (x: ArgMap[K]) => void;
|
||||
type Funcs = { [K in keyof ArgMap]: Func<K> };
|
||||
|
||||
function f1<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
funcs[key](arg);
|
||||
}
|
||||
|
||||
function f2<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
const func = funcs[key]; // Type Funcs[K]
|
||||
func(arg);
|
||||
}
|
||||
|
||||
function f3<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
const func: Func<K> = funcs[key]; // Error, Funcs[K] not assignable to Func<K>
|
||||
func(arg);
|
||||
}
|
||||
|
||||
function f4<K extends keyof ArgMap>(x: Funcs[keyof ArgMap], y: Funcs[K]) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
|
||||
//// [correlatedUnions.js]
|
||||
@ -244,6 +268,20 @@ function ff1() {
|
||||
var x1 = apply('sum', 1, 2);
|
||||
var x2 = apply('concat', 'str1', 'str2', 'str3');
|
||||
}
|
||||
function f1(funcs, key, arg) {
|
||||
funcs[key](arg);
|
||||
}
|
||||
function f2(funcs, key, arg) {
|
||||
var func = funcs[key]; // Type Funcs[K]
|
||||
func(arg);
|
||||
}
|
||||
function f3(funcs, key, arg) {
|
||||
var func = funcs[key]; // Error, Funcs[K] not assignable to Func<K>
|
||||
func(arg);
|
||||
}
|
||||
function f4(x, y) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
|
||||
//// [correlatedUnions.d.ts]
|
||||
@ -348,3 +386,15 @@ declare const scrollEvent: {
|
||||
readonly callback: (ev: Event) => void;
|
||||
};
|
||||
declare function ff1(): void;
|
||||
declare type ArgMap = {
|
||||
a: number;
|
||||
b: string;
|
||||
};
|
||||
declare type Func<K extends keyof ArgMap> = (x: ArgMap[K]) => void;
|
||||
declare type Funcs = {
|
||||
[K in keyof ArgMap]: Func<K>;
|
||||
};
|
||||
declare function f1<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]): void;
|
||||
declare function f2<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]): void;
|
||||
declare function f3<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]): void;
|
||||
declare function f4<K extends keyof ArgMap>(x: Funcs[keyof ArgMap], y: Funcs[K]): void;
|
||||
|
||||
@ -573,3 +573,105 @@ function ff1() {
|
||||
>apply : Symbol(apply, Decl(correlatedUnions.ts, 150, 5))
|
||||
}
|
||||
|
||||
// Repro from #47368
|
||||
|
||||
type ArgMap = { a: number, b: string };
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>a : Symbol(a, Decl(correlatedUnions.ts, 161, 15))
|
||||
>b : Symbol(b, Decl(correlatedUnions.ts, 161, 26))
|
||||
|
||||
type Func<K extends keyof ArgMap> = (x: ArgMap[K]) => void;
|
||||
>Func : Symbol(Func, Decl(correlatedUnions.ts, 161, 39))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 162, 10))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>x : Symbol(x, Decl(correlatedUnions.ts, 162, 37))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 162, 10))
|
||||
|
||||
type Funcs = { [K in keyof ArgMap]: Func<K> };
|
||||
>Funcs : Symbol(Funcs, Decl(correlatedUnions.ts, 162, 59))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 163, 16))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>Func : Symbol(Func, Decl(correlatedUnions.ts, 161, 39))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 163, 16))
|
||||
|
||||
function f1<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
>f1 : Symbol(f1, Decl(correlatedUnions.ts, 163, 46))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 165, 12))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>funcs : Symbol(funcs, Decl(correlatedUnions.ts, 165, 36))
|
||||
>Funcs : Symbol(Funcs, Decl(correlatedUnions.ts, 162, 59))
|
||||
>key : Symbol(key, Decl(correlatedUnions.ts, 165, 49))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 165, 12))
|
||||
>arg : Symbol(arg, Decl(correlatedUnions.ts, 165, 57))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 165, 12))
|
||||
|
||||
funcs[key](arg);
|
||||
>funcs : Symbol(funcs, Decl(correlatedUnions.ts, 165, 36))
|
||||
>key : Symbol(key, Decl(correlatedUnions.ts, 165, 49))
|
||||
>arg : Symbol(arg, Decl(correlatedUnions.ts, 165, 57))
|
||||
}
|
||||
|
||||
function f2<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
>f2 : Symbol(f2, Decl(correlatedUnions.ts, 167, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 169, 12))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>funcs : Symbol(funcs, Decl(correlatedUnions.ts, 169, 36))
|
||||
>Funcs : Symbol(Funcs, Decl(correlatedUnions.ts, 162, 59))
|
||||
>key : Symbol(key, Decl(correlatedUnions.ts, 169, 49))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 169, 12))
|
||||
>arg : Symbol(arg, Decl(correlatedUnions.ts, 169, 57))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 169, 12))
|
||||
|
||||
const func = funcs[key]; // Type Funcs[K]
|
||||
>func : Symbol(func, Decl(correlatedUnions.ts, 170, 9))
|
||||
>funcs : Symbol(funcs, Decl(correlatedUnions.ts, 169, 36))
|
||||
>key : Symbol(key, Decl(correlatedUnions.ts, 169, 49))
|
||||
|
||||
func(arg);
|
||||
>func : Symbol(func, Decl(correlatedUnions.ts, 170, 9))
|
||||
>arg : Symbol(arg, Decl(correlatedUnions.ts, 169, 57))
|
||||
}
|
||||
|
||||
function f3<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
>f3 : Symbol(f3, Decl(correlatedUnions.ts, 172, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 174, 12))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>funcs : Symbol(funcs, Decl(correlatedUnions.ts, 174, 36))
|
||||
>Funcs : Symbol(Funcs, Decl(correlatedUnions.ts, 162, 59))
|
||||
>key : Symbol(key, Decl(correlatedUnions.ts, 174, 49))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 174, 12))
|
||||
>arg : Symbol(arg, Decl(correlatedUnions.ts, 174, 57))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 174, 12))
|
||||
|
||||
const func: Func<K> = funcs[key]; // Error, Funcs[K] not assignable to Func<K>
|
||||
>func : Symbol(func, Decl(correlatedUnions.ts, 175, 9))
|
||||
>Func : Symbol(Func, Decl(correlatedUnions.ts, 161, 39))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 174, 12))
|
||||
>funcs : Symbol(funcs, Decl(correlatedUnions.ts, 174, 36))
|
||||
>key : Symbol(key, Decl(correlatedUnions.ts, 174, 49))
|
||||
|
||||
func(arg);
|
||||
>func : Symbol(func, Decl(correlatedUnions.ts, 175, 9))
|
||||
>arg : Symbol(arg, Decl(correlatedUnions.ts, 174, 57))
|
||||
}
|
||||
|
||||
function f4<K extends keyof ArgMap>(x: Funcs[keyof ArgMap], y: Funcs[K]) {
|
||||
>f4 : Symbol(f4, Decl(correlatedUnions.ts, 177, 1))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 179, 12))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>x : Symbol(x, Decl(correlatedUnions.ts, 179, 36))
|
||||
>Funcs : Symbol(Funcs, Decl(correlatedUnions.ts, 162, 59))
|
||||
>ArgMap : Symbol(ArgMap, Decl(correlatedUnions.ts, 157, 1))
|
||||
>y : Symbol(y, Decl(correlatedUnions.ts, 179, 59))
|
||||
>Funcs : Symbol(Funcs, Decl(correlatedUnions.ts, 162, 59))
|
||||
>K : Symbol(K, Decl(correlatedUnions.ts, 179, 12))
|
||||
|
||||
x = y;
|
||||
>x : Symbol(x, Decl(correlatedUnions.ts, 179, 36))
|
||||
>y : Symbol(y, Decl(correlatedUnions.ts, 179, 59))
|
||||
}
|
||||
|
||||
|
||||
@ -549,3 +549,78 @@ function ff1() {
|
||||
>'str3' : "str3"
|
||||
}
|
||||
|
||||
// Repro from #47368
|
||||
|
||||
type ArgMap = { a: number, b: string };
|
||||
>ArgMap : ArgMap
|
||||
>a : number
|
||||
>b : string
|
||||
|
||||
type Func<K extends keyof ArgMap> = (x: ArgMap[K]) => void;
|
||||
>Func : Func<K>
|
||||
>x : ArgMap[K]
|
||||
|
||||
type Funcs = { [K in keyof ArgMap]: Func<K> };
|
||||
>Funcs : Funcs
|
||||
|
||||
function f1<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
>f1 : <K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) => void
|
||||
>funcs : Funcs
|
||||
>key : K
|
||||
>arg : ArgMap[K]
|
||||
|
||||
funcs[key](arg);
|
||||
>funcs[key](arg) : void
|
||||
>funcs[key] : Funcs[K]
|
||||
>funcs : Funcs
|
||||
>key : K
|
||||
>arg : ArgMap[K]
|
||||
}
|
||||
|
||||
function f2<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
>f2 : <K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) => void
|
||||
>funcs : Funcs
|
||||
>key : K
|
||||
>arg : ArgMap[K]
|
||||
|
||||
const func = funcs[key]; // Type Funcs[K]
|
||||
>func : Funcs[K]
|
||||
>funcs[key] : Funcs[K]
|
||||
>funcs : Funcs
|
||||
>key : K
|
||||
|
||||
func(arg);
|
||||
>func(arg) : void
|
||||
>func : Funcs[K]
|
||||
>arg : ArgMap[K]
|
||||
}
|
||||
|
||||
function f3<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
>f3 : <K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) => void
|
||||
>funcs : Funcs
|
||||
>key : K
|
||||
>arg : ArgMap[K]
|
||||
|
||||
const func: Func<K> = funcs[key]; // Error, Funcs[K] not assignable to Func<K>
|
||||
>func : Func<K>
|
||||
>funcs[key] : Funcs[K]
|
||||
>funcs : Funcs
|
||||
>key : K
|
||||
|
||||
func(arg);
|
||||
>func(arg) : void
|
||||
>func : Func<K>
|
||||
>arg : ArgMap[K]
|
||||
}
|
||||
|
||||
function f4<K extends keyof ArgMap>(x: Funcs[keyof ArgMap], y: Funcs[K]) {
|
||||
>f4 : <K extends keyof ArgMap>(x: Funcs[keyof ArgMap], y: Funcs[K]) => void
|
||||
>x : Func<"b"> | Func<"a">
|
||||
>y : Funcs[K]
|
||||
|
||||
x = y;
|
||||
>x = y : Funcs[K]
|
||||
>x : Func<"b"> | Func<"a">
|
||||
>y : Funcs[K]
|
||||
}
|
||||
|
||||
|
||||
@ -159,3 +159,27 @@ function ff1() {
|
||||
const x1 = apply('sum', 1, 2)
|
||||
const x2 = apply('concat', 'str1', 'str2', 'str3' )
|
||||
}
|
||||
|
||||
// Repro from #47368
|
||||
|
||||
type ArgMap = { a: number, b: string };
|
||||
type Func<K extends keyof ArgMap> = (x: ArgMap[K]) => void;
|
||||
type Funcs = { [K in keyof ArgMap]: Func<K> };
|
||||
|
||||
function f1<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
funcs[key](arg);
|
||||
}
|
||||
|
||||
function f2<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
const func = funcs[key]; // Type Funcs[K]
|
||||
func(arg);
|
||||
}
|
||||
|
||||
function f3<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
|
||||
const func: Func<K> = funcs[key]; // Error, Funcs[K] not assignable to Func<K>
|
||||
func(arg);
|
||||
}
|
||||
|
||||
function f4<K extends keyof ArgMap>(x: Funcs[keyof ArgMap], y: Funcs[K]) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user