mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Merge pull request #12351 from Microsoft/mappedTypeRelations
Higher order type relations for mapped types
This commit is contained in:
commit
e81da9cd8a
@ -120,6 +120,7 @@ namespace ts {
|
||||
const intersectionTypes = createMap<IntersectionType>();
|
||||
const stringLiteralTypes = createMap<LiteralType>();
|
||||
const numericLiteralTypes = createMap<LiteralType>();
|
||||
const indexedAccessTypes = createMap<IndexedAccessType>();
|
||||
const evolvingArrayTypes: EvolvingArrayType[] = [];
|
||||
|
||||
const unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown");
|
||||
@ -4665,13 +4666,22 @@ namespace ts {
|
||||
return type.resolvedApparentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The apparent type of an indexed access T[K] is the type of T's string index signature, if any.
|
||||
*/
|
||||
function getApparentTypeOfIndexedAccess(type: IndexedAccessType) {
|
||||
return getIndexTypeOfType(getApparentType(type.objectType), IndexKind.String) || type;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a type parameter, return the base constraint of the type parameter. For the string, number,
|
||||
* boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
|
||||
* type itself. Note that the apparent type of a union type is the union type itself.
|
||||
*/
|
||||
function getApparentType(type: Type): Type {
|
||||
const t = type.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(<TypeParameter>type) : type;
|
||||
const t = type.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(<TypeParameter>type) :
|
||||
type.flags & TypeFlags.IndexedAccess ? getApparentTypeOfIndexedAccess(<IndexedAccessType>type) :
|
||||
type;
|
||||
return t.flags & TypeFlags.StringLike ? globalStringType :
|
||||
t.flags & TypeFlags.NumberLike ? globalNumberType :
|
||||
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
|
||||
@ -5907,6 +5917,7 @@ namespace ts {
|
||||
|
||||
function getIndexType(type: Type): Type {
|
||||
return type.flags & TypeFlags.TypeParameter ? getIndexTypeForTypeParameter(<TypeParameter>type) :
|
||||
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
|
||||
type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringOrNumberType :
|
||||
getIndexInfoOfType(type, IndexKind.Number) ? getUnionType([numberType, getLiteralTypeFromPropertyNames(type)]) :
|
||||
getLiteralTypeFromPropertyNames(type);
|
||||
@ -5920,18 +5931,13 @@ namespace ts {
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function createIndexedAccessType(objectType: Type, indexType: TypeParameter) {
|
||||
function createIndexedAccessType(objectType: Type, indexType: Type) {
|
||||
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
|
||||
type.objectType = objectType;
|
||||
type.indexType = indexType;
|
||||
return type;
|
||||
}
|
||||
|
||||
function getIndexedAccessTypeForTypeParameter(objectType: Type, indexType: TypeParameter) {
|
||||
const indexedAccessTypes = indexType.resolvedIndexedAccessTypes || (indexType.resolvedIndexedAccessTypes = []);
|
||||
return indexedAccessTypes[objectType.id] || (indexedAccessTypes[objectType.id] = createIndexedAccessType(objectType, indexType));
|
||||
}
|
||||
|
||||
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
|
||||
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
|
||||
const propName = indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral) ?
|
||||
@ -5995,13 +6001,41 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
function getIndexedAccessForMappedType(type: MappedType, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
|
||||
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
|
||||
if (accessExpression && isAssignmentTarget(accessExpression) && type.declaration.readonlyToken) {
|
||||
error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(type));
|
||||
return unknownType;
|
||||
}
|
||||
const mapper = createUnaryTypeMapper(getTypeParameterFromMappedType(type), indexType);
|
||||
const templateMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper;
|
||||
return addOptionality(instantiateType(getTemplateTypeFromMappedType(type), templateMapper), !!type.declaration.questionToken);
|
||||
}
|
||||
|
||||
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
|
||||
if (indexType.flags & TypeFlags.TypeParameter) {
|
||||
if (accessNode && !isTypeAssignableTo(getConstraintOfTypeParameter(<TypeParameter>indexType) || emptyObjectType, getIndexType(objectType))) {
|
||||
error(accessNode, Diagnostics.Type_0_is_not_constrained_to_keyof_1, typeToString(indexType), typeToString(objectType));
|
||||
return unknownType;
|
||||
if (indexType.flags & TypeFlags.TypeParameter ||
|
||||
objectType.flags & TypeFlags.TypeParameter && indexType.flags & TypeFlags.Index ||
|
||||
isGenericMappedType(objectType)) {
|
||||
// If either the object type or the index type are type parameters, or if the object type is a mapped
|
||||
// type with a generic constraint, we are performing a higher-order index access where we cannot
|
||||
// meaningfully access the properties of the object type. In those cases, we first check that the
|
||||
// index type is assignable to 'keyof T' for the object type.
|
||||
if (accessNode) {
|
||||
const keyType = indexType.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>indexType) || emptyObjectType : indexType;
|
||||
if (!isTypeAssignableTo(keyType, getIndexType(objectType))) {
|
||||
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType));
|
||||
return unknownType;
|
||||
}
|
||||
}
|
||||
return getIndexedAccessTypeForTypeParameter(objectType, <TypeParameter>indexType);
|
||||
// If the object type is a mapped type { [P in K]: E }, we instantiate E using a mapper that substitutes
|
||||
// the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we construct the
|
||||
// type Box<T[X]>.
|
||||
if (isGenericMappedType(objectType)) {
|
||||
return getIndexedAccessForMappedType(<MappedType>objectType, indexType, accessNode);
|
||||
}
|
||||
// Otherwise we defer the operation by creating an indexed access type.
|
||||
const id = objectType.id + "," + indexType.id;
|
||||
return indexedAccessTypes[id] || (indexedAccessTypes[id] = createIndexedAccessType(objectType, indexType));
|
||||
}
|
||||
const apparentType = getApparentType(objectType);
|
||||
if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Primitive)) {
|
||||
@ -6034,6 +6068,9 @@ namespace ts {
|
||||
type.aliasSymbol = getAliasSymbolForTypeNode(node);
|
||||
type.aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node);
|
||||
links.resolvedType = type;
|
||||
// Eagerly resolve the constraint type which forces an error if the constraint type circularly
|
||||
// references itself through one or more type aliases.
|
||||
getConstraintTypeFromMappedType(type);
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
@ -7153,12 +7190,24 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (target.flags & TypeFlags.TypeParameter) {
|
||||
// Given a type parameter K with a constraint keyof T, a type S is
|
||||
// assignable to K if S is assignable to keyof T.
|
||||
const constraint = getConstraintOfTypeParameter(<TypeParameter>target);
|
||||
if (constraint && constraint.flags & TypeFlags.Index) {
|
||||
if (result = isRelatedTo(source, constraint, reportErrors)) {
|
||||
return result;
|
||||
// A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P].
|
||||
if (getObjectFlags(source) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(<MappedType>source) === getIndexType(target)) {
|
||||
if (!(<MappedType>source).declaration.questionToken) {
|
||||
const templateType = getTemplateTypeFromMappedType(<MappedType>source);
|
||||
const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(<MappedType>source));
|
||||
if (result = isRelatedTo(templateType, indexedAccessType, reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Given a type parameter K with a constraint keyof T, a type S is
|
||||
// assignable to K if S is assignable to keyof T.
|
||||
const constraint = getConstraintOfTypeParameter(<TypeParameter>target);
|
||||
if (constraint && constraint.flags & TypeFlags.Index) {
|
||||
if (result = isRelatedTo(source, constraint, reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7178,22 +7227,41 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (target.flags & TypeFlags.IndexedAccess) {
|
||||
// if we have indexed access types with identical index types, see if relationship holds for
|
||||
// the two object types.
|
||||
if (source.flags & TypeFlags.IndexedAccess && (<IndexedAccessType>source).indexType === (<IndexedAccessType>target).indexType) {
|
||||
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (source.flags & TypeFlags.TypeParameter) {
|
||||
let constraint = getConstraintOfTypeParameter(<TypeParameter>source);
|
||||
|
||||
if (!constraint || constraint.flags & TypeFlags.Any) {
|
||||
constraint = emptyObjectType;
|
||||
// A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X.
|
||||
if (getObjectFlags(target) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(<MappedType>target) === getIndexType(source)) {
|
||||
const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(<MappedType>target));
|
||||
const templateType = getTemplateTypeFromMappedType(<MappedType>target);
|
||||
if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
let constraint = getConstraintOfTypeParameter(<TypeParameter>source);
|
||||
|
||||
// The constraint may need to be further instantiated with its 'this' type.
|
||||
constraint = getTypeWithThisArgument(constraint, source);
|
||||
if (!constraint || constraint.flags & TypeFlags.Any) {
|
||||
constraint = emptyObjectType;
|
||||
}
|
||||
|
||||
// Report constraint errors only if the constraint is not the empty object type
|
||||
const reportConstraintErrors = reportErrors && constraint !== emptyObjectType;
|
||||
if (result = isRelatedTo(constraint, target, reportConstraintErrors)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
// The constraint may need to be further instantiated with its 'this' type.
|
||||
constraint = getTypeWithThisArgument(constraint, source);
|
||||
|
||||
// Report constraint errors only if the constraint is not the empty object type
|
||||
const reportConstraintErrors = reportErrors && constraint !== emptyObjectType;
|
||||
if (result = isRelatedTo(constraint, target, reportConstraintErrors)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@ -1731,7 +1731,7 @@
|
||||
"category": "Error",
|
||||
"code": 2535
|
||||
},
|
||||
"Type '{0}' is not constrained to 'keyof {1}'.": {
|
||||
"Type '{0}' cannot be used to index type '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 2536
|
||||
},
|
||||
|
||||
@ -2974,8 +2974,6 @@ namespace ts {
|
||||
/* @internal */
|
||||
resolvedIndexType: IndexType;
|
||||
/* @internal */
|
||||
resolvedIndexedAccessTypes: IndexedAccessType[];
|
||||
/* @internal */
|
||||
isThisType?: boolean;
|
||||
}
|
||||
|
||||
@ -2985,7 +2983,7 @@ namespace ts {
|
||||
|
||||
export interface IndexedAccessType extends Type {
|
||||
objectType: Type;
|
||||
indexType: TypeParameter;
|
||||
indexType: Type;
|
||||
}
|
||||
|
||||
export const enum SignatureKind {
|
||||
|
||||
183
tests/baselines/reference/mappedTypeRelationships.errors.txt
Normal file
183
tests/baselines/reference/mappedTypeRelationships.errors.txt
Normal file
@ -0,0 +1,183 @@
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(12,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'.
|
||||
Type 'T' is not assignable to type 'U'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(17,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
|
||||
Type 'T' is not assignable to type 'U'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(21,5): error TS2536: Type 'keyof U' cannot be used to index type 'T'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(22,12): error TS2536: Type 'keyof U' cannot be used to index type 'T'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(26,5): error TS2536: Type 'K' cannot be used to index type 'T'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(27,12): error TS2536: Type 'K' cannot be used to index type 'T'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(31,5): error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'.
|
||||
Type 'undefined' is not assignable to type 'T[keyof T]'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(36,5): error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[K]'.
|
||||
Type 'undefined' is not assignable to type 'T[K]'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(41,5): error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'.
|
||||
Type 'undefined' is not assignable to type 'T[keyof T]'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(42,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'.
|
||||
Type 'T[keyof T]' is not assignable to type 'U[keyof T]'.
|
||||
Type 'T' is not assignable to type 'U'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(46,5): error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[K]'.
|
||||
Type 'undefined' is not assignable to type 'T[K]'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(47,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K] | undefined'.
|
||||
Type 'T[K]' is not assignable to type 'U[K]'.
|
||||
Type 'T' is not assignable to type 'U'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(52,5): error TS2542: Index signature in type 'Readonly<T>' only permits reading.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(57,5): error TS2542: Index signature in type 'Readonly<T>' only permits reading.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(62,5): error TS2542: Index signature in type 'Readonly<U>' only permits reading.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(67,5): error TS2542: Index signature in type 'Readonly<U>' only permits reading.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(71,5): error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(76,5): error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/mapped/mappedTypeRelationships.ts (18 errors) ====
|
||||
|
||||
function f1<T>(x: T, k: keyof T) {
|
||||
return x[k];
|
||||
}
|
||||
|
||||
function f2<T, K extends keyof T>(x: T, k: K) {
|
||||
return x[k];
|
||||
}
|
||||
|
||||
function f3<T, U extends T>(x: T, y: U, k: keyof T) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'U'.
|
||||
}
|
||||
|
||||
function f4<T, U extends T, K extends keyof T>(x: T, y: U, k: K) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'U'.
|
||||
}
|
||||
|
||||
function f5<T, U extends T>(x: T, y: U, k: keyof U) {
|
||||
x[k] = y[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2536: Type 'keyof U' cannot be used to index type 'T'.
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2536: Type 'keyof U' cannot be used to index type 'T'.
|
||||
}
|
||||
|
||||
function f6<T, U extends T, K extends keyof U>(x: T, y: U, k: K) {
|
||||
x[k] = y[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2536: Type 'K' cannot be used to index type 'T'.
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2536: Type 'K' cannot be used to index type 'T'.
|
||||
}
|
||||
|
||||
function f10<T>(x: T, y: Partial<T>, k: keyof T) {
|
||||
x[k] = y[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'.
|
||||
y[k] = x[k];
|
||||
}
|
||||
|
||||
function f11<T, K extends keyof T>(x: T, y: Partial<T>, k: K) {
|
||||
x[k] = y[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[K]'.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'T[K]'.
|
||||
y[k] = x[k];
|
||||
}
|
||||
|
||||
function f12<T, U extends T>(x: T, y: Partial<U>, k: keyof T) {
|
||||
x[k] = y[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'.
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'.
|
||||
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'U'.
|
||||
}
|
||||
|
||||
function f13<T, U extends T, K extends keyof T>(x: T, y: Partial<U>, k: K) {
|
||||
x[k] = y[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[K]'.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'T[K]'.
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K] | undefined'.
|
||||
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'U'.
|
||||
}
|
||||
|
||||
function f20<T>(x: T, y: Readonly<T>, k: keyof T) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2542: Index signature in type 'Readonly<T>' only permits reading.
|
||||
}
|
||||
|
||||
function f21<T, K extends keyof T>(x: T, y: Readonly<T>, k: K) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2542: Index signature in type 'Readonly<T>' only permits reading.
|
||||
}
|
||||
|
||||
function f22<T, U extends T>(x: T, y: Readonly<U>, k: keyof T) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2542: Index signature in type 'Readonly<U>' only permits reading.
|
||||
}
|
||||
|
||||
function f23<T, U extends T, K extends keyof T>(x: T, y: Readonly<U>, k: K) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
~~~~
|
||||
!!! error TS2542: Index signature in type 'Readonly<U>' only permits reading.
|
||||
}
|
||||
|
||||
function f30<T>(x: T, y: Partial<T>) {
|
||||
x = y; // Error
|
||||
~
|
||||
!!! error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f31<T>(x: T, y: Partial<T>) {
|
||||
x = y; // Error
|
||||
~
|
||||
!!! error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f40<T>(x: T, y: Readonly<T>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f41<T>(x: T, y: Readonly<T>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
type Item = {
|
||||
name: string;
|
||||
}
|
||||
|
||||
type ItemMap = {
|
||||
[x: string]: Item;
|
||||
}
|
||||
|
||||
function f50<T extends ItemMap>(obj: T, key: keyof T) {
|
||||
let item: Item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
|
||||
function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K) {
|
||||
let item: Item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
216
tests/baselines/reference/mappedTypeRelationships.js
Normal file
216
tests/baselines/reference/mappedTypeRelationships.js
Normal file
@ -0,0 +1,216 @@
|
||||
//// [mappedTypeRelationships.ts]
|
||||
|
||||
function f1<T>(x: T, k: keyof T) {
|
||||
return x[k];
|
||||
}
|
||||
|
||||
function f2<T, K extends keyof T>(x: T, k: K) {
|
||||
return x[k];
|
||||
}
|
||||
|
||||
function f3<T, U extends T>(x: T, y: U, k: keyof T) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f4<T, U extends T, K extends keyof T>(x: T, y: U, k: K) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f5<T, U extends T>(x: T, y: U, k: keyof U) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f6<T, U extends T, K extends keyof U>(x: T, y: U, k: K) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f10<T>(x: T, y: Partial<T>, k: keyof T) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k];
|
||||
}
|
||||
|
||||
function f11<T, K extends keyof T>(x: T, y: Partial<T>, k: K) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k];
|
||||
}
|
||||
|
||||
function f12<T, U extends T>(x: T, y: Partial<U>, k: keyof T) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f13<T, U extends T, K extends keyof T>(x: T, y: Partial<U>, k: K) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f20<T>(x: T, y: Readonly<T>, k: keyof T) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f21<T, K extends keyof T>(x: T, y: Readonly<T>, k: K) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f22<T, U extends T>(x: T, y: Readonly<U>, k: keyof T) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f23<T, U extends T, K extends keyof T>(x: T, y: Readonly<U>, k: K) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f30<T>(x: T, y: Partial<T>) {
|
||||
x = y; // Error
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f31<T>(x: T, y: Partial<T>) {
|
||||
x = y; // Error
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f40<T>(x: T, y: Readonly<T>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f41<T>(x: T, y: Readonly<T>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
type Item = {
|
||||
name: string;
|
||||
}
|
||||
|
||||
type ItemMap = {
|
||||
[x: string]: Item;
|
||||
}
|
||||
|
||||
function f50<T extends ItemMap>(obj: T, key: keyof T) {
|
||||
let item: Item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
|
||||
function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K) {
|
||||
let item: Item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
|
||||
//// [mappedTypeRelationships.js]
|
||||
function f1(x, k) {
|
||||
return x[k];
|
||||
}
|
||||
function f2(x, k) {
|
||||
return x[k];
|
||||
}
|
||||
function f3(x, y, k) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f4(x, y, k) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f5(x, y, k) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f6(x, y, k) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f10(x, y, k) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k];
|
||||
}
|
||||
function f11(x, y, k) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k];
|
||||
}
|
||||
function f12(x, y, k) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f13(x, y, k) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f20(x, y, k) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f21(x, y, k) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f22(x, y, k) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f23(x, y, k) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
function f30(x, y) {
|
||||
x = y; // Error
|
||||
y = x;
|
||||
}
|
||||
function f31(x, y) {
|
||||
x = y; // Error
|
||||
y = x;
|
||||
}
|
||||
function f40(x, y) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
function f41(x, y) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
function f50(obj, key) {
|
||||
var item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
function f51(obj, key) {
|
||||
var item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
|
||||
|
||||
//// [mappedTypeRelationships.d.ts]
|
||||
declare function f1<T>(x: T, k: keyof T): T[keyof T];
|
||||
declare function f2<T, K extends keyof T>(x: T, k: K): T[K];
|
||||
declare function f3<T, U extends T>(x: T, y: U, k: keyof T): void;
|
||||
declare function f4<T, U extends T, K extends keyof T>(x: T, y: U, k: K): void;
|
||||
declare function f5<T, U extends T>(x: T, y: U, k: keyof U): void;
|
||||
declare function f6<T, U extends T, K extends keyof U>(x: T, y: U, k: K): void;
|
||||
declare function f10<T>(x: T, y: Partial<T>, k: keyof T): void;
|
||||
declare function f11<T, K extends keyof T>(x: T, y: Partial<T>, k: K): void;
|
||||
declare function f12<T, U extends T>(x: T, y: Partial<U>, k: keyof T): void;
|
||||
declare function f13<T, U extends T, K extends keyof T>(x: T, y: Partial<U>, k: K): void;
|
||||
declare function f20<T>(x: T, y: Readonly<T>, k: keyof T): void;
|
||||
declare function f21<T, K extends keyof T>(x: T, y: Readonly<T>, k: K): void;
|
||||
declare function f22<T, U extends T>(x: T, y: Readonly<U>, k: keyof T): void;
|
||||
declare function f23<T, U extends T, K extends keyof T>(x: T, y: Readonly<U>, k: K): void;
|
||||
declare function f30<T>(x: T, y: Partial<T>): void;
|
||||
declare function f31<T>(x: T, y: Partial<T>): void;
|
||||
declare function f40<T>(x: T, y: Readonly<T>): void;
|
||||
declare function f41<T>(x: T, y: Readonly<T>): void;
|
||||
declare type Item = {
|
||||
name: string;
|
||||
};
|
||||
declare type ItemMap = {
|
||||
[x: string]: Item;
|
||||
};
|
||||
declare function f50<T extends ItemMap>(obj: T, key: keyof T): string;
|
||||
declare function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K): string;
|
||||
26
tests/baselines/reference/recursiveMappedTypes.errors.txt
Normal file
26
tests/baselines/reference/recursiveMappedTypes.errors.txt
Normal file
@ -0,0 +1,26 @@
|
||||
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(4,6): error TS2456: Type alias 'Recurse' circularly references itself.
|
||||
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(8,6): error TS2456: Type alias 'Recurse1' circularly references itself.
|
||||
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(12,6): error TS2456: Type alias 'Recurse2' circularly references itself.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts (3 errors) ====
|
||||
|
||||
// Recursive mapped types simply appear empty
|
||||
|
||||
type Recurse = {
|
||||
~~~~~~~
|
||||
!!! error TS2456: Type alias 'Recurse' circularly references itself.
|
||||
[K in keyof Recurse]: Recurse[K]
|
||||
}
|
||||
|
||||
type Recurse1 = {
|
||||
~~~~~~~~
|
||||
!!! error TS2456: Type alias 'Recurse1' circularly references itself.
|
||||
[K in keyof Recurse2]: Recurse2[K]
|
||||
}
|
||||
|
||||
type Recurse2 = {
|
||||
~~~~~~~~
|
||||
!!! error TS2456: Type alias 'Recurse2' circularly references itself.
|
||||
[K in keyof Recurse1]: Recurse1[K]
|
||||
}
|
||||
108
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts
Normal file
108
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts
Normal file
@ -0,0 +1,108 @@
|
||||
// @strictNullChecks: true
|
||||
// @declaration: true
|
||||
|
||||
function f1<T>(x: T, k: keyof T) {
|
||||
return x[k];
|
||||
}
|
||||
|
||||
function f2<T, K extends keyof T>(x: T, k: K) {
|
||||
return x[k];
|
||||
}
|
||||
|
||||
function f3<T, U extends T>(x: T, y: U, k: keyof T) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f4<T, U extends T, K extends keyof T>(x: T, y: U, k: K) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f5<T, U extends T>(x: T, y: U, k: keyof U) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f6<T, U extends T, K extends keyof U>(x: T, y: U, k: K) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f10<T>(x: T, y: Partial<T>, k: keyof T) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k];
|
||||
}
|
||||
|
||||
function f11<T, K extends keyof T>(x: T, y: Partial<T>, k: K) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k];
|
||||
}
|
||||
|
||||
function f12<T, U extends T>(x: T, y: Partial<U>, k: keyof T) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f13<T, U extends T, K extends keyof T>(x: T, y: Partial<U>, k: K) {
|
||||
x[k] = y[k]; // Error
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f20<T>(x: T, y: Readonly<T>, k: keyof T) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f21<T, K extends keyof T>(x: T, y: Readonly<T>, k: K) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f22<T, U extends T>(x: T, y: Readonly<U>, k: keyof T) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f23<T, U extends T, K extends keyof T>(x: T, y: Readonly<U>, k: K) {
|
||||
x[k] = y[k];
|
||||
y[k] = x[k]; // Error
|
||||
}
|
||||
|
||||
function f30<T>(x: T, y: Partial<T>) {
|
||||
x = y; // Error
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f31<T>(x: T, y: Partial<T>) {
|
||||
x = y; // Error
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f40<T>(x: T, y: Readonly<T>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f41<T>(x: T, y: Readonly<T>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
type Item = {
|
||||
name: string;
|
||||
}
|
||||
|
||||
type ItemMap = {
|
||||
[x: string]: Item;
|
||||
}
|
||||
|
||||
function f50<T extends ItemMap>(obj: T, key: keyof T) {
|
||||
let item: Item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
|
||||
function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K) {
|
||||
let item: Item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user