Skip to content

Commit b8f6227

Browse files
authoredNov 18, 2016
Merge pull request #12368 from Microsoft/Port12351-3
Port #12351 to release-2.1
2 parents 30fde91 + a41746b commit b8f6227

File tree

7 files changed

+632
-33
lines changed

7 files changed

+632
-33
lines changed
 

‎src/compiler/checker.ts‎

Lines changed: 97 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ namespace ts {
120120
const intersectionTypes = createMap<IntersectionType>();
121121
const stringLiteralTypes = createMap<LiteralType>();
122122
const numericLiteralTypes = createMap<LiteralType>();
123+
const indexedAccessTypes = createMap<IndexedAccessType>();
123124
const evolvingArrayTypes: EvolvingArrayType[] = [];
124125

125126
const unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown");
@@ -4665,13 +4666,22 @@ namespace ts {
46654666
return type.resolvedApparentType;
46664667
}
46674668

4669+
/**
4670+
* The apparent type of an indexed access T[K] is the type of T's string index signature, if any.
4671+
*/
4672+
function getApparentTypeOfIndexedAccess(type: IndexedAccessType) {
4673+
return getIndexTypeOfType(getApparentType(type.objectType), IndexKind.String) || type;
4674+
}
4675+
46684676
/**
46694677
* For a type parameter, return the base constraint of the type parameter. For the string, number,
46704678
* boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
46714679
* type itself. Note that the apparent type of a union type is the union type itself.
46724680
*/
46734681
function getApparentType(type: Type): Type {
4674-
const t = type.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(<TypeParameter>type) : type;
4682+
const t = type.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(<TypeParameter>type) :
4683+
type.flags & TypeFlags.IndexedAccess ? getApparentTypeOfIndexedAccess(<IndexedAccessType>type) :
4684+
type;
46754685
return t.flags & TypeFlags.StringLike ? globalStringType :
46764686
t.flags & TypeFlags.NumberLike ? globalNumberType :
46774687
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
@@ -5907,6 +5917,7 @@ namespace ts {
59075917

59085918
function getIndexType(type: Type): Type {
59095919
return type.flags & TypeFlags.TypeParameter ? getIndexTypeForTypeParameter(<TypeParameter>type) :
5920+
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
59105921
type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringOrNumberType :
59115922
getIndexInfoOfType(type, IndexKind.Number) ? getUnionType([numberType, getLiteralTypeFromPropertyNames(type)]) :
59125923
getLiteralTypeFromPropertyNames(type);
@@ -5920,18 +5931,13 @@ namespace ts {
59205931
return links.resolvedType;
59215932
}
59225933

5923-
function createIndexedAccessType(objectType: Type, indexType: TypeParameter) {
5934+
function createIndexedAccessType(objectType: Type, indexType: Type) {
59245935
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
59255936
type.objectType = objectType;
59265937
type.indexType = indexType;
59275938
return type;
59285939
}
59295940

5930-
function getIndexedAccessTypeForTypeParameter(objectType: Type, indexType: TypeParameter) {
5931-
const indexedAccessTypes = indexType.resolvedIndexedAccessTypes || (indexType.resolvedIndexedAccessTypes = []);
5932-
return indexedAccessTypes[objectType.id] || (indexedAccessTypes[objectType.id] = createIndexedAccessType(objectType, indexType));
5933-
}
5934-
59355941
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
59365942
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
59375943
const propName = indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral) ?
@@ -5995,13 +6001,41 @@ namespace ts {
59956001
return unknownType;
59966002
}
59976003

6004+
function getIndexedAccessForMappedType(type: MappedType, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
6005+
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
6006+
if (accessExpression && isAssignmentTarget(accessExpression) && type.declaration.readonlyToken) {
6007+
error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(type));
6008+
return unknownType;
6009+
}
6010+
const mapper = createUnaryTypeMapper(getTypeParameterFromMappedType(type), indexType);
6011+
const templateMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper;
6012+
return addOptionality(instantiateType(getTemplateTypeFromMappedType(type), templateMapper), !!type.declaration.questionToken);
6013+
}
6014+
59986015
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
5999-
if (indexType.flags & TypeFlags.TypeParameter) {
6000-
if (accessNode && !isTypeAssignableTo(getConstraintOfTypeParameter(<TypeParameter>indexType) || emptyObjectType, getIndexType(objectType))) {
6001-
error(accessNode, Diagnostics.Type_0_is_not_constrained_to_keyof_1, typeToString(indexType), typeToString(objectType));
6002-
return unknownType;
6016+
if (indexType.flags & TypeFlags.TypeParameter ||
6017+
objectType.flags & TypeFlags.TypeParameter && indexType.flags & TypeFlags.Index ||
6018+
isGenericMappedType(objectType)) {
6019+
// If either the object type or the index type are type parameters, or if the object type is a mapped
6020+
// type with a generic constraint, we are performing a higher-order index access where we cannot
6021+
// meaningfully access the properties of the object type. In those cases, we first check that the
6022+
// index type is assignable to 'keyof T' for the object type.
6023+
if (accessNode) {
6024+
const keyType = indexType.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>indexType) || emptyObjectType : indexType;
6025+
if (!isTypeAssignableTo(keyType, getIndexType(objectType))) {
6026+
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType));
6027+
return unknownType;
6028+
}
6029+
}
6030+
// If the object type is a mapped type { [P in K]: E }, we instantiate E using a mapper that substitutes
6031+
// the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we construct the
6032+
// type Box<T[X]>.
6033+
if (isGenericMappedType(objectType)) {
6034+
return getIndexedAccessForMappedType(<MappedType>objectType, indexType, accessNode);
60036035
}
6004-
return getIndexedAccessTypeForTypeParameter(objectType, <TypeParameter>indexType);
6036+
// Otherwise we defer the operation by creating an indexed access type.
6037+
const id = objectType.id + "," + indexType.id;
6038+
return indexedAccessTypes[id] || (indexedAccessTypes[id] = createIndexedAccessType(objectType, indexType));
60056039
}
60066040
const apparentType = getApparentType(objectType);
60076041
if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Primitive)) {
@@ -6034,6 +6068,9 @@ namespace ts {
60346068
type.aliasSymbol = getAliasSymbolForTypeNode(node);
60356069
type.aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node);
60366070
links.resolvedType = type;
6071+
// Eagerly resolve the constraint type which forces an error if the constraint type circularly
6072+
// references itself through one or more type aliases.
6073+
getConstraintTypeFromMappedType(type);
60376074
}
60386075
return links.resolvedType;
60396076
}
@@ -7153,12 +7190,24 @@ namespace ts {
71537190
}
71547191

