Merge pull request #13448 from Microsoft/fixMappedTypeRelations
Improve generic mapped type relations
This commit is contained in:
commit
2711303539
4 changed files with 331 additions and 24 deletions
|
@ -4662,10 +4662,6 @@ namespace ts {
|
|||
return type.modifiersType;
|
||||
}
|
||||
|
||||
function getErasedTemplateTypeFromMappedType(type: MappedType) {
|
||||
return instantiateType(getTemplateTypeFromMappedType(type), createTypeEraser([getTypeParameterFromMappedType(type)]));
|
||||
}
|
||||
|
||||
function isGenericMappedType(type: Type) {
|
||||
if (getObjectFlags(type) & ObjectFlags.Mapped) {
|
||||
const constraintType = getConstraintTypeFromMappedType(<MappedType>type);
|
||||
|
@ -7764,25 +7760,24 @@ namespace ts {
|
|||
return result;
|
||||
}
|
||||
|
||||
// A type [P in S]: X is related to a type [P in T]: Y if T is related to S and X is related to Y.
|
||||
// A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is
|
||||
// related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice
|
||||
// that S and T are contra-variant whereas X and Y are co-variant.
|
||||
function mappedTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
if (isGenericMappedType(target)) {
|
||||
if (isGenericMappedType(source)) {
|
||||
let result: Ternary;
|
||||
if (relation === identityRelation) {
|
||||
const readonlyMatches = !(<MappedType>source).declaration.readonlyToken === !(<MappedType>target).declaration.readonlyToken;
|
||||
const optionalMatches = !(<MappedType>source).declaration.questionToken === !(<MappedType>target).declaration.questionToken;
|
||||
if (readonlyMatches && optionalMatches) {
|
||||
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
|
||||
return result & isRelatedTo(getErasedTemplateTypeFromMappedType(<MappedType>source), getErasedTemplateTypeFromMappedType(<MappedType>target), reportErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (relation === comparableRelation || !(<MappedType>source).declaration.questionToken || (<MappedType>target).declaration.questionToken) {
|
||||
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
|
||||
return result & isRelatedTo(getTemplateTypeFromMappedType(<MappedType>source), getTemplateTypeFromMappedType(<MappedType>target), reportErrors);
|
||||
}
|
||||
const sourceReadonly = !!(<MappedType>source).declaration.readonlyToken;
|
||||
const sourceOptional = !!(<MappedType>source).declaration.questionToken;
|
||||
const targetReadonly = !!(<MappedType>target).declaration.readonlyToken;
|
||||
const targetOptional = !!(<MappedType>target).declaration.questionToken;
|
||||
const modifiersRelated = relation === identityRelation ?
|
||||
sourceReadonly === targetReadonly && sourceOptional === targetOptional :
|
||||
relation === comparableRelation || !sourceOptional || targetOptional;
|
||||
if (modifiersRelated) {
|
||||
let result: Ternary;
|
||||
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
|
||||
const mapper = createTypeMapper([getTypeParameterFromMappedType(<MappedType>source)], [getTypeParameterFromMappedType(<MappedType>target)]);
|
||||
return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(<MappedType>source), mapper), getTemplateTypeFromMappedType(<MappedType>target), reportErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,9 +30,24 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(62,5): error TS2
|
|||
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(126,5): error TS2322: Type 'Partial<U>' is not assignable to type 'Identity<U>'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(142,5): error TS2322: Type '{ [P in keyof T]: T[P]; }' is not assignable to type '{ [P in keyof T]: U[P]; }'.
|
||||
Type 'T[P]' is not assignable to type 'U[P]'.
|
||||
Type 'T' is not assignable to type 'U'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(147,5): error TS2322: Type '{ [P in keyof T]: T[P]; }' is not assignable to type '{ [P in keyof U]: U[P]; }'.
|
||||
Type 'keyof U' is not assignable to type 'keyof T'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(152,5): error TS2322: Type '{ [P in K]: T[P]; }' is not assignable to type '{ [P in keyof T]: T[P]; }'.
|
||||
Type 'keyof T' is not assignable to type 'K'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(157,5): error TS2322: Type '{ [P in K]: T[P]; }' is not assignable to type '{ [P in keyof U]: U[P]; }'.
|
||||
Type 'keyof U' is not assignable to type 'K'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(162,5): error TS2322: Type '{ [P in K]: T[P]; }' is not assignable to type '{ [P in keyof T]: U[P]; }'.
|
||||
Type 'keyof T' is not assignable to type 'K'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(167,5): error TS2322: Type '{ [P in K]: T[P]; }' is not assignable to type '{ [P in K]: U[P]; }'.
|
||||
Type 'T[P]' is not assignable to type 'U[P]'.
|
||||
Type 'T' is not assignable to type 'U'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/mapped/mappedTypeRelationships.ts (20 errors) ====
|
||||
==== tests/cases/conformance/types/mapped/mappedTypeRelationships.ts (27 errors) ====
|
||||
|
||||
function f1<T>(x: T, k: keyof T) {
|
||||
return x[k];
|
||||
|
@ -190,4 +205,89 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(76,5): error TS2
|
|||
function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K) {
|
||||
let item: Item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
}
|
||||
|
||||
type T1<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
}
|
||||
|
||||
type T2<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
}
|
||||
|
||||
function f60<U>(x: T1<U>, y: T2<U>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
type Identity<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
}
|
||||
|
||||
function f61<U>(x: Identity<U>, y: Partial<U>) {
|
||||
x = y; // Error
|
||||
~
|
||||
!!! error TS2322: Type 'Partial<U>' is not assignable to type 'Identity<U>'.
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f62<U>(x: Identity<U>, y: Readonly<U>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f70<T>(x: { [P in keyof T]: T[P] }, y: { [P in keyof T]: T[P] }) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f71<T, U extends T>(x: { [P in keyof T]: T[P] }, y: { [P in keyof T]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
~
|
||||
!!! error TS2322: Type '{ [P in keyof T]: T[P]; }' is not assignable to type '{ [P in keyof T]: U[P]; }'.
|
||||
!!! error TS2322: Type 'T[P]' is not assignable to type 'U[P]'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'U'.
|
||||
}
|
||||
|
||||
function f72<T, U extends T>(x: { [P in keyof T]: T[P] }, y: { [P in keyof U]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
~
|
||||
!!! error TS2322: Type '{ [P in keyof T]: T[P]; }' is not assignable to type '{ [P in keyof U]: U[P]; }'.
|
||||
!!! error TS2322: Type 'keyof U' is not assignable to type 'keyof T'.
|
||||
}
|
||||
|
||||
function f73<T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in keyof T]: T[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
~
|
||||
!!! error TS2322: Type '{ [P in K]: T[P]; }' is not assignable to type '{ [P in keyof T]: T[P]; }'.
|
||||
!!! error TS2322: Type 'keyof T' is not assignable to type 'K'.
|
||||
}
|
||||
|
||||
function f74<T, U extends T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in keyof U]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
~
|
||||
!!! error TS2322: Type '{ [P in K]: T[P]; }' is not assignable to type '{ [P in keyof U]: U[P]; }'.
|
||||
!!! error TS2322: Type 'keyof U' is not assignable to type 'K'.
|
||||
}
|
||||
|
||||
function f75<T, U extends T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in keyof T]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
~
|
||||
!!! error TS2322: Type '{ [P in K]: T[P]; }' is not assignable to type '{ [P in keyof T]: U[P]; }'.
|
||||
!!! error TS2322: Type 'keyof T' is not assignable to type 'K'.
|
||||
}
|
||||
|
||||
function f76<T, U extends T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in K]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
~
|
||||
!!! error TS2322: Type '{ [P in K]: T[P]; }' is not assignable to type '{ [P in K]: U[P]; }'.
|
||||
!!! error TS2322: Type 'T[P]' is not assignable to type 'U[P]'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'U'.
|
||||
}
|
||||
|
|
@ -104,7 +104,70 @@ function f50<T extends ItemMap>(obj: T, key: keyof T) {
|
|||
function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K) {
|
||||
let item: Item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
}
|
||||
|
||||
type T1<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
}
|
||||
|
||||
type T2<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
}
|
||||
|
||||
function f60<U>(x: T1<U>, y: T2<U>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
type Identity<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
}
|
||||
|
||||
function f61<U>(x: Identity<U>, y: Partial<U>) {
|
||||
x = y; // Error
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f62<U>(x: Identity<U>, y: Readonly<U>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f70<T>(x: { [P in keyof T]: T[P] }, y: { [P in keyof T]: T[P] }) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f71<T, U extends T>(x: { [P in keyof T]: T[P] }, y: { [P in keyof T]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f72<T, U extends T>(x: { [P in keyof T]: T[P] }, y: { [P in keyof U]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f73<T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in keyof T]: T[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f74<T, U extends T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in keyof U]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f75<T, U extends T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in keyof T]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f76<T, U extends T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in K]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
|
||||
//// [mappedTypeRelationships.js]
|
||||
function f1(x, k) {
|
||||
|
@ -185,6 +248,46 @@ function f51(obj, key) {
|
|||
var item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
function f60(x, y) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
function f61(x, y) {
|
||||
x = y; // Error
|
||||
y = x;
|
||||
}
|
||||
function f62(x, y) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
function f70(x, y) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
function f71(x, y) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
function f72(x, y) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
function f73(x, y) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
function f74(x, y) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
function f75(x, y) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
function f76(x, y) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
|
||||
//// [mappedTypeRelationships.d.ts]
|
||||
|
@ -214,3 +317,50 @@ declare type ItemMap = {
|
|||
};
|
||||
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;
|
||||
declare type T1<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
};
|
||||
declare type T2<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
};
|
||||
declare function f60<U>(x: T1<U>, y: T2<U>): void;
|
||||
declare type Identity<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
};
|
||||
declare function f61<U>(x: Identity<U>, y: Partial<U>): void;
|
||||
declare function f62<U>(x: Identity<U>, y: Readonly<U>): void;
|
||||
declare function f70<T>(x: {
|
||||
[P in keyof T]: T[P];
|
||||
}, y: {
|
||||
[P in keyof T]: T[P];
|
||||
}): void;
|
||||
declare function f71<T, U extends T>(x: {
|
||||
[P in keyof T]: T[P];
|
||||
}, y: {
|
||||
[P in keyof T]: U[P];
|
||||
}): void;
|
||||
declare function f72<T, U extends T>(x: {
|
||||
[P in keyof T]: T[P];
|
||||
}, y: {
|
||||
[P in keyof U]: U[P];
|
||||
}): void;
|
||||
declare function f73<T, K extends keyof T>(x: {
|
||||
[P in K]: T[P];
|
||||
}, y: {
|
||||
[P in keyof T]: T[P];
|
||||
}): void;
|
||||
declare function f74<T, U extends T, K extends keyof T>(x: {
|
||||
[P in K]: T[P];
|
||||
}, y: {
|
||||
[P in keyof U]: U[P];
|
||||
}): void;
|
||||
declare function f75<T, U extends T, K extends keyof T>(x: {
|
||||
[P in K]: T[P];
|
||||
}, y: {
|
||||
[P in keyof T]: U[P];
|
||||
}): void;
|
||||
declare function f76<T, U extends T, K extends keyof T>(x: {
|
||||
[P in K]: T[P];
|
||||
}, y: {
|
||||
[P in K]: U[P];
|
||||
}): void;
|
||||
|
|
|
@ -105,4 +105,66 @@ function f50<T extends ItemMap>(obj: T, key: keyof T) {
|
|||
function f51<T extends ItemMap, K extends keyof T>(obj: T, key: K) {
|
||||
let item: Item = obj[key];
|
||||
return obj[key].name;
|
||||
}
|
||||
}
|
||||
|
||||
type T1<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
}
|
||||
|
||||
type T2<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
}
|
||||
|
||||
function f60<U>(x: T1<U>, y: T2<U>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
type Identity<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
}
|
||||
|
||||
function f61<U>(x: Identity<U>, y: Partial<U>) {
|
||||
x = y; // Error
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f62<U>(x: Identity<U>, y: Readonly<U>) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f70<T>(x: { [P in keyof T]: T[P] }, y: { [P in keyof T]: T[P] }) {
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
|
||||
function f71<T, U extends T>(x: { [P in keyof T]: T[P] }, y: { [P in keyof T]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f72<T, U extends T>(x: { [P in keyof T]: T[P] }, y: { [P in keyof U]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f73<T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in keyof T]: T[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f74<T, U extends T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in keyof U]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f75<T, U extends T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in keyof T]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
||||
function f76<T, U extends T, K extends keyof T>(x: { [P in K]: T[P] }, y: { [P in K]: U[P] }) {
|
||||
x = y;
|
||||
y = x; // Error
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue