mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-08 18:11:45 -06:00
Component commits: 0edae127ae Reduce void | undefined only in conjunction with subtype reduction 6b487a6db5 Accept new baselines e7b6601de7 Add regression test Co-authored-by: Anders Hejlsberg <andersh@microsoft.com>
This commit is contained in:
parent
16f2556473
commit
57ba6ddaee
@ -13358,7 +13358,7 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function removeRedundantLiteralTypes(types: Type[], includes: TypeFlags) {
|
||||
function removeRedundantLiteralTypes(types: Type[], includes: TypeFlags, reduceVoidUndefined: boolean) {
|
||||
let i = types.length;
|
||||
while (i > 0) {
|
||||
i--;
|
||||
@ -13369,7 +13369,7 @@ namespace ts {
|
||||
flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number ||
|
||||
flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt ||
|
||||
flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol ||
|
||||
flags & TypeFlags.Undefined && includes & TypeFlags.Void ||
|
||||
reduceVoidUndefined && flags & TypeFlags.Undefined && includes & TypeFlags.Void ||
|
||||
isFreshLiteralType(t) && containsType(types, (<LiteralType>t).regularType);
|
||||
if (remove) {
|
||||
orderedRemoveItemAt(types, i);
|
||||
@ -13437,7 +13437,7 @@ namespace ts {
|
||||
}
|
||||
if (unionReduction & (UnionReduction.Literal | UnionReduction.Subtype)) {
|
||||
if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol) || includes & TypeFlags.Void && includes & TypeFlags.Undefined) {
|
||||
removeRedundantLiteralTypes(typeSet, includes);
|
||||
removeRedundantLiteralTypes(typeSet, includes, !!(unionReduction & UnionReduction.Subtype));
|
||||
}
|
||||
if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) {
|
||||
removeStringLiteralsMatchedByTemplateLiterals(typeSet);
|
||||
|
||||
@ -260,7 +260,7 @@ declare const o5: <T>() => undefined | (() => void);
|
||||
>o5 : <T>() => undefined | (() => void)
|
||||
|
||||
o5<number>()?.();
|
||||
>o5<number>()?.() : void
|
||||
>o5<number>()?.() : void | undefined
|
||||
>o5<number>() : (() => void) | undefined
|
||||
>o5 : <T>() => (() => void) | undefined
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ if (value) {
|
||||
}
|
||||
|
||||
value?.foo("a");
|
||||
>value?.foo("a") : void
|
||||
>value?.foo("a") : void | undefined
|
||||
>value?.foo : (<T>(this: T, arg: keyof T) => void) | undefined
|
||||
>value : Y | undefined
|
||||
>foo : (<T>(this: T, arg: keyof T) => void) | undefined
|
||||
|
||||
@ -595,7 +595,7 @@ function f01(x: unknown) {
|
||||
>true : true
|
||||
|
||||
maybeIsString?.(x);
|
||||
>maybeIsString?.(x) : void
|
||||
>maybeIsString?.(x) : void | undefined
|
||||
>maybeIsString : ((value: unknown) => asserts value is string) | undefined
|
||||
>x : unknown
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ class C extends B {
|
||||
>body : () => void
|
||||
|
||||
super.m && super.m();
|
||||
>super.m && super.m() : void
|
||||
>super.m && super.m() : void | undefined
|
||||
>super.m : (() => void) | undefined
|
||||
>super : B
|
||||
>m : (() => void) | undefined
|
||||
|
||||
@ -343,7 +343,7 @@ const u: U = {} as any;
|
||||
>{} : {}
|
||||
|
||||
u.a && u.b && f(u.a, u.b);
|
||||
>u.a && u.b && f(u.a, u.b) : void | ""
|
||||
>u.a && u.b && f(u.a, u.b) : void | "" | undefined
|
||||
>u.a && u.b : string | undefined
|
||||
>u.a : string | undefined
|
||||
>u : U
|
||||
@ -361,7 +361,7 @@ u.a && u.b && f(u.a, u.b);
|
||||
>b : string
|
||||
|
||||
u.b && u.a && f(u.a, u.b);
|
||||
>u.b && u.a && f(u.a, u.b) : void | ""
|
||||
>u.b && u.a && f(u.a, u.b) : void | "" | undefined
|
||||
>u.b && u.a : string | undefined
|
||||
>u.b : string | undefined
|
||||
>u : U
|
||||
|
||||
@ -888,8 +888,8 @@ const p75 = p.then(() => undefined, () => null);
|
||||
>null : null
|
||||
|
||||
const p76 = p.then(() => undefined, () => {});
|
||||
>p76 : Promise<void>
|
||||
>p.then(() => undefined, () => {}) : Promise<void>
|
||||
>p76 : Promise<void | undefined>
|
||||
>p.then(() => undefined, () => {}) : Promise<void | undefined>
|
||||
>p.then : <TResult1 = boolean, TResult2 = never>(onfulfilled?: ((value: boolean) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
|
||||
>p : Promise<boolean>
|
||||
>then : <TResult1 = boolean, TResult2 = never>(onfulfilled?: ((value: boolean) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
|
||||
@ -1092,8 +1092,8 @@ const p93 = p.then(() => {}, () => x);
|
||||
>x : any
|
||||
|
||||
const p94 = p.then(() => {}, () => undefined);
|
||||
>p94 : Promise<void>
|
||||
>p.then(() => {}, () => undefined) : Promise<void>
|
||||
>p94 : Promise<void | undefined>
|
||||
>p.then(() => {}, () => undefined) : Promise<void | undefined>
|
||||
>p.then : <TResult1 = boolean, TResult2 = never>(onfulfilled?: ((value: boolean) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
|
||||
>p : Promise<boolean>
|
||||
>then : <TResult1 = boolean, TResult2 = never>(onfulfilled?: ((value: boolean) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
|
||||
|
||||
@ -11,20 +11,20 @@ class Derived extends Base {
|
||||
>Base : Base
|
||||
|
||||
method() {
|
||||
>method : () => void
|
||||
>method : () => void | undefined
|
||||
|
||||
return super.method?.();
|
||||
>super.method?.() : void
|
||||
>super.method?.() : void | undefined
|
||||
>super.method : (() => void) | undefined
|
||||
>super : Base
|
||||
>method : (() => void) | undefined
|
||||
}
|
||||
|
||||
async asyncMethod() {
|
||||
>asyncMethod : () => Promise<void>
|
||||
>asyncMethod : () => Promise<void | undefined>
|
||||
|
||||
return super.method?.();
|
||||
>super.method?.() : void
|
||||
>super.method?.() : void | undefined
|
||||
>super.method : (() => void) | undefined
|
||||
>super : Base
|
||||
>method : (() => void) | undefined
|
||||
|
||||
@ -9,7 +9,7 @@ class C {
|
||||
>other : () => void
|
||||
|
||||
this.method?.();
|
||||
>this.method?.() : void
|
||||
>this.method?.() : void | undefined
|
||||
>this.method : (() => void) | undefined
|
||||
>this : this
|
||||
>method : (() => void) | undefined
|
||||
|
||||
@ -60,7 +60,7 @@ function test(required1: () => boolean, required2: () => boolean, b: boolean, op
|
||||
|
||||
// ok
|
||||
optional && console.log('optional');
|
||||
>optional && console.log('optional') : void
|
||||
>optional && console.log('optional') : void | undefined
|
||||
>optional : (() => boolean) | undefined
|
||||
>console.log('optional') : void
|
||||
>console.log : (...data: any[]) => void
|
||||
@ -70,7 +70,7 @@ function test(required1: () => boolean, required2: () => boolean, b: boolean, op
|
||||
|
||||
// ok
|
||||
1 && optional && console.log('optional');
|
||||
>1 && optional && console.log('optional') : void
|
||||
>1 && optional && console.log('optional') : void | undefined
|
||||
>1 && optional : (() => boolean) | undefined
|
||||
>1 : 1
|
||||
>optional : (() => boolean) | undefined
|
||||
@ -441,7 +441,7 @@ class Foo {
|
||||
|
||||
// ok
|
||||
1 && this.optional && console.log('optional');
|
||||
>1 && this.optional && console.log('optional') : void
|
||||
>1 && this.optional && console.log('optional') : void | undefined
|
||||
>1 && this.optional : (() => boolean) | undefined
|
||||
>1 : 1
|
||||
>this.optional : (() => boolean) | undefined
|
||||
|
||||
@ -16,7 +16,7 @@ class A<P extends Partial<Foo>> {
|
||||
>doSomething : () => void
|
||||
|
||||
this.props.foo && this.props.foo()
|
||||
>this.props.foo && this.props.foo() : void
|
||||
>this.props.foo && this.props.foo() : void | undefined
|
||||
>this.props.foo : P["foo"] | undefined
|
||||
>this.props : Readonly<P>
|
||||
>this : this
|
||||
|
||||
@ -51,7 +51,7 @@ function bad<P extends Props>(props: Readonly<P>) {
|
||||
// ERROR HERE!!!
|
||||
// Type R in signature of safeInvoke incorrectly inferred as {} instead of void!
|
||||
safeInvoke(props.onBar, "blah");
|
||||
>safeInvoke(props.onBar, "blah") : void
|
||||
>safeInvoke(props.onBar, "blah") : void | undefined
|
||||
>safeInvoke : <A1, R>(func: ((arg1: A1) => R) | null | undefined, arg1: A1) => R | undefined
|
||||
>props.onBar : P["onBar"] | undefined
|
||||
>props : Readonly<P>
|
||||
|
||||
23
tests/baselines/reference/voidUndefinedReduction.js
Normal file
23
tests/baselines/reference/voidUndefinedReduction.js
Normal file
@ -0,0 +1,23 @@
|
||||
//// [voidUndefinedReduction.ts]
|
||||
// Repro from #42786
|
||||
|
||||
function isDefined<T>(value: T | undefined | null | void): value is T {
|
||||
return value !== undefined && value !== null;
|
||||
}
|
||||
|
||||
declare const foo: string | undefined;
|
||||
|
||||
if (isDefined(foo)) {
|
||||
console.log(foo.toUpperCase());
|
||||
}
|
||||
|
||||
|
||||
//// [voidUndefinedReduction.js]
|
||||
"use strict";
|
||||
// Repro from #42786
|
||||
function isDefined(value) {
|
||||
return value !== undefined && value !== null;
|
||||
}
|
||||
if (isDefined(foo)) {
|
||||
console.log(foo.toUpperCase());
|
||||
}
|
||||
33
tests/baselines/reference/voidUndefinedReduction.symbols
Normal file
33
tests/baselines/reference/voidUndefinedReduction.symbols
Normal file
@ -0,0 +1,33 @@
|
||||
=== tests/cases/compiler/voidUndefinedReduction.ts ===
|
||||
// Repro from #42786
|
||||
|
||||
function isDefined<T>(value: T | undefined | null | void): value is T {
|
||||
>isDefined : Symbol(isDefined, Decl(voidUndefinedReduction.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(voidUndefinedReduction.ts, 2, 19))
|
||||
>value : Symbol(value, Decl(voidUndefinedReduction.ts, 2, 22))
|
||||
>T : Symbol(T, Decl(voidUndefinedReduction.ts, 2, 19))
|
||||
>value : Symbol(value, Decl(voidUndefinedReduction.ts, 2, 22))
|
||||
>T : Symbol(T, Decl(voidUndefinedReduction.ts, 2, 19))
|
||||
|
||||
return value !== undefined && value !== null;
|
||||
>value : Symbol(value, Decl(voidUndefinedReduction.ts, 2, 22))
|
||||
>undefined : Symbol(undefined)
|
||||
>value : Symbol(value, Decl(voidUndefinedReduction.ts, 2, 22))
|
||||
}
|
||||
|
||||
declare const foo: string | undefined;
|
||||
>foo : Symbol(foo, Decl(voidUndefinedReduction.ts, 6, 13))
|
||||
|
||||
if (isDefined(foo)) {
|
||||
>isDefined : Symbol(isDefined, Decl(voidUndefinedReduction.ts, 0, 0))
|
||||
>foo : Symbol(foo, Decl(voidUndefinedReduction.ts, 6, 13))
|
||||
|
||||
console.log(foo.toUpperCase());
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>foo.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
>foo : Symbol(foo, Decl(voidUndefinedReduction.ts, 6, 13))
|
||||
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
|
||||
}
|
||||
|
||||
37
tests/baselines/reference/voidUndefinedReduction.types
Normal file
37
tests/baselines/reference/voidUndefinedReduction.types
Normal file
@ -0,0 +1,37 @@
|
||||
=== tests/cases/compiler/voidUndefinedReduction.ts ===
|
||||
// Repro from #42786
|
||||
|
||||
function isDefined<T>(value: T | undefined | null | void): value is T {
|
||||
>isDefined : <T>(value: T | undefined | null | void) => value is T
|
||||
>value : void | T | null | undefined
|
||||
>null : null
|
||||
|
||||
return value !== undefined && value !== null;
|
||||
>value !== undefined && value !== null : boolean
|
||||
>value !== undefined : boolean
|
||||
>value : void | T | null | undefined
|
||||
>undefined : undefined
|
||||
>value !== null : boolean
|
||||
>value : T | null
|
||||
>null : null
|
||||
}
|
||||
|
||||
declare const foo: string | undefined;
|
||||
>foo : string | undefined
|
||||
|
||||
if (isDefined(foo)) {
|
||||
>isDefined(foo) : boolean
|
||||
>isDefined : <T>(value: void | T | null | undefined) => value is T
|
||||
>foo : string | undefined
|
||||
|
||||
console.log(foo.toUpperCase());
|
||||
>console.log(foo.toUpperCase()) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>foo.toUpperCase() : string
|
||||
>foo.toUpperCase : () => string
|
||||
>foo : string
|
||||
>toUpperCase : () => string
|
||||
}
|
||||
|
||||
13
tests/cases/compiler/voidUndefinedReduction.ts
Normal file
13
tests/cases/compiler/voidUndefinedReduction.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// @strict: true
|
||||
|
||||
// Repro from #42786
|
||||
|
||||
function isDefined<T>(value: T | undefined | null | void): value is T {
|
||||
return value !== undefined && value !== null;
|
||||
}
|
||||
|
||||
declare const foo: string | undefined;
|
||||
|
||||
if (isDefined(foo)) {
|
||||
console.log(foo.toUpperCase());
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user