71557192
if (target.flags & TypeFlags.TypeParameter) {
7156-
// Given a type parameter K with a constraint keyof T, a type S is
7157-
// assignable to K if S is assignable to keyof T.
7158-
const constraint = getConstraintOfTypeParameter(<TypeParameter>target);
7159-
if (constraint && constraint.flags & TypeFlags.Index) {
7160-
if (result = isRelatedTo(source, constraint, reportErrors)) {
7161-
return result;
7193+
// A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P].
7194+
if (getObjectFlags(source) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(<MappedType>source) === getIndexType(target)) {
7195+
if (!(<MappedType>source).declaration.questionToken) {
7196+
const templateType = getTemplateTypeFromMappedType(<MappedType>source);
7197+
const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(<MappedType>source));
7198+
if (result = isRelatedTo(templateType, indexedAccessType, reportErrors)) {
7199+
return result;
7200+
}
7201+
}
7202+
}
7203+
else {
7204+
// Given a type parameter K with a constraint keyof T, a type S is
7205+
// assignable to K if S is assignable to keyof T.
7206+
const constraint = getConstraintOfTypeParameter(<TypeParameter>target);
7207+
if (constraint && constraint.flags & TypeFlags.Index) {
7208+
if (result = isRelatedTo(source, constraint, reportErrors)) {
7209+
return result;
7210+
}
71627211
}
71637212
}
71647213
}
@@ -7178,22 +7227,41 @@ namespace ts {
71787227
}
71797228
}
71807229
}
7230+
else if (target.flags & TypeFlags.IndexedAccess) {
7231+
// if we have indexed access types with identical index types, see if relationship holds for
7232+
// the two object types.
7233+
if (source.flags & TypeFlags.IndexedAccess && (<IndexedAccessType>source).indexType === (<IndexedAccessType>target).indexType) {
7234+
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
7235+
return result;
7236+
}
7237+
}
7238+
}
71817239

