Skip to content

Commit

Permalink
Merge pull request #26698 from Microsoft/indexedAccessConstraints
Browse files Browse the repository at this point in the history
Improve indexed access type relations
  • Loading branch information
ahejlsberg authored Aug 28, 2018
2 parents 7223945 + d369cec commit bd40583
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 13 deletions.
29 changes: 16 additions & 13 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -7080,9 +7085,6 @@ namespace ts {
if (t.flags & TypeFlags.Substitution) {
return getBaseConstraint((<SubstitutionType>t).substitute);
}
if (isGenericMappedType(t)) {
return emptyObjectType;
}
return t;
}
}
Expand Down Expand Up @@ -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;
}
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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;
51 changes: 51 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -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)

};

41 changes: 41 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess.types
Original file line number Diff line number Diff line change
Expand Up @@ -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

};

14 changes: 14 additions & 0 deletions tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

0 comments on commit bd40583

Please sign in to comment.