Merge pull request #26698 from Microsoft/indexedAccessConstraints

Improve indexed access type relations
This commit is contained in:
Anders Hejlsberg
2018-08-27 18:14:43 -07:00
committed by GitHub
5 changed files with 149 additions and 13 deletions

View File

@@ -6905,10 +6905,15 @@ namespace ts {
}
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
const objectType = getBaseConstraintOfType(type.objectType) || type.objectType;
const indexType = getBaseConstraintOfType(type.indexType) || type.indexType;
const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType, /*accessNode*/ undefined, errorType) : undefined;
return constraint && constraint !== errorType ? constraint : undefined;
const objectType = getConstraintOfType(type.objectType) || type.objectType;
if (objectType !== type.objectType) {
const constraint = getIndexedAccessType(objectType, type.indexType, /*accessNode*/ undefined, errorType);
if (constraint && constraint !== errorType) {
return constraint;
}
}
const baseConstraint = getBaseConstraintOfType(type);
return baseConstraint && baseConstraint !== type ? baseConstraint : undefined;
}
function getDefaultConstraintOfConditionalType(type: ConditionalType) {
@@ -7080,9 +7085,6 @@ namespace ts {
if (t.flags & TypeFlags.Substitution) {
return getBaseConstraint((<SubstitutionType>t).substitute);
}
if (isGenericMappedType(t)) {
return emptyObjectType;
}
return t;
}
}
@@ -11648,12 +11650,13 @@ namespace ts {
}
}
else if (target.flags & TypeFlags.IndexedAccess) {
// A type S is related to a type T[K] if S is related to C, where C is the
// constraint of T[K]
const constraint = getConstraintForRelation(target);
if (constraint) {
if (result = isRelatedTo(source, constraint, reportErrors)) {
return result;
// A type S is related to a type T[K] if S is related to C, where C is the base constraint of T[K]
if (relation !== identityRelation) {
const constraint = getBaseConstraintOfType(target);
if (constraint && constraint !== target) {
if (result = isRelatedTo(source, constraint, reportErrors)) {
return result;
}
}
}
}

View File

@@ -649,6 +649,20 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
const d: Dict<T> = dd[k1];
return d[k2];
}
// Repro from #26409
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
{
const s: string = t[k];
t.cool;
};
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
{
const s: string = t[k];
t.cool;
};
//// [keyofAndIndexedAccess.js]
@@ -1078,6 +1092,15 @@ function ff2(dd, k1, k2) {
var d = dd[k1];
return d[k2];
}
// Repro from #26409
var cf1 = function (t, k) {
var s = t[k];
t.cool;
};
var cf2 = function (t, k) {
var s = t[k];
t.cool;
};
//// [keyofAndIndexedAccess.d.ts]
@@ -1413,3 +1436,7 @@ declare type DictDict<V extends string, T extends string> = {
};
declare function ff1<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2: T): number;
declare function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2: T): number;
declare const cf1: <T extends { [P in K]: string; } & {
cool: string;
}, K extends keyof T>(t: T, k: K) => void;
declare const cf2: <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) => void;

View File

@@ -2319,3 +2319,54 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
>k2 : Symbol(k2, Decl(keyofAndIndexedAccess.ts, 646, 75))
}
// Repro from #26409
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
>cf1 : Symbol(cf1, Decl(keyofAndIndexedAccess.ts, 653, 5))
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13))
>P : Symbol(P, Decl(keyofAndIndexedAccess.ts, 653, 26))
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65))
>cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48))
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65))
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13))
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85))
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13))
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 653, 90))
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65))
{
const s: string = t[k];
>s : Symbol(s, Decl(keyofAndIndexedAccess.ts, 655, 9))
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85))
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 653, 90))
t.cool;
>t.cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48))
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85))
>cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48))
};
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
>cf2 : Symbol(cf2, Decl(keyofAndIndexedAccess.ts, 659, 5))
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13))
>P : Symbol(P, Decl(keyofAndIndexedAccess.ts, 659, 26))
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54))
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54))
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13))
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74))
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13))
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 659, 79))
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54))
{
const s: string = t[k];
>s : Symbol(s, Decl(keyofAndIndexedAccess.ts, 661, 9))
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74))
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 659, 79))
t.cool;
>t.cool : Symbol(cool)
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74))
>cool : Symbol(cool)
};

View File

@@ -2184,3 +2184,44 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
>k2 : T
}
// Repro from #26409
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
>cf1 : <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) => void
><T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>{ const s: string = t[k]; t.cool;} : <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) => void
>cool : string
>t : T
>k : K
{
const s: string = t[k];
>s : string
>t[k] : T[K]
>t : T
>k : K
t.cool;
>t.cool : string
>t : T
>cool : string
};
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
>cf2 : <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) => void
><T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>{ const s: string = t[k]; t.cool;} : <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) => void
>t : T
>k : K
{
const s: string = t[k];
>s : string
>t[k] : T[K]
>t : T
>k : K
t.cool;
>t.cool : string
>t : T
>cool : string
};

View File

@@ -651,3 +651,17 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
const d: Dict<T> = dd[k1];
return d[k2];
}
// Repro from #26409
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
{
const s: string = t[k];
t.cool;
};
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
{
const s: string = t[k];
t.cool;
};