71827240
if (source.flags & TypeFlags.TypeParameter) {
7183-
let constraint = getConstraintOfTypeParameter(<TypeParameter>source);
7184-
7185-
if (!constraint || constraint.flags & TypeFlags.Any) {
7186-
constraint = emptyObjectType;
7241+
// A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X.
7242+
if (getObjectFlags(target) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(<MappedType>target) === getIndexType(source)) {
7243+
const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(<MappedType>target));
7244+
const templateType = getTemplateTypeFromMappedType(<MappedType>target);
7245+
if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) {
7246+
return result;
7247+
}
71877248
}
7249+
else {
7250+
let constraint = getConstraintOfTypeParameter(<TypeParameter>source);
71887251

7189-
// The constraint may need to be further instantiated with its 'this' type.
7190-
constraint = getTypeWithThisArgument(constraint, source);
7252+
if (!constraint || constraint.flags & TypeFlags.Any) {
7253+
constraint = emptyObjectType;
7254+
}
71917255

7192-
// Report constraint errors only if the constraint is not the empty object type
7193-
const reportConstraintErrors = reportErrors && constraint !== emptyObjectType;
7194-
if (result = isRelatedTo(constraint, target, reportConstraintErrors)) {
7195-
errorInfo = saveErrorInfo;
7196-
return result;
7256+
// The constraint may need to be further instantiated with its 'this' type.
7257+
constraint = getTypeWithThisArgument(constraint, source);
7258+
7259+
// Report constraint errors only if the constraint is not the empty object type
7260+
const reportConstraintErrors = reportErrors && constraint !== emptyObjectType;
7261+
if (result = isRelatedTo(constraint, target, reportConstraintErrors)) {
7262+
errorInfo = saveErrorInfo;
7263+
return result;
7264+
}
71977265
}
71987266
}
71997267
else {

‎src/compiler/diagnosticMessages.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1731,7 +1731,7 @@
17311731
"category": "Error",
17321732
"code": 2535
17331733
},
1734-
"Type '{0}' is not constrained to 'keyof {1}'.": {
1734+
"Type '{0}' cannot be used to index type '{1}'.": {
17351735
"category": "Error",
17361736
"code": 2536
17371737
},

‎src/compiler/types.ts‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,8 +2974,6 @@ namespace ts {
29742974
/* @internal */
29752975
resolvedIndexType: IndexType;
29762976
/* @internal */
2977-
resolvedIndexedAccessTypes: IndexedAccessType[];
2978-
/* @internal */
29792977
isThisType?: boolean;
29802978
}
29812979

@@ -2985,7 +2983,7 @@ namespace ts {
29852983

29862984
export interface IndexedAccessType extends Type {
29872985
objectType: Type;
2988-
indexType: TypeParameter;
2986+
indexType: Type;
29892987
}
29902988

29912989
export const enum SignatureKind {
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(12,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'.
2+
Type 'T' is not assignable to type 'U'.
3+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(17,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
4+
Type 'T' is not assignable to type 'U'.
5+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(21,5): error TS2536: Type 'keyof U' cannot be used to index type 'T'.
6+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(22,12): error TS2536: Type 'keyof U' cannot be used to index type 'T'.
7+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(26,5): error TS2536: Type 'K' cannot be used to index type 'T'.
8+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(27,12): error TS2536: Type 'K' cannot be used to index type 'T'.
9+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(31,5): error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'.
10+
Type 'undefined' is not assignable to type 'T[keyof T]'.
11+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(36,5): error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[K]'.
12+
Type 'undefined' is not assignable to type 'T[K]'.
13+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(41,5): error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'.
14+
Type 'undefined' is not assignable to type 'T[keyof T]'.
15+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(42,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'.
16+
Type 'T[keyof T]' is not assignable to type 'U[keyof T]'.
17+
Type 'T' is not assignable to type 'U'.
18+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(46,5): error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[K]'.
19+
Type 'undefined' is not assignable to type 'T[K]'.
20+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(47,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K] | undefined'.
21+
Type 'T[K]' is not assignable to type 'U[K]'.
22+
Type 'T' is not assignable to type 'U'.
23+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(52,5): error TS2542: Index signature in type 'Readonly<T>' only permits reading.
24+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(57,5): error TS2542: Index signature in type 'Readonly<T>' only permits reading.
25+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(62,5): error TS2542: Index signature in type 'Readonly<U>' only permits reading.
26+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(67,5): error TS2542: Index signature in type 'Readonly<U>' only permits reading.
27+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(71,5): error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
28+
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(76,5): error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
29+
30+
31+
==== tests/cases/conformance/types/mapped/mappedTypeRelationships.ts (18 errors) ====
32+
33+
function f1<T>(x: T, k: keyof T) {
34+
return x[k];
35+
}
36+
37+
function f2<T, K extends keyof T>(x: T, k: K) {
38+
return x[k];
39+
}
40+
41+
function f3<T, U extends T>(x: T, y: U, k: keyof T) {
42+
x[k] = y[k];
43+
y[k] = x[k]; // Error
44+
~~~~
45+
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'.
46+
!!! error TS2322: Type 'T' is not assignable to type 'U'.
47+
}
48+
49+
function f4<T, U extends T, K extends keyof T>(x: T, y: U, k: K) {
50+
x[k] = y[k];
51+
y[k] = x[k]; // Error
52+
~~~~
53+
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
54+
!!! error TS2322: Type 'T' is not assignable to type 'U'.
55+
}
56+
57+
function f5<T, U extends T>(x: T, y: U, k: keyof U) {
58+
x[k] = y[k]; // Error
59+
~~~~
60+
!!! error TS2536: Type 'keyof U' cannot be used to index type 'T'.
61+
y[k] = x[k]; // Error
62+
~~~~
63+
!!! error TS2536: Type 'keyof U' cannot be used to index type 'T'.
64+
}
65+
66+
function f6<T, U extends T, K extends keyof U>(x: T, y: U, k: K) {
67+
x[k] = y[k]; // Error
68+
~~~~
69+
!!! error TS2536: Type 'K' cannot be used to index type 'T'.
70+
y[k] = x[k]; // Error
71+
~~~~
72+
!!! error TS2536: Type 'K' cannot be used to index type 'T'.
73+
}
74+
75+
function f10<T>(x: T, y: Partial<T>, k: keyof T) {
76+
x[k] = y[k]; // Error
77+
~~~~
78+
!!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'.
79+
!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'.
80+
y[k] = x[k];
81+
}
82+
83+
function f11<T, K extends keyof T>(x: T, y: Partial<T>, k: K) {
84+
x[k] = y[k]; // Error
85+
~~~~
86+
!!! error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[K]'.
87+
!!! error TS2322: Type 'undefined' is not assignable to type 'T[K]'.
88+
y[k] = x[k];
89+
}
90+
91+
function f12<T, U extends T>(x: T, y: Partial<U>, k: keyof T) {
92+
x[k] = y[k]; // Error
93+
~~~~
94+
!!! error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'.
95+
!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'.
96+
y[k] = x[k]; // Error
97+
~~~~
98+
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'.
99+
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'.
100+
!!! error TS2322: Type 'T' is not assignable to type 'U'.
101+
}
102+
103+
function f13<T, U extends T, K extends keyof T>(x: T, y: Partial<U>, k: K) {
104+
x[k] = y[k]; // Error
105+
~~~~
106+
!!! error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[K]'.
107+
!!! error TS2322: Type 'undefined' is not assignable to type 'T[K]'.
108+
y[k] = x[k]; // Error
109+
~~~~
110+
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K] | undefined'.
111+
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
112+
!!! error TS2322: Type 'T' is not assignable to type 'U'.
113+
}
114+
115+
function f20<T>(x: T, y: Readonly<T>, k: keyof T) {
116+
x[k] = y[k];
117+
y[k] = x[k]; // Error
118+
~~~~
119+
!!! error TS2542: Index signature in type 'Readonly<T>' only permits reading.
120+
}
121+
122+
function f21<T, K extends keyof T>(x: T, y: Readonly<T>, k: K) {
123+
x[k] = y[k];
124+
y[k] = x[k]; // Error
125+
~~~~
126+
!!! error TS2542: Index signature in type 'Readonly<T>' only permits reading.
127+
}
128+
129+
function f22<T, U extends T>(x: T, y: Readonly<U>, k: keyof T) {
130+
x[k] = y[k];
131+
y[k] = x[k]; // Error
132+
~~~~
133+
!!! error TS2542: Index signature in type 'Readonly<U>' only permits reading.
134+
}
135+
136+
function f23<T, U extends T, K extends keyof T>(x: T, y: Readonly<U>, k: K) {
137+
x[k] = y[k];
138+
y[k] = x[k]; // Error
139+
~~~~
140+
!!! error TS2542: Index signature in type 'Readonly<U>' only permits reading.
141+
}
142+
143+
function f30<T>(x: T, y: Partial<T>) {
144+
x = y; // Error
145+
~
146+
!!! error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
147+
y = x;
148+
}
149+
150+
function f31<T>(x: T, y: Partial<T>) {
151+
x = y; // Error
152+
~
153+
!!! error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
154+
y = x;
155+
}
156+
157+
function f40<T>(x: T, y: Readonly<T>) {
158+
x = y;
159+
y = x;
160+
}
161+
162+
function f41<T>(x: T, y: Readonly<T>) {
163+
x = y;
164+
y = x;
165+
}
166+
167+
type Item = {
168+
name: string;
169+
}
170+
171+
type ItemMap = {
172+
[x: string]: Item;
173+
}
174+
175+
function f50<T extends ItemMap>(obj: T, key: keyof T) {
176+
let item: Item = obj[key];
177+
return obj[key].name;
178+
}
179+
180+
function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K) {
181+
let item: Item = obj[key];
182+
return obj[key].name;
183+
}
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
//// [mappedTypeRelationships.ts]
2+
3+
function f1<T>(x: T, k: keyof T) {
4+
return x[k];
5+
}
6+
7+
function f2<T, K extends keyof T>(x: T, k: K) {
8+
return x[k];
9+
}
10+
11+
function f3<T, U extends T>(x: T, y: U, k: keyof T) {
12+
x[k] = y[k];
13+
y[k] = x[k]; // Error
14+
}
15+
16+
function f4<T, U extends T, K extends keyof T>(x: T, y: U, k: K) {
17+
x[k] = y[k];
18+
y[k] = x[k]; // Error
19+
}
20+
21+
function f5<T, U extends T>(x: T, y: U, k: keyof U) {
22+
x[k] = y[k]; // Error
23+
y[k] = x[k]; // Error
24+
}
25+
26+
function f6<T, U extends T, K extends keyof U>(x: T, y: U, k: K) {
27+
x[k] = y[k]; // Error
28+
y[k] = x[k]; // Error
29+
}
30+
31+
function f10<T>(x: T, y: Partial<T>, k: keyof T) {
32+
x[k] = y[k]; // Error
33+
y[k] = x[k];
34+
}
35+
36+
function f11<T, K extends keyof T>(x: T, y: Partial<T>, k: K) {
37+
x[k] = y[k]; // Error
38+
y[k] = x[k];
39+
}
40+
41+
function f12<T, U extends T>(x: T, y: Partial<U>, k: keyof T) {
42+
x[k] = y[k]; // Error
43+
y[k] = x[k]; // Error
44+
}
45+
46+
function f13<T, U extends T, K extends keyof T>(x: T, y: Partial<U>, k: K) {
47+
x[k] = y[k]; // Error
48+
y[k] = x[k]; // Error
49+
}
50+
51+
function f20<T>(x: T, y: Readonly<T>, k: keyof T) {
52+
x[k] = y[k];
53+
y[k] = x[k]; // Error
54+
}
55+
56+
function f21<T, K extends keyof T>(x: T, y: Readonly<T>, k: K) {
57+
x[k] = y[k];
58+
y[k] = x[k]; // Error
59+
}
60+
61+
function f22<T, U extends T>(x: T, y: Readonly<U>, k: keyof T) {
62+
x[k] = y[k];
63+
y[k] = x[k]; // Error
64+
}
65+
66+
function f23<T, U extends T, K extends keyof T>(x: T, y: Readonly<U>, k: K) {
67+
x[k] = y[k];
68+
y[k] = x[k]; // Error
69+
}
70+
71+
function f30<T>(x: T, y: Partial<T>) {
72+
x = y; // Error
73+
y = x;
74+
}
75+
76+
function f31<T>(x: T, y: Partial<T>) {
77+
x = y; // Error
78+
y = x;
79+
}
80+
81+
function f40<T>(x: T, y: Readonly<T>) {
82+
x = y;
83+
y = x;
84+
}
85+
86+
function f41<T>(x: T, y: Readonly<T>) {
87+
x = y;
88+
y = x;
89+
}
90+
91+
type Item = {
92+
name: string;
93+
}
94+
95+
type ItemMap = {
96+
[x: string]: Item;
97+
}
98+
99+
function f50<T extends ItemMap>(obj: T, key: keyof T) {
100+
let item: Item = obj[key];
101+
return obj[key].name;
102+
}
103+
104+
function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K) {
105+
let item: Item = obj[key];
106+
return obj[key].name;
107+
}
108+
109+
//// [mappedTypeRelationships.js]
110+
function f1(x, k) {
111+
return x[k];
112+
}
113+
function f2(x, k) {
114+
return x[k];
115+
}
116+
function f3(x, y, k) {
117+
x[k] = y[k];
118+
y[k] = x[k]; // Error
119+
}
120+
function f4(x, y, k) {
121+
x[k] = y[k];
122+
y[k] = x[k]; // Error
123+
}
124+
function f5(x, y, k) {
125+
x[k] = y[k]; // Error
126+
y[k] = x[k]; // Error
127+
}
128+
function f6(x, y, k) {
129+
x[k] = y[k]; // Error
130+
y[k] = x[k]; // Error
131+
}
132+
function f10(x, y, k) {
133+
x[k] = y[k]; // Error
134+
y[k] = x[k];
135+
}
136+
function f11(x, y, k) {
137+
x[k] = y[k]; // Error
138+
y[k] = x[k];
139+
}
140+
function f12(x, y, k) {
141+
x[k] = y[k]; // Error
142+
y[k] = x[k]; // Error
143+
}
144+
function f13(x, y, k) {
145+
x[k] = y[k]; // Error
146+
y[k] = x[k]; // Error
147+
}
148+
function f20(x, y, k) {
149+
x[k] = y[k];
150+
y[k] = x[k]; // Error
151+
}
152+
function f21(x, y, k) {
153+
x[k] = y[k];
154+
y[k] = x[k]; // Error
155+
}
156+
function f22(x, y, k) {
157+
x[k] = y[k];
158+
y[k] = x[k]; // Error
159+
}
160+
function f23(x, y, k) {
161+
x[k] = y[k];
162+
y[k] = x[k]; // Error
163+
}
164+
function f30(x, y) {
165+
x = y; // Error
166+
y = x;
167+
}
168+
function f31(x, y) {
169+
x = y; // Error
170+
y = x;
171+
}
172+
function f40(x, y) {
173+
x = y;
174+
y = x;
175+
}
176+
function f41(x, y) {
177+
x = y;
178+
y = x;
179+
}
180+
function f50(obj, key) {
181+
var item = obj[key];
182+
return obj[key].name;
183+
}
184+
function f51(obj, key) {
185+
var item = obj[key];
186+
return obj[key].name;
187+
}
188+
189+
190+
//// [mappedTypeRelationships.d.ts]
191+
declare function f1<T>(x: T, k: keyof T): T[keyof T];
192+
declare function f2<T, K extends keyof T>(x: T, k: K): T[K];
193+
declare function f3<T, U extends T>(x: T, y: U, k: keyof T): void;
194+
declare function f4<T, U extends T, K extends keyof T>(x: T, y: U, k: K): void;
195+
declare function f5<T, U extends T>(x: T, y: U, k: keyof U): void;
196+
declare function f6<T, U extends T, K extends keyof U>(x: T, y: U, k: K): void;
197+
declare function f10<T>(x: T, y: Partial<T>, k: keyof T): void;
198+
declare function f11<T, K extends keyof T>(x: T, y: Partial<T>, k: K): void;
199+
declare function f12<T, U extends T>(x: T, y: Partial<U>, k: keyof T): void;
200+
declare function f13<T, U extends T, K extends keyof T>(x: T, y: Partial<U>, k: K): void;
201+
declare function f20<T>(x: T, y: Readonly<T>, k: keyof T): void;
202+
declare function f21<T, K extends keyof T>(x: T, y: Readonly<T>, k: K): void;
203+
declare function f22<T, U extends T>(x: T, y: Readonly<U>, k: keyof T): void;
204+
declare function f23<T, U extends T, K extends keyof T>(x: T, y: Readonly<U>, k: K): void;
205+
declare function f30<T>(x: T, y: Partial<T>): void;
206+
declare function f31<T>(x: T, y: Partial<T>): void;
207+
declare function f40<T>(x: T, y: Readonly<T>): void;
208+
declare function f41<T>(x: T, y: Readonly<T>): void;
209+
declare type Item = {
210+
name: string;
211+
};
212+
declare type ItemMap = {
213+
[x: string]: Item;
214+
};
215+
declare function f50<T extends ItemMap>(obj: T, key: keyof T): string;
216+
declare function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K): string;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(4,6): error TS2456: Type alias 'Recurse' circularly references itself.
2+
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(8,6): error TS2456: Type alias 'Recurse1' circularly references itself.
3+
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(12,6): error TS2456: Type alias 'Recurse2' circularly references itself.
4+
5+
6+
==== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts (3 errors) ====
7+
8+
// Recursive mapped types simply appear empty
9+
10+
type Recurse = {
11+
~~~~~~~
12+
!!! error TS2456: Type alias 'Recurse' circularly references itself.
13+
[K in keyof Recurse]: Recurse[K]
14+
}
15+
16+
type Recurse1 = {
17+
~~~~~~~~
18+
!!! error TS2456: Type alias 'Recurse1' circularly references itself.
19+
[K in keyof Recurse2]: Recurse2[K]
20+
}
21+
22+
type Recurse2 = {
23+
~~~~~~~~
24+
!!! error TS2456: Type alias 'Recurse2' circularly references itself.
25+
[K in keyof Recurse1]: Recurse1[K]
26+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// @strictNullChecks: true
2+
// @declaration: true
3+
4+
function f1<T>(x: T, k: keyof T) {
5+
return x[k];
6+
}
7+
8+
function f2<T, K extends keyof T>(x: T, k: K) {
9+
return x[k];
10+
}
11+
12+
function f3<T, U extends T>(x: T, y: U, k: keyof T) {
13+
x[k] = y[k];
14+
y[k] = x[k]; // Error
15+
}
16+
17+
function f4<T, U extends T, K extends keyof T>(x: T, y: U, k: K) {
18+
x[k] = y[k];
19+
y[k] = x[k]; // Error
20+
}
21+
22+
function f5<T, U extends T>(x: T, y: U, k: keyof U) {
23+
x[k] = y[k]; // Error
24+
y[k] = x[k]; // Error
25+
}
26+
27+
function f6<T, U extends T, K extends keyof U>(x: T, y: U, k: K) {
28+
x[k] = y[k]; // Error
29+
y[k] = x[k]; // Error
30+
}
31+
32+
function f10<T>(x: T, y: Partial<T>, k: keyof T) {
33+
x[k] = y[k]; // Error
34+
y[k] = x[k];
35+
}
36+
37+
function f11<T, K extends keyof T>(x: T, y: Partial<T>, k: K) {
38+
x[k] = y[k]; // Error
39+
y[k] = x[k];
40+
}
41+
42+
function f12<T, U extends T>(x: T, y: Partial<U>, k: keyof T) {
43+
x[k] = y[k]; // Error
44+
y[k] = x[k]; // Error
45+
}
46+
47+
function f13<T, U extends T, K extends keyof T>(x: T, y: Partial<U>, k: K) {
48+
x[k] = y[k]; // Error
49+
y[k] = x[k]; // Error
50+
}
51+
52+
function f20<T>(x: T, y: Readonly<T>, k: keyof T) {
53+
x[k] = y[k];
54+
y[k] = x[k]; // Error
55+
}
56+
57+
function f21<T, K extends keyof T>(x: T, y: Readonly<T>, k: K) {
58+
x[k] = y[k];
59+
y[k] = x[k]; // Error
60+
}
61+
62+
function f22<T, U extends T>(x: T, y: Readonly<U>, k: keyof T) {
63+
x[k] = y[k];
64+
y[k] = x[k]; // Error
65+
}
66+
67+
function f23<T, U extends T, K extends keyof T>(x: T, y: Readonly<U>, k: K) {
68+
x[k] = y[k];
69+
y[k] = x[k]; // Error
70+
}
71+
72+
function f30<T>(x: T, y: Partial<T>) {
73+
x = y; // Error
74+
y = x;
75+
}
76+
77+
function f31<T>(x: T, y: Partial<T>) {
78+
x = y; // Error
79+
y = x;
80+
}
81+
82+
function f40<T>(x: T, y: Readonly<T>) {
83+
x = y;
84+
y = x;
85+
}
86+
87+
function f41<T>(x: T, y: Readonly<T>) {
88+
x = y;
89+
y = x;
90+
}
91+
92+
type Item = {
93+
name: string;
94+
}
95+
96+
type ItemMap = {
97+
[x: string]: Item;
98+
}
99+
100+
function f50<T extends ItemMap>(obj: T, key: keyof T) {
101+
let item: Item = obj[key];
102+
return obj[key].name;
103+
}
104+
105+
function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K) {
106+
let item: Item = obj[key];
107+
return obj[key].name;
108+
}

0 commit comments

Comments
 (0)
Please sign in to comment.