Merge pull request #17870 from Microsoft/fix-getConstraintOfIndexedAccess
Fix getConstraintOfIndexedAccess
This commit is contained in:
commit
439cdca52f
|
@ -5911,7 +5911,13 @@ namespace ts {
|
|||
return transformed;
|
||||
}
|
||||
const baseObjectType = getBaseConstraintOfType(type.objectType);
|
||||
const baseIndexType = getBaseConstraintOfType(type.indexType);
|
||||
const keepTypeParameterForMappedType = baseObjectType && getObjectFlags(baseObjectType) & ObjectFlags.Mapped && type.indexType.flags & TypeFlags.TypeParameter;
|
||||
const baseIndexType = !keepTypeParameterForMappedType && getBaseConstraintOfType(type.indexType);
|
||||
if (baseObjectType && baseIndexType === stringType && !getIndexInfoOfType(baseObjectType, IndexKind.String)) {
|
||||
// getIndexedAccessType returns `any` for X[string] where X doesn't have an index signature.
|
||||
// instead, return undefined so that the indexed access check fails
|
||||
return undefined;
|
||||
}
|
||||
return baseObjectType || baseIndexType ? getIndexedAccessType(baseObjectType || type.objectType, baseIndexType || type.indexType) : undefined;
|
||||
}
|
||||
|
||||
|
@ -5961,8 +5967,9 @@ namespace ts {
|
|||
function computeBaseConstraint(t: Type): Type {
|
||||
if (t.flags & TypeFlags.TypeParameter) {
|
||||
const constraint = getConstraintFromTypeParameter(<TypeParameter>t);
|
||||
return (<TypeParameter>t).isThisType ? constraint :
|
||||
constraint ? getBaseConstraint(constraint) : undefined;
|
||||
return (t as TypeParameter).isThisType || !constraint ?
|
||||
constraint :
|
||||
getBaseConstraint(constraint);
|
||||
}
|
||||
if (t.flags & TypeFlags.UnionOrIntersection) {
|
||||
const types = (<UnionOrIntersectionType>t).types;
|
||||
|
@ -5990,9 +5997,6 @@ namespace ts {
|
|||
const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined;
|
||||
return baseIndexedAccess && baseIndexedAccess !== unknownType ? getBaseConstraint(baseIndexedAccess) : undefined;
|
||||
}
|
||||
if (isGenericMappedType(t)) {
|
||||
return emptyObjectType;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
@ -9289,7 +9293,7 @@ namespace ts {
|
|||
}
|
||||
else if (target.flags & TypeFlags.IndexedAccess) {
|
||||
// A type S is related to a type T[K] if S is related to A[K], where K is string-like and
|
||||
// A is the apparent type of S.
|
||||
// A is the apparent type of T.
|
||||
const constraint = getConstraintOfType(<IndexedAccessType>target);
|
||||
if (constraint) {
|
||||
if (result = isRelatedTo(source, constraint, reportErrors)) {
|
||||
|
|
|
@ -718,7 +718,7 @@ namespace ts {
|
|||
export function sum<T extends Record<K, number>, K extends string>(array: T[], prop: K): number {
|
||||
let result = 0;
|
||||
for (const v of array) {
|
||||
// Note: we need the following type assertion because of GH #17069
|
||||
// TODO: Remove the following type assertion once the fix for #17069 is merged
|
||||
result += v[prop] as number;
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
//// [additionOperatorWithConstrainedTypeParameter.ts]
|
||||
// test for #17069
|
||||
function sum<T extends Record<K, number>, K extends string>(n: number, v: T, k: K) {
|
||||
n = n + v[k];
|
||||
n += v[k]; // += should work the same way
|
||||
}
|
||||
function realSum<T extends Record<K, number>, K extends string>(n: number, vs: T[], k: K) {
|
||||
for (const v of vs) {
|
||||
n = n + v[k];
|
||||
n += v[k];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [additionOperatorWithConstrainedTypeParameter.js]
|
||||
// test for #17069
|
||||
function sum(n, v, k) {
|
||||
n = n + v[k];
|
||||
n += v[k]; // += should work the same way
|
||||
}
|
||||
function realSum(n, vs, k) {
|
||||
for (var _i = 0, vs_1 = vs; _i < vs_1.length; _i++) {
|
||||
var v = vs_1[_i];
|
||||
n = n + v[k];
|
||||
n += v[k];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
=== tests/cases/conformance/expressions/binaryOperators/additionOperator/additionOperatorWithConstrainedTypeParameter.ts ===
|
||||
// test for #17069
|
||||
function sum<T extends Record<K, number>, K extends string>(n: number, v: T, k: K) {
|
||||
>sum : Symbol(sum, Decl(additionOperatorWithConstrainedTypeParameter.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 13))
|
||||
>Record : Symbol(Record, Decl(lib.d.ts, --, --))
|
||||
>K : Symbol(K, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 41))
|
||||
>K : Symbol(K, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 41))
|
||||
>n : Symbol(n, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 60))
|
||||
>v : Symbol(v, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 70))
|
||||
>T : Symbol(T, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 13))
|
||||
>k : Symbol(k, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 76))
|
||||
>K : Symbol(K, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 41))
|
||||
|
||||
n = n + v[k];
|
||||
>n : Symbol(n, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 60))
|
||||
>n : Symbol(n, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 60))
|
||||
>v : Symbol(v, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 70))
|
||||
>k : Symbol(k, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 76))
|
||||
|
||||
n += v[k]; // += should work the same way
|
||||
>n : Symbol(n, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 60))
|
||||
>v : Symbol(v, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 70))
|
||||
>k : Symbol(k, Decl(additionOperatorWithConstrainedTypeParameter.ts, 1, 76))
|
||||
}
|
||||
function realSum<T extends Record<K, number>, K extends string>(n: number, vs: T[], k: K) {
|
||||
>realSum : Symbol(realSum, Decl(additionOperatorWithConstrainedTypeParameter.ts, 4, 1))
|
||||
>T : Symbol(T, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 17))
|
||||
>Record : Symbol(Record, Decl(lib.d.ts, --, --))
|
||||
>K : Symbol(K, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 45))
|
||||
>K : Symbol(K, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 45))
|
||||
>n : Symbol(n, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 64))
|
||||
>vs : Symbol(vs, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 74))
|
||||
>T : Symbol(T, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 17))
|
||||
>k : Symbol(k, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 83))
|
||||
>K : Symbol(K, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 45))
|
||||
|
||||
for (const v of vs) {
|
||||
>v : Symbol(v, Decl(additionOperatorWithConstrainedTypeParameter.ts, 6, 14))
|
||||
>vs : Symbol(vs, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 74))
|
||||
|
||||
n = n + v[k];
|
||||
>n : Symbol(n, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 64))
|
||||
>n : Symbol(n, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 64))
|
||||
>v : Symbol(v, Decl(additionOperatorWithConstrainedTypeParameter.ts, 6, 14))
|
||||
>k : Symbol(k, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 83))
|
||||
|
||||
n += v[k];
|
||||
>n : Symbol(n, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 64))
|
||||
>v : Symbol(v, Decl(additionOperatorWithConstrainedTypeParameter.ts, 6, 14))
|
||||
>k : Symbol(k, Decl(additionOperatorWithConstrainedTypeParameter.ts, 5, 83))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
=== tests/cases/conformance/expressions/binaryOperators/additionOperator/additionOperatorWithConstrainedTypeParameter.ts ===
|
||||
// test for #17069
|
||||
function sum<T extends Record<K, number>, K extends string>(n: number, v: T, k: K) {
|
||||
>sum : <T extends Record<K, number>, K extends string>(n: number, v: T, k: K) => void
|
||||
>T : T
|
||||
>Record : Record<K, T>
|
||||
>K : K
|
||||
>K : K
|
||||
>n : number
|
||||
>v : T
|
||||
>T : T
|
||||
>k : K
|
||||
>K : K
|
||||
|
||||
n = n + v[k];
|
||||
>n = n + v[k] : number
|
||||
>n : number
|
||||
>n + v[k] : number
|
||||
>n : number
|
||||
>v[k] : T[K]
|
||||
>v : T
|
||||
>k : K
|
||||
|
||||
n += v[k]; // += should work the same way
|
||||
>n += v[k] : number
|
||||
>n : number
|
||||
>v[k] : T[K]
|
||||
>v : T
|
||||
>k : K
|
||||
}
|
||||
function realSum<T extends Record<K, number>, K extends string>(n: number, vs: T[], k: K) {
|
||||
>realSum : <T extends Record<K, number>, K extends string>(n: number, vs: T[], k: K) => void
|
||||
>T : T
|
||||
>Record : Record<K, T>
|
||||
>K : K
|
||||
>K : K
|
||||
>n : number
|
||||
>vs : T[]
|
||||
>T : T
|
||||
>k : K
|
||||
>K : K
|
||||
|
||||
for (const v of vs) {
|
||||
>v : T
|
||||
>vs : T[]
|
||||
|
||||
n = n + v[k];
|
||||
>n = n + v[k] : number
|
||||
>n : number
|
||||
>n + v[k] : number
|
||||
>n : number
|
||||
>v[k] : T[K]
|
||||
>v : T
|
||||
>k : K
|
||||
|
||||
n += v[k];
|
||||
>n += v[k] : number
|
||||
>n : number
|
||||
>v[k] : T[K]
|
||||
>v : T
|
||||
>k : K
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(3,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(6,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(9,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(12,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(15,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(18,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(21,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(24,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(27,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(30,5): error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts (10 errors) ====
|
||||
// test for #15371
|
||||
function f<T extends object, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
}
|
||||
function g<T extends null, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
}
|
||||
function h<T extends undefined, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
}
|
||||
function i<T extends void, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
}
|
||||
function j<T extends never, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
}
|
||||
function k<T extends number, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
}
|
||||
function o<T extends string, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
}
|
||||
function l<T extends {}, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
}
|
||||
function m<T extends { a: number }, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
}
|
||||
function n<T extends { [s: string]: number }, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T[P]'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
//// [nonPrimitiveConstraintOfIndexAccessType.ts]
|
||||
// test for #15371
|
||||
function f<T extends object, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function g<T extends null, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function h<T extends undefined, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function i<T extends void, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function j<T extends never, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function k<T extends number, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function o<T extends string, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function l<T extends {}, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function m<T extends { a: number }, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function n<T extends { [s: string]: number }, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
|
||||
|
||||
//// [nonPrimitiveConstraintOfIndexAccessType.js]
|
||||
"use strict";
|
||||
// test for #15371
|
||||
function f(s, tp) {
|
||||
tp = s;
|
||||
}
|
||||
function g(s, tp) {
|
||||
tp = s;
|
||||
}
|
||||
function h(s, tp) {
|
||||
tp = s;
|
||||
}
|
||||
function i(s, tp) {
|
||||
tp = s;
|
||||
}
|
||||
function j(s, tp) {
|
||||
tp = s;
|
||||
}
|
||||
function k(s, tp) {
|
||||
tp = s;
|
||||
}
|
||||
function o(s, tp) {
|
||||
tp = s;
|
||||
}
|
||||
function l(s, tp) {
|
||||
tp = s;
|
||||
}
|
||||
function m(s, tp) {
|
||||
tp = s;
|
||||
}
|
||||
function n(s, tp) {
|
||||
tp = s;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// test for #17069
|
||||
function sum<T extends Record<K, number>, K extends string>(n: number, v: T, k: K) {
|
||||
n = n + v[k];
|
||||
n += v[k]; // += should work the same way
|
||||
}
|
||||
function realSum<T extends Record<K, number>, K extends string>(n: number, vs: T[], k: K) {
|
||||
for (const v of vs) {
|
||||
n = n + v[k];
|
||||
n += v[k];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// @strict: true
|
||||
// test for #15371
|
||||
function f<T extends object, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function g<T extends null, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function h<T extends undefined, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function i<T extends void, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function j<T extends never, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function k<T extends number, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function o<T extends string, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function l<T extends {}, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function m<T extends { a: number }, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
||||
function n<T extends { [s: string]: number }, P extends keyof T>(s: string, tp: T[P]): void {
|
||||
tp = s;
|
||||
}
|
Loading…
Reference in a new issue