Normalize target type after null-stripping unions in relationship checks (#43202)

* Normalize target type after null-stripping

* Add regression tests
This commit is contained in:
Anders Hejlsberg 2021-03-19 09:19:25 -07:00 committed by GitHub
parent 451d4354b9
commit fbc9c942b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 186 additions and 2 deletions

View File

@ -17381,9 +17381,9 @@ namespace ts {
(target as UnionType).types.length <= 3 && maybeTypeOfKind(target, TypeFlags.Nullable)) {
const nullStrippedTarget = extractTypesOfKind(target, ~TypeFlags.Nullable);
if (!(nullStrippedTarget.flags & (TypeFlags.Union | TypeFlags.Never))) {
if (source === nullStrippedTarget) return Ternary.True;
target = nullStrippedTarget;
target = getNormalizedType(nullStrippedTarget, /*writing*/ true);
}
if (source === nullStrippedTarget) return Ternary.True;
}
if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||

View File

@ -0,0 +1,35 @@
//// [indexedAccessNormalization.ts]
// Repro from from #43152
type MyMap<M extends object> = {
[K in keyof M]: {
x: number
}
}
declare function g<T>(value?: T): void;
function f1<M extends object>(mymap: MyMap<M>, k: keyof M) {
const elemofM = mymap[k];
g(elemofM);
}
function f2<M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number }) {
const q1: MyMap<M>[keyof M] = z;
const q2: MyMap<M>[keyof M] | undefined = z;
const q3: MyMap<M>[keyof M] | string = z;
}
//// [indexedAccessNormalization.js]
"use strict";
// Repro from from #43152
function f1(mymap, k) {
var elemofM = mymap[k];
g(elemofM);
}
function f2(mymap, k, z) {
var q1 = z;
var q2 = z;
var q3 = z;
}

View File

@ -0,0 +1,74 @@
=== tests/cases/compiler/indexedAccessNormalization.ts ===
// Repro from from #43152
type MyMap<M extends object> = {
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 2, 11))
[K in keyof M]: {
>K : Symbol(K, Decl(indexedAccessNormalization.ts, 3, 5))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 2, 11))
x: number
>x : Symbol(x, Decl(indexedAccessNormalization.ts, 3, 21))
}
}
declare function g<T>(value?: T): void;
>g : Symbol(g, Decl(indexedAccessNormalization.ts, 6, 1))
>T : Symbol(T, Decl(indexedAccessNormalization.ts, 8, 19))
>value : Symbol(value, Decl(indexedAccessNormalization.ts, 8, 22))
>T : Symbol(T, Decl(indexedAccessNormalization.ts, 8, 19))
function f1<M extends object>(mymap: MyMap<M>, k: keyof M) {
>f1 : Symbol(f1, Decl(indexedAccessNormalization.ts, 8, 39))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 10, 12))
>mymap : Symbol(mymap, Decl(indexedAccessNormalization.ts, 10, 30))
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 10, 12))
>k : Symbol(k, Decl(indexedAccessNormalization.ts, 10, 46))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 10, 12))
const elemofM = mymap[k];
>elemofM : Symbol(elemofM, Decl(indexedAccessNormalization.ts, 11, 9))
>mymap : Symbol(mymap, Decl(indexedAccessNormalization.ts, 10, 30))
>k : Symbol(k, Decl(indexedAccessNormalization.ts, 10, 46))
g(elemofM);
>g : Symbol(g, Decl(indexedAccessNormalization.ts, 6, 1))
>elemofM : Symbol(elemofM, Decl(indexedAccessNormalization.ts, 11, 9))
}
function f2<M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number }) {
>f2 : Symbol(f2, Decl(indexedAccessNormalization.ts, 13, 1))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
>mymap : Symbol(mymap, Decl(indexedAccessNormalization.ts, 15, 30))
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
>k : Symbol(k, Decl(indexedAccessNormalization.ts, 15, 46))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
>z : Symbol(z, Decl(indexedAccessNormalization.ts, 15, 58))
>x : Symbol(x, Decl(indexedAccessNormalization.ts, 15, 63))
const q1: MyMap<M>[keyof M] = z;
>q1 : Symbol(q1, Decl(indexedAccessNormalization.ts, 16, 9))
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
>z : Symbol(z, Decl(indexedAccessNormalization.ts, 15, 58))
const q2: MyMap<M>[keyof M] | undefined = z;
>q2 : Symbol(q2, Decl(indexedAccessNormalization.ts, 17, 9))
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
>z : Symbol(z, Decl(indexedAccessNormalization.ts, 15, 58))
const q3: MyMap<M>[keyof M] | string = z;
>q3 : Symbol(q3, Decl(indexedAccessNormalization.ts, 18, 9))
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
>z : Symbol(z, Decl(indexedAccessNormalization.ts, 15, 58))
}

View File

@ -0,0 +1,53 @@
=== tests/cases/compiler/indexedAccessNormalization.ts ===
// Repro from from #43152
type MyMap<M extends object> = {
>MyMap : MyMap<M>
[K in keyof M]: {
x: number
>x : number
}
}
declare function g<T>(value?: T): void;
>g : <T>(value?: T | undefined) => void
>value : T | undefined
function f1<M extends object>(mymap: MyMap<M>, k: keyof M) {
>f1 : <M extends object>(mymap: MyMap<M>, k: keyof M) => void
>mymap : MyMap<M>
>k : keyof M
const elemofM = mymap[k];
>elemofM : MyMap<M>[keyof M]
>mymap[k] : MyMap<M>[keyof M]
>mymap : MyMap<M>
>k : keyof M
g(elemofM);
>g(elemofM) : void
>g : <T>(value?: T | undefined) => void
>elemofM : MyMap<M>[keyof M]
}
function f2<M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number }) {
>f2 : <M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number;}) => void
>mymap : MyMap<M>
>k : keyof M
>z : { x: number; }
>x : number
const q1: MyMap<M>[keyof M] = z;
>q1 : MyMap<M>[keyof M]
>z : { x: number; }
const q2: MyMap<M>[keyof M] | undefined = z;
>q2 : MyMap<M>[keyof M] | undefined
>z : { x: number; }
const q3: MyMap<M>[keyof M] | string = z;
>q3 : string | MyMap<M>[keyof M]
>z : { x: number; }
}

View File

@ -0,0 +1,22 @@
// @strict: true
// Repro from from #43152
type MyMap<M extends object> = {
[K in keyof M]: {
x: number
}
}
declare function g<T>(value?: T): void;
function f1<M extends object>(mymap: MyMap<M>, k: keyof M) {
const elemofM = mymap[k];
g(elemofM);
}
function f2<M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number }) {
const q1: MyMap<M>[keyof M] = z;
const q2: MyMap<M>[keyof M] | undefined = z;
const q3: MyMap<M>[keyof M] | string = z;
}