* Treat never-like intersections as never * Accept new baselines * Fix compiler issues revealed by increased intersection correctness * Delete fourslash tests that are no longer applicable * Include isNeverLikeIntersection check in getNormalizedType * Erase never-like types in several more places * Check that base types are not never-like * Add comments * Revert isNeverLikeType check in getIndexType (keyof shouldn't resolve member types) * Introduce getReducedType for union and intersection types * Don't reduce in getApparentType * Avoid relationship check in resolveMappedTypeMembers * Accept new baselines * Don't call getReducedType in getIndexType * Ensure reduced and unreduced forms of a type can compare identical * Reduce types before converting them to string representation * Accept new baselines * Reduce intersections before obtaining keyof X * Add tests * Accept new baselines * Fix comment in tests * Don't infer from empty intersection types * Add tests * Accept new baselines * Defer instantiation of mapped type property types * Accept new baselines * Include more precise type in diagnostic * Accept new baselines * Minor optimization * Improve error message * Optional properties in intersections are never discriminants
145 lines
2.7 KiB
TypeScript
145 lines
2.7 KiB
TypeScript
// @strict: true
|
|
|
|
function f10(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
|
|
if (x.kind === false) {
|
|
x.a;
|
|
}
|
|
else if (x.kind === true) {
|
|
x.b;
|
|
}
|
|
else {
|
|
x.c;
|
|
}
|
|
}
|
|
|
|
function f11(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
|
|
switch (x.kind) {
|
|
case false:
|
|
x.a;
|
|
break;
|
|
case true:
|
|
x.b;
|
|
break;
|
|
default:
|
|
x.c;
|
|
}
|
|
}
|
|
|
|
function f13(x: { a: null; b: string } | { a: string, c: number }) {
|
|
x = { a: null, b: "foo", c: 4}; // Error
|
|
}
|
|
|
|
function f14<T>(x: { a: 0; b: string } | { a: T, c: number }) {
|
|
if (x.a === 0) {
|
|
x.b; // Error
|
|
}
|
|
}
|
|
|
|
type Result<T> = { error?: undefined, value: T } | { error: Error };
|
|
|
|
function f15(x: Result<number>) {
|
|
if (!x.error) {
|
|
x.value;
|
|
}
|
|
else {
|
|
x.error.message;
|
|
}
|
|
}
|
|
|
|
f15({ value: 10 });
|
|
f15({ error: new Error("boom") });
|
|
|
|
// Repro from #24193
|
|
|
|
interface WithError {
|
|
error: Error
|
|
data: null
|
|
}
|
|
|
|
interface WithoutError<Data> {
|
|
error: null
|
|
data: Data
|
|
}
|
|
|
|
type DataCarrier<Data> = WithError | WithoutError<Data>
|
|
|
|
function f20<Data>(carrier: DataCarrier<Data>) {
|
|
if (carrier.error === null) {
|
|
const error: null = carrier.error
|
|
const data: Data = carrier.data
|
|
} else {
|
|
const error: Error = carrier.error
|
|
const data: null = carrier.data
|
|
}
|
|
}
|
|
|
|
// Repro from #28935
|
|
|
|
type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string };
|
|
|
|
function f30(foo: Foo) {
|
|
if (foo.tag) {
|
|
foo;
|
|
}
|
|
else {
|
|
foo;
|
|
}
|
|
}
|
|
|
|
function f31(foo: Foo) {
|
|
if (foo.tag === true) {
|
|
foo;
|
|
}
|
|
else {
|
|
foo;
|
|
}
|
|
}
|
|
|
|
// Repro from #33448
|
|
|
|
type a = {
|
|
type: 'a',
|
|
data: string
|
|
}
|
|
type b = {
|
|
type: 'b',
|
|
name: string
|
|
}
|
|
type c = {
|
|
type: 'c',
|
|
other: string
|
|
}
|
|
|
|
type abc = a | b | c;
|
|
|
|
function f(problem: abc & (b | c)) {
|
|
if (problem.type === 'b') {
|
|
problem.name;
|
|
}
|
|
else {
|
|
problem.other;
|
|
}
|
|
}
|
|
|
|
type RuntimeValue =
|
|
| { type: 'number', value: number }
|
|
| { type: 'string', value: string }
|
|
| { type: 'boolean', value: boolean };
|
|
|
|
function foo1(x: RuntimeValue & { type: 'number' }) {
|
|
if (x.type === 'number') {
|
|
x.value; // number
|
|
}
|
|
else {
|
|
x.value; // number
|
|
}
|
|
}
|
|
|
|
function foo2(x: RuntimeValue & ({ type: 'number' } | { type: 'string' })) {
|
|
if (x.type === 'number') {
|
|
x.value; // number
|
|
}
|
|
else {
|
|
x.value; // string
|
|
}
|
|
}
|