Remove mapped types to never from intersections

when transforming an indexed access type in order to get its constraint.
This commit is contained in:
Nathan Shively-Sanders 2018-01-12 14:43:31 -08:00
parent baf31ec52e
commit d74820d519
5 changed files with 92 additions and 8 deletions

View File

@ -6468,7 +6468,7 @@ namespace ts {
}
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
const transformed = getSubstitutedIndexedMappedType(type);
const transformed = getSimplifiedIndexedAccessType(type);
if (transformed) {
return transformed;
}
@ -8359,6 +8359,10 @@ namespace ts {
return false;
}
function isMappedTypeToNever(type: Type) {
return getObjectFlags(type) & ObjectFlags.Mapped && getTemplateTypeFromMappedType(type as MappedType) === neverType;
}
// Transform an indexed access to a simpler form, if possible. Return the simpler form, or return
// undefined if no transformation is possible.
function getSimplifiedIndexedAccessType(type: IndexedAccessType): Type {
@ -8383,11 +8387,22 @@ namespace ts {
getIntersectionType(stringIndexTypes)
]);
}
return getSubstitutedIndexedMappedType(type);
}
// Given an indexed access type T[K], if T is an intersection containing one or more generic types and one or
// more mapped types with a template type `never`, '(U & V & { [P in T]: never })[K]', return a
// transformed type that removes the never-mapped type: '(U & V)[K]'. This mirrors what would happen
// eventually anyway, but it easier to reason about.
if (objectType.flags & TypeFlags.Intersection && isGenericObjectType(objectType) && some((<IntersectionType>objectType).types, isMappedTypeToNever)) {
let nonNeverTypes: Type[];
for (const t of (<IntersectionType>objectType).types) {
if (!isMappedTypeToNever(t)) {
(nonNeverTypes || (nonNeverTypes = [])).push(t);
}
}
if (nonNeverTypes) {
return getIndexedAccessType(getIntersectionType(nonNeverTypes), type.indexType);
}
}
function getSubstitutedIndexedMappedType(type: IndexedAccessType): Type {
const objectType = type.objectType;
// If the object type is a mapped type { [P in K]: E }, where K is generic, 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]>.

View File

@ -2,9 +2,14 @@
type Diff<T extends string, U extends string> =
({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T]
type Omit<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>
type Omit1<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>;
// is in fact an equivalent of
type Omit2<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]};
type O = Omit<{ a: number, b: string }, 'a'>
const o: O = { b: '' }
//// [indexedAccessRetainsIndexSignature.js]
var o = { b: '' };

View File

@ -24,10 +24,39 @@ type Omit<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>
>U : Symbol(U, Decl(indexedAccessRetainsIndexSignature.ts, 2, 10))
>K : Symbol(K, Decl(indexedAccessRetainsIndexSignature.ts, 2, 12))
type Omit1<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>;
>Omit1 : Symbol(Omit1, Decl(indexedAccessRetainsIndexSignature.ts, 2, 59))
>U : Symbol(U, Decl(indexedAccessRetainsIndexSignature.ts, 3, 11))
>K : Symbol(K, Decl(indexedAccessRetainsIndexSignature.ts, 3, 13))
>U : Symbol(U, Decl(indexedAccessRetainsIndexSignature.ts, 3, 11))
>Pick : Symbol(Pick, Decl(lib.d.ts, --, --))
>U : Symbol(U, Decl(indexedAccessRetainsIndexSignature.ts, 3, 11))
>Diff : Symbol(Diff, Decl(indexedAccessRetainsIndexSignature.ts, 0, 0))
>U : Symbol(U, Decl(indexedAccessRetainsIndexSignature.ts, 3, 11))
>K : Symbol(K, Decl(indexedAccessRetainsIndexSignature.ts, 3, 13))
// is in fact an equivalent of
type Omit2<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]};
>Omit2 : Symbol(Omit2, Decl(indexedAccessRetainsIndexSignature.ts, 3, 61))
>T : Symbol(T, Decl(indexedAccessRetainsIndexSignature.ts, 6, 11))
>K : Symbol(K, Decl(indexedAccessRetainsIndexSignature.ts, 6, 13))
>T : Symbol(T, Decl(indexedAccessRetainsIndexSignature.ts, 6, 11))
>P : Symbol(P, Decl(indexedAccessRetainsIndexSignature.ts, 6, 37))
>Diff : Symbol(Diff, Decl(indexedAccessRetainsIndexSignature.ts, 0, 0))
>T : Symbol(T, Decl(indexedAccessRetainsIndexSignature.ts, 6, 11))
>K : Symbol(K, Decl(indexedAccessRetainsIndexSignature.ts, 6, 13))
>T : Symbol(T, Decl(indexedAccessRetainsIndexSignature.ts, 6, 11))
>P : Symbol(P, Decl(indexedAccessRetainsIndexSignature.ts, 6, 37))
type O = Omit<{ a: number, b: string }, 'a'>
>O : Symbol(O, Decl(indexedAccessRetainsIndexSignature.ts, 2, 59))
>O : Symbol(O, Decl(indexedAccessRetainsIndexSignature.ts, 6, 67))
>Omit : Symbol(Omit, Decl(indexedAccessRetainsIndexSignature.ts, 1, 71))
>a : Symbol(a, Decl(indexedAccessRetainsIndexSignature.ts, 5, 15))
>b : Symbol(b, Decl(indexedAccessRetainsIndexSignature.ts, 5, 26))
>a : Symbol(a, Decl(indexedAccessRetainsIndexSignature.ts, 8, 15))
>b : Symbol(b, Decl(indexedAccessRetainsIndexSignature.ts, 8, 26))
const o: O = { b: '' }
>o : Symbol(o, Decl(indexedAccessRetainsIndexSignature.ts, 9, 5))
>O : Symbol(O, Decl(indexedAccessRetainsIndexSignature.ts, 6, 67))
>b : Symbol(b, Decl(indexedAccessRetainsIndexSignature.ts, 9, 14))

View File

@ -24,6 +24,30 @@ type Omit<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>
>U : U
>K : K
type Omit1<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>;
>Omit1 : Pick<U, ({ [P in T]: P; } & { [P in U]: never; } & { [x: string]: never; })[keyof U]>
>U : U
>K : K
>U : U
>Pick : Pick<T, K>
>U : U
>Diff : ({ [P in T]: P; } & { [P in U]: never; } & { [x: string]: never; })[T]
>U : U
>K : K
// is in fact an equivalent of
type Omit2<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]};
>Omit2 : Omit2<T, K>
>T : T
>K : K
>T : T
>P : P
>Diff : ({ [P in T]: P; } & { [P in U]: never; } & { [x: string]: never; })[T]
>T : T
>K : K
>T : T
>P : P
type O = Omit<{ a: number, b: string }, 'a'>
>O : Pick<{ a: number; b: string; }, "b">
@ -31,3 +55,10 @@ type O = Omit<{ a: number, b: string }, 'a'>
>a : number
>b : string
const o: O = { b: '' }
>o : Pick<{ a: number; b: string; }, "b">
>O : Pick<{ a: number; b: string; }, "b">
>{ b: '' } : { b: string; }
>b : string
>'' : ""

View File

@ -1,6 +1,10 @@
type Diff<T extends string, U extends string> =
({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T]
type Omit<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>
type Omit1<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>;
// is in fact an equivalent of
type Omit2<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]};
type O = Omit<{ a: number, b: string }, 'a'>
const o: O = { b: '' }