Make T[never] = never instead of erroring or being any (#22787)

* Add tests showing existing behavior for indexing types with never.

* Make T[never] = never instead of erroring or being any.

And update the baselines for the tests for this change.

* Add test case for indexing an expression with never showing existing behavior.

* Make indexing an object with never expression result in never.

And update baseline to reflect new behavior.
This commit is contained in:
Kevin Donnelly 2018-03-27 09:45:25 -05:00 committed by Nathan Shively-Sanders
parent dcbc478efa
commit 4fa96056ea
5 changed files with 1028 additions and 0 deletions

View File

@ -8151,6 +8151,9 @@ namespace ts {
}
return indexInfo.type;
}
if (indexType.flags & TypeFlags.Never) {
return neverType;
}
if (accessExpression && !isConstEnumObjectType(objectType)) {
if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) {
if (getIndexTypeOfType(objectType, IndexKind.Number)) {

View File

@ -0,0 +1,121 @@
//// [indexingTypesWithNever.ts]
type TestObj = {
a: string;
b: number;
};
// Should be never but without an error
type Result1 = TestObj[never];
type EmptyObj = {};
// Should be never but without an error
type Result2 = EmptyObj[keyof EmptyObj];
declare function genericFn1<T>(obj: T): T[never];
// Should be never
const result3 = genericFn1({ c: "ctest", d: "dtest" });
declare function genericFn2<T extends { [ind: string]: string }>(
obj: T
): T[never];
// Should be never
const result4 = genericFn2({ e: "etest", f: "ftest" });
declare function genericFn3<
T extends { [K in keyof T]: T[K] },
U extends keyof T,
V extends keyof T
>(obj: T, u: U, v: V): T[U & V];
// Should be never
const result5 = genericFn3({ g: "gtest", h: "htest" }, "g", "h"); // 'g' & 'h' will reduce to never
declare const obj: {a: string, b: number}
declare const key: never
const result6 = obj[key]
// Expanded examples from https://github.com/Microsoft/TypeScript/issues/21988
type RequiredPropNames<T> = {
[P in keyof T]-?: undefined extends T[P] ? never : P
}[keyof T];
type OptionalPropNames<T> = {
[P in keyof T]-?: undefined extends T[P] ? P : never
}[keyof T];
type RequiredProps<T> = { [P in RequiredPropNames<T>]: T[P] };
type OptionalProps<T> = { [P in OptionalPropNames<T>]?: T[P] };
type Match<Exp, Act> = [Exp] extends [Act]
? ([Act] extends [Exp] ? "Match" : "Did not match 2")
: "Did not match 1";
type ExpectType<Exp, Act> = Match<Exp, Act> extends "Match"
? ({} extends Exp ? Match<Required<Exp>, Required<Act>> : "Match")
: "Did not match";
type P3 = { a: string; b: number; c?: boolean };
type P2 = { a: string; c?: boolean };
type P1 = { c?: boolean };
type P0 = {};
type P3Names = RequiredPropNames<P3>; // expect 'a' | 'b'
type P2Names = RequiredPropNames<P2>; // expect 'a'
type P1Names = RequiredPropNames<P1>; // expect never
type P0Names = RequiredPropNames<P0>; // expect never
declare const p3NameTest: ExpectType<"a" | "b", P3Names>;
declare const p2NameTest: ExpectType<"a", P2Names>;
declare const p1NameTest: ExpectType<never, P1Names>;
declare const p0NameTest: ExpectType<never, P0Names>;
type P3Props = RequiredProps<P3>; // expect { a: string; b: number }
type P2Props = RequiredProps<P2>; // expect { a: string; }
type P1Props = RequiredProps<P1>; // expect {}
type P0Props = RequiredProps<P0>; // expect {}
declare const p3Test: ExpectType<{ a: string; b: number }, P3Props>;
declare const p2Test: ExpectType<{ a: string }, P2Props>;
declare const p1Test: ExpectType<{}, P1Props>;
declare const p0Test: ExpectType<{}, P0Props>;
type O3 = { a?: string; b?: number; c: boolean };
type O2 = { a?: string; c: boolean };
type O1 = { c: boolean };
type O0 = {};
type O3Names = OptionalPropNames<O3>; // expect 'a' | 'b'
type O2Names = OptionalPropNames<O2>; // expect 'a'
type O1Names = OptionalPropNames<O1>; // expect never
type O0Names = OptionalPropNames<O0>; // expect never
declare const o3NameTest: ExpectType<"a" | "b", O3Names>;
declare const o2NameTest: ExpectType<"a", O2Names>;
declare const o1NameTest: ExpectType<never, O1Names>;
declare const o0NameTest: ExpectType<never, O0Names>;
type O3Props = OptionalProps<O3>; // expect { a?: string | undefined; b?: number | undefined }
type O2Props = OptionalProps<O2>; // expect { a?: string | undefined; }
type O1Props = OptionalProps<O1>; // expect {}
type O0Props = OptionalProps<O0>; // expect {}
declare const o3Test: ExpectType<{ a?: string; b?: number }, O3Props>;
declare const o2Test: ExpectType<{ a?: string }, O2Props>;
declare const o1Test: ExpectType<{}, O1Props>;
declare const o0Test: ExpectType<{}, O0Props>;
//// [indexingTypesWithNever.js]
"use strict";
// Should be never
var result3 = genericFn1({ c: "ctest", d: "dtest" });
// Should be never
var result4 = genericFn2({ e: "etest", f: "ftest" });
// Should be never
var result5 = genericFn3({ g: "gtest", h: "htest" }, "g", "h"); // 'g' & 'h' will reduce to never
var result6 = obj[key];

View File

@ -0,0 +1,389 @@
=== tests/cases/compiler/indexingTypesWithNever.ts ===
type TestObj = {
>TestObj : Symbol(TestObj, Decl(indexingTypesWithNever.ts, 0, 0))
a: string;
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 0, 16))
b: number;
>b : Symbol(b, Decl(indexingTypesWithNever.ts, 1, 12))
};
// Should be never but without an error
type Result1 = TestObj[never];
>Result1 : Symbol(Result1, Decl(indexingTypesWithNever.ts, 3, 2))
>TestObj : Symbol(TestObj, Decl(indexingTypesWithNever.ts, 0, 0))
type EmptyObj = {};
>EmptyObj : Symbol(EmptyObj, Decl(indexingTypesWithNever.ts, 6, 30))
// Should be never but without an error
type Result2 = EmptyObj[keyof EmptyObj];
>Result2 : Symbol(Result2, Decl(indexingTypesWithNever.ts, 8, 19))
>EmptyObj : Symbol(EmptyObj, Decl(indexingTypesWithNever.ts, 6, 30))
>EmptyObj : Symbol(EmptyObj, Decl(indexingTypesWithNever.ts, 6, 30))
declare function genericFn1<T>(obj: T): T[never];
>genericFn1 : Symbol(genericFn1, Decl(indexingTypesWithNever.ts, 11, 40))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 13, 28))
>obj : Symbol(obj, Decl(indexingTypesWithNever.ts, 13, 31))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 13, 28))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 13, 28))
// Should be never
const result3 = genericFn1({ c: "ctest", d: "dtest" });
>result3 : Symbol(result3, Decl(indexingTypesWithNever.ts, 16, 5))
>genericFn1 : Symbol(genericFn1, Decl(indexingTypesWithNever.ts, 11, 40))
>c : Symbol(c, Decl(indexingTypesWithNever.ts, 16, 28))
>d : Symbol(d, Decl(indexingTypesWithNever.ts, 16, 40))
declare function genericFn2<T extends { [ind: string]: string }>(
>genericFn2 : Symbol(genericFn2, Decl(indexingTypesWithNever.ts, 16, 55))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 18, 28))
>ind : Symbol(ind, Decl(indexingTypesWithNever.ts, 18, 41))
obj: T
>obj : Symbol(obj, Decl(indexingTypesWithNever.ts, 18, 65))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 18, 28))
): T[never];
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 18, 28))
// Should be never
const result4 = genericFn2({ e: "etest", f: "ftest" });
>result4 : Symbol(result4, Decl(indexingTypesWithNever.ts, 23, 5))
>genericFn2 : Symbol(genericFn2, Decl(indexingTypesWithNever.ts, 16, 55))
>e : Symbol(e, Decl(indexingTypesWithNever.ts, 23, 28))
>f : Symbol(f, Decl(indexingTypesWithNever.ts, 23, 40))
declare function genericFn3<
>genericFn3 : Symbol(genericFn3, Decl(indexingTypesWithNever.ts, 23, 55))
T extends { [K in keyof T]: T[K] },
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 25, 28))
>K : Symbol(K, Decl(indexingTypesWithNever.ts, 26, 15))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 25, 28))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 25, 28))
>K : Symbol(K, Decl(indexingTypesWithNever.ts, 26, 15))
U extends keyof T,
>U : Symbol(U, Decl(indexingTypesWithNever.ts, 26, 37))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 25, 28))
V extends keyof T
>V : Symbol(V, Decl(indexingTypesWithNever.ts, 27, 20))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 25, 28))
>(obj: T, u: U, v: V): T[U & V];
>obj : Symbol(obj, Decl(indexingTypesWithNever.ts, 29, 2))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 25, 28))
>u : Symbol(u, Decl(indexingTypesWithNever.ts, 29, 9))
>U : Symbol(U, Decl(indexingTypesWithNever.ts, 26, 37))
>v : Symbol(v, Decl(indexingTypesWithNever.ts, 29, 15))
>V : Symbol(V, Decl(indexingTypesWithNever.ts, 27, 20))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 25, 28))
>U : Symbol(U, Decl(indexingTypesWithNever.ts, 26, 37))
>V : Symbol(V, Decl(indexingTypesWithNever.ts, 27, 20))
// Should be never
const result5 = genericFn3({ g: "gtest", h: "htest" }, "g", "h"); // 'g' & 'h' will reduce to never
>result5 : Symbol(result5, Decl(indexingTypesWithNever.ts, 32, 5))
>genericFn3 : Symbol(genericFn3, Decl(indexingTypesWithNever.ts, 23, 55))
>g : Symbol(g, Decl(indexingTypesWithNever.ts, 32, 28))
>h : Symbol(h, Decl(indexingTypesWithNever.ts, 32, 40))
declare const obj: {a: string, b: number}
>obj : Symbol(obj, Decl(indexingTypesWithNever.ts, 35, 13))
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 35, 20))
>b : Symbol(b, Decl(indexingTypesWithNever.ts, 35, 30))
declare const key: never
>key : Symbol(key, Decl(indexingTypesWithNever.ts, 36, 13))
const result6 = obj[key]
>result6 : Symbol(result6, Decl(indexingTypesWithNever.ts, 38, 5))
>obj : Symbol(obj, Decl(indexingTypesWithNever.ts, 35, 13))
>key : Symbol(key, Decl(indexingTypesWithNever.ts, 36, 13))
// Expanded examples from https://github.com/Microsoft/TypeScript/issues/21988
type RequiredPropNames<T> = {
>RequiredPropNames : Symbol(RequiredPropNames, Decl(indexingTypesWithNever.ts, 38, 24))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 41, 23))
[P in keyof T]-?: undefined extends T[P] ? never : P
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 42, 3))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 41, 23))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 41, 23))
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 42, 3))
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 42, 3))
}[keyof T];
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 41, 23))
type OptionalPropNames<T> = {
>OptionalPropNames : Symbol(OptionalPropNames, Decl(indexingTypesWithNever.ts, 43, 11))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 45, 23))
[P in keyof T]-?: undefined extends T[P] ? P : never
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 46, 3))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 45, 23))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 45, 23))
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 46, 3))
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 46, 3))
}[keyof T];
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 45, 23))
type RequiredProps<T> = { [P in RequiredPropNames<T>]: T[P] };
>RequiredProps : Symbol(RequiredProps, Decl(indexingTypesWithNever.ts, 47, 11))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 49, 19))
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 49, 27))
>RequiredPropNames : Symbol(RequiredPropNames, Decl(indexingTypesWithNever.ts, 38, 24))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 49, 19))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 49, 19))
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 49, 27))
type OptionalProps<T> = { [P in OptionalPropNames<T>]?: T[P] };
>OptionalProps : Symbol(OptionalProps, Decl(indexingTypesWithNever.ts, 49, 62))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 50, 19))
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 50, 27))
>OptionalPropNames : Symbol(OptionalPropNames, Decl(indexingTypesWithNever.ts, 43, 11))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 50, 19))
>T : Symbol(T, Decl(indexingTypesWithNever.ts, 50, 19))
>P : Symbol(P, Decl(indexingTypesWithNever.ts, 50, 27))
type Match<Exp, Act> = [Exp] extends [Act]
>Match : Symbol(Match, Decl(indexingTypesWithNever.ts, 50, 63))
>Exp : Symbol(Exp, Decl(indexingTypesWithNever.ts, 52, 11))
>Act : Symbol(Act, Decl(indexingTypesWithNever.ts, 52, 15))
>Exp : Symbol(Exp, Decl(indexingTypesWithNever.ts, 52, 11))
>Act : Symbol(Act, Decl(indexingTypesWithNever.ts, 52, 15))
? ([Act] extends [Exp] ? "Match" : "Did not match 2")
>Act : Symbol(Act, Decl(indexingTypesWithNever.ts, 52, 15))
>Exp : Symbol(Exp, Decl(indexingTypesWithNever.ts, 52, 11))
: "Did not match 1";
type ExpectType<Exp, Act> = Match<Exp, Act> extends "Match"
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>Exp : Symbol(Exp, Decl(indexingTypesWithNever.ts, 56, 16))
>Act : Symbol(Act, Decl(indexingTypesWithNever.ts, 56, 20))
>Match : Symbol(Match, Decl(indexingTypesWithNever.ts, 50, 63))
>Exp : Symbol(Exp, Decl(indexingTypesWithNever.ts, 56, 16))
>Act : Symbol(Act, Decl(indexingTypesWithNever.ts, 56, 20))
? ({} extends Exp ? Match<Required<Exp>, Required<Act>> : "Match")
>Exp : Symbol(Exp, Decl(indexingTypesWithNever.ts, 56, 16))
>Match : Symbol(Match, Decl(indexingTypesWithNever.ts, 50, 63))
>Required : Symbol(Required, Decl(lib.d.ts, --, --))
>Exp : Symbol(Exp, Decl(indexingTypesWithNever.ts, 56, 16))
>Required : Symbol(Required, Decl(lib.d.ts, --, --))
>Act : Symbol(Act, Decl(indexingTypesWithNever.ts, 56, 20))
: "Did not match";
type P3 = { a: string; b: number; c?: boolean };
>P3 : Symbol(P3, Decl(indexingTypesWithNever.ts, 58, 20))
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 60, 11))
>b : Symbol(b, Decl(indexingTypesWithNever.ts, 60, 22))
>c : Symbol(c, Decl(indexingTypesWithNever.ts, 60, 33))
type P2 = { a: string; c?: boolean };
>P2 : Symbol(P2, Decl(indexingTypesWithNever.ts, 60, 48))
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 61, 11))
>c : Symbol(c, Decl(indexingTypesWithNever.ts, 61, 22))
type P1 = { c?: boolean };
>P1 : Symbol(P1, Decl(indexingTypesWithNever.ts, 61, 37))
>c : Symbol(c, Decl(indexingTypesWithNever.ts, 62, 11))
type P0 = {};
>P0 : Symbol(P0, Decl(indexingTypesWithNever.ts, 62, 26))
type P3Names = RequiredPropNames<P3>; // expect 'a' | 'b'
>P3Names : Symbol(P3Names, Decl(indexingTypesWithNever.ts, 63, 13))
>RequiredPropNames : Symbol(RequiredPropNames, Decl(indexingTypesWithNever.ts, 38, 24))
>P3 : Symbol(P3, Decl(indexingTypesWithNever.ts, 58, 20))
type P2Names = RequiredPropNames<P2>; // expect 'a'
>P2Names : Symbol(P2Names, Decl(indexingTypesWithNever.ts, 65, 37))
>RequiredPropNames : Symbol(RequiredPropNames, Decl(indexingTypesWithNever.ts, 38, 24))
>P2 : Symbol(P2, Decl(indexingTypesWithNever.ts, 60, 48))
type P1Names = RequiredPropNames<P1>; // expect never
>P1Names : Symbol(P1Names, Decl(indexingTypesWithNever.ts, 66, 37))
>RequiredPropNames : Symbol(RequiredPropNames, Decl(indexingTypesWithNever.ts, 38, 24))
>P1 : Symbol(P1, Decl(indexingTypesWithNever.ts, 61, 37))
type P0Names = RequiredPropNames<P0>; // expect never
>P0Names : Symbol(P0Names, Decl(indexingTypesWithNever.ts, 67, 37))
>RequiredPropNames : Symbol(RequiredPropNames, Decl(indexingTypesWithNever.ts, 38, 24))
>P0 : Symbol(P0, Decl(indexingTypesWithNever.ts, 62, 26))
declare const p3NameTest: ExpectType<"a" | "b", P3Names>;
>p3NameTest : Symbol(p3NameTest, Decl(indexingTypesWithNever.ts, 70, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>P3Names : Symbol(P3Names, Decl(indexingTypesWithNever.ts, 63, 13))
declare const p2NameTest: ExpectType<"a", P2Names>;
>p2NameTest : Symbol(p2NameTest, Decl(indexingTypesWithNever.ts, 71, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>P2Names : Symbol(P2Names, Decl(indexingTypesWithNever.ts, 65, 37))
declare const p1NameTest: ExpectType<never, P1Names>;
>p1NameTest : Symbol(p1NameTest, Decl(indexingTypesWithNever.ts, 72, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>P1Names : Symbol(P1Names, Decl(indexingTypesWithNever.ts, 66, 37))
declare const p0NameTest: ExpectType<never, P0Names>;
>p0NameTest : Symbol(p0NameTest, Decl(indexingTypesWithNever.ts, 73, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>P0Names : Symbol(P0Names, Decl(indexingTypesWithNever.ts, 67, 37))
type P3Props = RequiredProps<P3>; // expect { a: string; b: number }
>P3Props : Symbol(P3Props, Decl(indexingTypesWithNever.ts, 73, 53))
>RequiredProps : Symbol(RequiredProps, Decl(indexingTypesWithNever.ts, 47, 11))
>P3 : Symbol(P3, Decl(indexingTypesWithNever.ts, 58, 20))
type P2Props = RequiredProps<P2>; // expect { a: string; }
>P2Props : Symbol(P2Props, Decl(indexingTypesWithNever.ts, 75, 33))
>RequiredProps : Symbol(RequiredProps, Decl(indexingTypesWithNever.ts, 47, 11))
>P2 : Symbol(P2, Decl(indexingTypesWithNever.ts, 60, 48))
type P1Props = RequiredProps<P1>; // expect {}
>P1Props : Symbol(P1Props, Decl(indexingTypesWithNever.ts, 76, 33))
>RequiredProps : Symbol(RequiredProps, Decl(indexingTypesWithNever.ts, 47, 11))
>P1 : Symbol(P1, Decl(indexingTypesWithNever.ts, 61, 37))
type P0Props = RequiredProps<P0>; // expect {}
>P0Props : Symbol(P0Props, Decl(indexingTypesWithNever.ts, 77, 33))
>RequiredProps : Symbol(RequiredProps, Decl(indexingTypesWithNever.ts, 47, 11))
>P0 : Symbol(P0, Decl(indexingTypesWithNever.ts, 62, 26))
declare const p3Test: ExpectType<{ a: string; b: number }, P3Props>;
>p3Test : Symbol(p3Test, Decl(indexingTypesWithNever.ts, 80, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 80, 34))
>b : Symbol(b, Decl(indexingTypesWithNever.ts, 80, 45))
>P3Props : Symbol(P3Props, Decl(indexingTypesWithNever.ts, 73, 53))
declare const p2Test: ExpectType<{ a: string }, P2Props>;
>p2Test : Symbol(p2Test, Decl(indexingTypesWithNever.ts, 81, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 81, 34))
>P2Props : Symbol(P2Props, Decl(indexingTypesWithNever.ts, 75, 33))
declare const p1Test: ExpectType<{}, P1Props>;
>p1Test : Symbol(p1Test, Decl(indexingTypesWithNever.ts, 82, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>P1Props : Symbol(P1Props, Decl(indexingTypesWithNever.ts, 76, 33))
declare const p0Test: ExpectType<{}, P0Props>;
>p0Test : Symbol(p0Test, Decl(indexingTypesWithNever.ts, 83, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>P0Props : Symbol(P0Props, Decl(indexingTypesWithNever.ts, 77, 33))
type O3 = { a?: string; b?: number; c: boolean };
>O3 : Symbol(O3, Decl(indexingTypesWithNever.ts, 83, 46))
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 85, 11))
>b : Symbol(b, Decl(indexingTypesWithNever.ts, 85, 23))
>c : Symbol(c, Decl(indexingTypesWithNever.ts, 85, 35))
type O2 = { a?: string; c: boolean };
>O2 : Symbol(O2, Decl(indexingTypesWithNever.ts, 85, 49))
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 86, 11))
>c : Symbol(c, Decl(indexingTypesWithNever.ts, 86, 23))
type O1 = { c: boolean };
>O1 : Symbol(O1, Decl(indexingTypesWithNever.ts, 86, 37))
>c : Symbol(c, Decl(indexingTypesWithNever.ts, 87, 11))
type O0 = {};
>O0 : Symbol(O0, Decl(indexingTypesWithNever.ts, 87, 25))
type O3Names = OptionalPropNames<O3>; // expect 'a' | 'b'
>O3Names : Symbol(O3Names, Decl(indexingTypesWithNever.ts, 88, 13))
>OptionalPropNames : Symbol(OptionalPropNames, Decl(indexingTypesWithNever.ts, 43, 11))
>O3 : Symbol(O3, Decl(indexingTypesWithNever.ts, 83, 46))
type O2Names = OptionalPropNames<O2>; // expect 'a'
>O2Names : Symbol(O2Names, Decl(indexingTypesWithNever.ts, 90, 37))
>OptionalPropNames : Symbol(OptionalPropNames, Decl(indexingTypesWithNever.ts, 43, 11))
>O2 : Symbol(O2, Decl(indexingTypesWithNever.ts, 85, 49))
type O1Names = OptionalPropNames<O1>; // expect never
>O1Names : Symbol(O1Names, Decl(indexingTypesWithNever.ts, 91, 37))
>OptionalPropNames : Symbol(OptionalPropNames, Decl(indexingTypesWithNever.ts, 43, 11))
>O1 : Symbol(O1, Decl(indexingTypesWithNever.ts, 86, 37))
type O0Names = OptionalPropNames<O0>; // expect never
>O0Names : Symbol(O0Names, Decl(indexingTypesWithNever.ts, 92, 37))
>OptionalPropNames : Symbol(OptionalPropNames, Decl(indexingTypesWithNever.ts, 43, 11))
>O0 : Symbol(O0, Decl(indexingTypesWithNever.ts, 87, 25))
declare const o3NameTest: ExpectType<"a" | "b", O3Names>;
>o3NameTest : Symbol(o3NameTest, Decl(indexingTypesWithNever.ts, 95, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>O3Names : Symbol(O3Names, Decl(indexingTypesWithNever.ts, 88, 13))
declare const o2NameTest: ExpectType<"a", O2Names>;
>o2NameTest : Symbol(o2NameTest, Decl(indexingTypesWithNever.ts, 96, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>O2Names : Symbol(O2Names, Decl(indexingTypesWithNever.ts, 90, 37))
declare const o1NameTest: ExpectType<never, O1Names>;
>o1NameTest : Symbol(o1NameTest, Decl(indexingTypesWithNever.ts, 97, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>O1Names : Symbol(O1Names, Decl(indexingTypesWithNever.ts, 91, 37))
declare const o0NameTest: ExpectType<never, O0Names>;
>o0NameTest : Symbol(o0NameTest, Decl(indexingTypesWithNever.ts, 98, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>O0Names : Symbol(O0Names, Decl(indexingTypesWithNever.ts, 92, 37))
type O3Props = OptionalProps<O3>; // expect { a?: string | undefined; b?: number | undefined }
>O3Props : Symbol(O3Props, Decl(indexingTypesWithNever.ts, 98, 53))
>OptionalProps : Symbol(OptionalProps, Decl(indexingTypesWithNever.ts, 49, 62))
>O3 : Symbol(O3, Decl(indexingTypesWithNever.ts, 83, 46))
type O2Props = OptionalProps<O2>; // expect { a?: string | undefined; }
>O2Props : Symbol(O2Props, Decl(indexingTypesWithNever.ts, 100, 33))
>OptionalProps : Symbol(OptionalProps, Decl(indexingTypesWithNever.ts, 49, 62))
>O2 : Symbol(O2, Decl(indexingTypesWithNever.ts, 85, 49))
type O1Props = OptionalProps<O1>; // expect {}
>O1Props : Symbol(O1Props, Decl(indexingTypesWithNever.ts, 101, 33))
>OptionalProps : Symbol(OptionalProps, Decl(indexingTypesWithNever.ts, 49, 62))
>O1 : Symbol(O1, Decl(indexingTypesWithNever.ts, 86, 37))
type O0Props = OptionalProps<O0>; // expect {}
>O0Props : Symbol(O0Props, Decl(indexingTypesWithNever.ts, 102, 33))
>OptionalProps : Symbol(OptionalProps, Decl(indexingTypesWithNever.ts, 49, 62))
>O0 : Symbol(O0, Decl(indexingTypesWithNever.ts, 87, 25))
declare const o3Test: ExpectType<{ a?: string; b?: number }, O3Props>;
>o3Test : Symbol(o3Test, Decl(indexingTypesWithNever.ts, 105, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 105, 34))
>b : Symbol(b, Decl(indexingTypesWithNever.ts, 105, 46))
>O3Props : Symbol(O3Props, Decl(indexingTypesWithNever.ts, 98, 53))
declare const o2Test: ExpectType<{ a?: string }, O2Props>;
>o2Test : Symbol(o2Test, Decl(indexingTypesWithNever.ts, 106, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>a : Symbol(a, Decl(indexingTypesWithNever.ts, 106, 34))
>O2Props : Symbol(O2Props, Decl(indexingTypesWithNever.ts, 100, 33))
declare const o1Test: ExpectType<{}, O1Props>;
>o1Test : Symbol(o1Test, Decl(indexingTypesWithNever.ts, 107, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>O1Props : Symbol(O1Props, Decl(indexingTypesWithNever.ts, 101, 33))
declare const o0Test: ExpectType<{}, O0Props>;
>o0Test : Symbol(o0Test, Decl(indexingTypesWithNever.ts, 108, 13))
>ExpectType : Symbol(ExpectType, Decl(indexingTypesWithNever.ts, 54, 22))
>O0Props : Symbol(O0Props, Decl(indexingTypesWithNever.ts, 102, 33))

View File

@ -0,0 +1,404 @@
=== tests/cases/compiler/indexingTypesWithNever.ts ===
type TestObj = {
>TestObj : TestObj
a: string;
>a : string
b: number;
>b : number
};
// Should be never but without an error
type Result1 = TestObj[never];
>Result1 : never
>TestObj : TestObj
type EmptyObj = {};
>EmptyObj : EmptyObj
// Should be never but without an error
type Result2 = EmptyObj[keyof EmptyObj];
>Result2 : never
>EmptyObj : EmptyObj
>EmptyObj : EmptyObj
declare function genericFn1<T>(obj: T): T[never];
>genericFn1 : <T>(obj: T) => T[never]
>T : T
>obj : T
>T : T
>T : T
// Should be never
const result3 = genericFn1({ c: "ctest", d: "dtest" });
>result3 : never
>genericFn1({ c: "ctest", d: "dtest" }) : never
>genericFn1 : <T>(obj: T) => T[never]
>{ c: "ctest", d: "dtest" } : { c: string; d: string; }
>c : string
>"ctest" : "ctest"
>d : string
>"dtest" : "dtest"
declare function genericFn2<T extends { [ind: string]: string }>(
>genericFn2 : <T extends { [ind: string]: string; }>(obj: T) => T[never]
>T : T
>ind : string
obj: T
>obj : T
>T : T
): T[never];
>T : T
// Should be never
const result4 = genericFn2({ e: "etest", f: "ftest" });
>result4 : never
>genericFn2({ e: "etest", f: "ftest" }) : never
>genericFn2 : <T extends { [ind: string]: string; }>(obj: T) => T[never]
>{ e: "etest", f: "ftest" } : { e: string; f: string; }
>e : string
>"etest" : "etest"
>f : string
>"ftest" : "ftest"
declare function genericFn3<
>genericFn3 : <T extends { [K in keyof T]: T[K]; }, U extends keyof T, V extends keyof T>(obj: T, u: U, v: V) => T[U & V]
T extends { [K in keyof T]: T[K] },
>T : T
>K : K
>T : T
>T : T
>K : K
U extends keyof T,
>U : U
>T : T
V extends keyof T
>V : V
>T : T
>(obj: T, u: U, v: V): T[U & V];
>obj : T
>T : T
>u : U
>U : U
>v : V
>V : V
>T : T
>U : U
>V : V
// Should be never
const result5 = genericFn3({ g: "gtest", h: "htest" }, "g", "h"); // 'g' & 'h' will reduce to never
>result5 : any
>genericFn3({ g: "gtest", h: "htest" }, "g", "h") : any
>genericFn3 : <T extends { [K in keyof T]: T[K]; }, U extends keyof T, V extends keyof T>(obj: T, u: U, v: V) => T[U & V]
>{ g: "gtest", h: "htest" } : { g: string; h: string; }
>g : string
>"gtest" : "gtest"
>h : string
>"htest" : "htest"
>"g" : "g"
>"h" : "h"
declare const obj: {a: string, b: number}
>obj : { a: string; b: number; }
>a : string
>b : number
declare const key: never
>key : never
const result6 = obj[key]
>result6 : never
>obj[key] : never
>obj : { a: string; b: number; }
>key : never
// Expanded examples from https://github.com/Microsoft/TypeScript/issues/21988
type RequiredPropNames<T> = {
>RequiredPropNames : { [P in keyof T]-?: undefined extends T[P] ? never : P; }[keyof T]
>T : T
[P in keyof T]-?: undefined extends T[P] ? never : P
>P : P
>T : T
>T : T
>P : P
>P : P
}[keyof T];
>T : T
type OptionalPropNames<T> = {
>OptionalPropNames : { [P in keyof T]-?: undefined extends T[P] ? P : never; }[keyof T]
>T : T
[P in keyof T]-?: undefined extends T[P] ? P : never
>P : P
>T : T
>T : T
>P : P
>P : P
}[keyof T];
>T : T
type RequiredProps<T> = { [P in RequiredPropNames<T>]: T[P] };
>RequiredProps : RequiredProps<T>
>T : T
>P : P
>RequiredPropNames : { [P in keyof T]-?: undefined extends T[P] ? never : P; }[keyof T]
>T : T
>T : T
>P : P
type OptionalProps<T> = { [P in OptionalPropNames<T>]?: T[P] };
>OptionalProps : OptionalProps<T>
>T : T
>P : P
>OptionalPropNames : { [P in keyof T]-?: undefined extends T[P] ? P : never; }[keyof T]
>T : T
>T : T
>P : P
type Match<Exp, Act> = [Exp] extends [Act]
>Match : Match<Exp, Act>
>Exp : Exp
>Act : Act
>Exp : Exp
>Act : Act
? ([Act] extends [Exp] ? "Match" : "Did not match 2")
>Act : Act
>Exp : Exp
: "Did not match 1";
type ExpectType<Exp, Act> = Match<Exp, Act> extends "Match"
>ExpectType : ExpectType<Exp, Act>
>Exp : Exp
>Act : Act
>Match : Match<Exp, Act>
>Exp : Exp
>Act : Act
? ({} extends Exp ? Match<Required<Exp>, Required<Act>> : "Match")
>Exp : Exp
>Match : Match<Exp, Act>
>Required : Required<T>
>Exp : Exp
>Required : Required<T>
>Act : Act
: "Did not match";
type P3 = { a: string; b: number; c?: boolean };
>P3 : P3
>a : string
>b : number
>c : boolean | undefined
type P2 = { a: string; c?: boolean };
>P2 : P2
>a : string
>c : boolean | undefined
type P1 = { c?: boolean };
>P1 : P1
>c : boolean | undefined
type P0 = {};
>P0 : P0
type P3Names = RequiredPropNames<P3>; // expect 'a' | 'b'
>P3Names : "a" | "b"
>RequiredPropNames : { [P in keyof T]-?: undefined extends T[P] ? never : P; }[keyof T]
>P3 : P3
type P2Names = RequiredPropNames<P2>; // expect 'a'
>P2Names : "a"
>RequiredPropNames : { [P in keyof T]-?: undefined extends T[P] ? never : P; }[keyof T]
>P2 : P2
type P1Names = RequiredPropNames<P1>; // expect never
>P1Names : never
>RequiredPropNames : { [P in keyof T]-?: undefined extends T[P] ? never : P; }[keyof T]
>P1 : P1
type P0Names = RequiredPropNames<P0>; // expect never
>P0Names : never
>RequiredPropNames : { [P in keyof T]-?: undefined extends T[P] ? never : P; }[keyof T]
>P0 : P0
declare const p3NameTest: ExpectType<"a" | "b", P3Names>;
>p3NameTest : "Match"
>ExpectType : ExpectType<Exp, Act>
>P3Names : "a" | "b"
declare const p2NameTest: ExpectType<"a", P2Names>;
>p2NameTest : "Match"
>ExpectType : ExpectType<Exp, Act>
>P2Names : "a"
declare const p1NameTest: ExpectType<never, P1Names>;
>p1NameTest : "Match"
>ExpectType : ExpectType<Exp, Act>
>P1Names : never
declare const p0NameTest: ExpectType<never, P0Names>;
>p0NameTest : "Match"
>ExpectType : ExpectType<Exp, Act>
>P0Names : never
type P3Props = RequiredProps<P3>; // expect { a: string; b: number }
>P3Props : RequiredProps<P3>
>RequiredProps : RequiredProps<T>
>P3 : P3
type P2Props = RequiredProps<P2>; // expect { a: string; }
>P2Props : RequiredProps<P2>
>RequiredProps : RequiredProps<T>
>P2 : P2
type P1Props = RequiredProps<P1>; // expect {}
>P1Props : RequiredProps<P1>
>RequiredProps : RequiredProps<T>
>P1 : P1
type P0Props = RequiredProps<P0>; // expect {}
>P0Props : RequiredProps<P0>
>RequiredProps : RequiredProps<T>
>P0 : P0
declare const p3Test: ExpectType<{ a: string; b: number }, P3Props>;
>p3Test : "Match"
>ExpectType : ExpectType<Exp, Act>
>a : string
>b : number
>P3Props : RequiredProps<P3>
declare const p2Test: ExpectType<{ a: string }, P2Props>;
>p2Test : "Match"
>ExpectType : ExpectType<Exp, Act>
>a : string
>P2Props : RequiredProps<P2>
declare const p1Test: ExpectType<{}, P1Props>;
>p1Test : "Match"
>ExpectType : ExpectType<Exp, Act>
>P1Props : RequiredProps<P1>
declare const p0Test: ExpectType<{}, P0Props>;
>p0Test : "Match"
>ExpectType : ExpectType<Exp, Act>
>P0Props : RequiredProps<P0>
type O3 = { a?: string; b?: number; c: boolean };
>O3 : O3
>a : string | undefined
>b : number | undefined
>c : boolean
type O2 = { a?: string; c: boolean };
>O2 : O2
>a : string | undefined
>c : boolean
type O1 = { c: boolean };
>O1 : O1
>c : boolean
type O0 = {};
>O0 : O0
type O3Names = OptionalPropNames<O3>; // expect 'a' | 'b'
>O3Names : "a" | "b"
>OptionalPropNames : { [P in keyof T]-?: undefined extends T[P] ? P : never; }[keyof T]
>O3 : O3
type O2Names = OptionalPropNames<O2>; // expect 'a'
>O2Names : "a"
>OptionalPropNames : { [P in keyof T]-?: undefined extends T[P] ? P : never; }[keyof T]
>O2 : O2
type O1Names = OptionalPropNames<O1>; // expect never
>O1Names : never
>OptionalPropNames : { [P in keyof T]-?: undefined extends T[P] ? P : never; }[keyof T]
>O1 : O1
type O0Names = OptionalPropNames<O0>; // expect never
>O0Names : never
>OptionalPropNames : { [P in keyof T]-?: undefined extends T[P] ? P : never; }[keyof T]
>O0 : O0
declare const o3NameTest: ExpectType<"a" | "b", O3Names>;
>o3NameTest : "Match"
>ExpectType : ExpectType<Exp, Act>
>O3Names : "a" | "b"
declare const o2NameTest: ExpectType<"a", O2Names>;
>o2NameTest : "Match"
>ExpectType : ExpectType<Exp, Act>
>O2Names : "a"
declare const o1NameTest: ExpectType<never, O1Names>;
>o1NameTest : "Match"
>ExpectType : ExpectType<Exp, Act>
>O1Names : never
declare const o0NameTest: ExpectType<never, O0Names>;
>o0NameTest : "Match"
>ExpectType : ExpectType<Exp, Act>
>O0Names : never
type O3Props = OptionalProps<O3>; // expect { a?: string | undefined; b?: number | undefined }
>O3Props : OptionalProps<O3>
>OptionalProps : OptionalProps<T>
>O3 : O3
type O2Props = OptionalProps<O2>; // expect { a?: string | undefined; }
>O2Props : OptionalProps<O2>
>OptionalProps : OptionalProps<T>
>O2 : O2
type O1Props = OptionalProps<O1>; // expect {}
>O1Props : OptionalProps<O1>
>OptionalProps : OptionalProps<T>
>O1 : O1
type O0Props = OptionalProps<O0>; // expect {}
>O0Props : OptionalProps<O0>
>OptionalProps : OptionalProps<T>
>O0 : O0
declare const o3Test: ExpectType<{ a?: string; b?: number }, O3Props>;
>o3Test : "Match"
>ExpectType : ExpectType<Exp, Act>
>a : string | undefined
>b : number | undefined
>O3Props : OptionalProps<O3>
declare const o2Test: ExpectType<{ a?: string }, O2Props>;
>o2Test : "Match"
>ExpectType : ExpectType<Exp, Act>
>a : string | undefined
>O2Props : OptionalProps<O2>
declare const o1Test: ExpectType<{}, O1Props>;
>o1Test : "Match"
>ExpectType : ExpectType<Exp, Act>
>O1Props : OptionalProps<O1>
declare const o0Test: ExpectType<{}, O0Props>;
>o0Test : "Match"
>ExpectType : ExpectType<Exp, Act>
>O0Props : OptionalProps<O0>

View File

@ -0,0 +1,111 @@
// @strict: true
type TestObj = {
a: string;
b: number;
};
// Should be never but without an error
type Result1 = TestObj[never];
type EmptyObj = {};
// Should be never but without an error
type Result2 = EmptyObj[keyof EmptyObj];
declare function genericFn1<T>(obj: T): T[never];
// Should be never
const result3 = genericFn1({ c: "ctest", d: "dtest" });
declare function genericFn2<T extends { [ind: string]: string }>(
obj: T
): T[never];
// Should be never
const result4 = genericFn2({ e: "etest", f: "ftest" });
declare function genericFn3<
T extends { [K in keyof T]: T[K] },
U extends keyof T,
V extends keyof T
>(obj: T, u: U, v: V): T[U & V];
// Should be never
const result5 = genericFn3({ g: "gtest", h: "htest" }, "g", "h"); // 'g' & 'h' will reduce to never
declare const obj: {a: string, b: number}
declare const key: never
const result6 = obj[key]
// Expanded examples from https://github.com/Microsoft/TypeScript/issues/21988
type RequiredPropNames<T> = {
[P in keyof T]-?: undefined extends T[P] ? never : P
}[keyof T];
type OptionalPropNames<T> = {
[P in keyof T]-?: undefined extends T[P] ? P : never
}[keyof T];
type RequiredProps<T> = { [P in RequiredPropNames<T>]: T[P] };
type OptionalProps<T> = { [P in OptionalPropNames<T>]?: T[P] };
type Match<Exp, Act> = [Exp] extends [Act]
? ([Act] extends [Exp] ? "Match" : "Did not match 2")
: "Did not match 1";
type ExpectType<Exp, Act> = Match<Exp, Act> extends "Match"
? ({} extends Exp ? Match<Required<Exp>, Required<Act>> : "Match")
: "Did not match";
type P3 = { a: string; b: number; c?: boolean };
type P2 = { a: string; c?: boolean };
type P1 = { c?: boolean };
type P0 = {};
type P3Names = RequiredPropNames<P3>; // expect 'a' | 'b'
type P2Names = RequiredPropNames<P2>; // expect 'a'
type P1Names = RequiredPropNames<P1>; // expect never
type P0Names = RequiredPropNames<P0>; // expect never
declare const p3NameTest: ExpectType<"a" | "b", P3Names>;
declare const p2NameTest: ExpectType<"a", P2Names>;
declare const p1NameTest: ExpectType<never, P1Names>;
declare const p0NameTest: ExpectType<never, P0Names>;
type P3Props = RequiredProps<P3>; // expect { a: string; b: number }
type P2Props = RequiredProps<P2>; // expect { a: string; }
type P1Props = RequiredProps<P1>; // expect {}
type P0Props = RequiredProps<P0>; // expect {}
declare const p3Test: ExpectType<{ a: string; b: number }, P3Props>;
declare const p2Test: ExpectType<{ a: string }, P2Props>;
declare const p1Test: ExpectType<{}, P1Props>;
declare const p0Test: ExpectType<{}, P0Props>;
type O3 = { a?: string; b?: number; c: boolean };
type O2 = { a?: string; c: boolean };
type O1 = { c: boolean };
type O0 = {};
type O3Names = OptionalPropNames<O3>; // expect 'a' | 'b'
type O2Names = OptionalPropNames<O2>; // expect 'a'
type O1Names = OptionalPropNames<O1>; // expect never
type O0Names = OptionalPropNames<O0>; // expect never
declare const o3NameTest: ExpectType<"a" | "b", O3Names>;
declare const o2NameTest: ExpectType<"a", O2Names>;
declare const o1NameTest: ExpectType<never, O1Names>;
declare const o0NameTest: ExpectType<never, O0Names>;
type O3Props = OptionalProps<O3>; // expect { a?: string | undefined; b?: number | undefined }
type O2Props = OptionalProps<O2>; // expect { a?: string | undefined; }
type O1Props = OptionalProps<O1>; // expect {}
type O0Props = OptionalProps<O0>; // expect {}
declare const o3Test: ExpectType<{ a?: string; b?: number }, O3Props>;
declare const o2Test: ExpectType<{ a?: string }, O2Props>;
declare const o1Test: ExpectType<{}, O1Props>;
declare const o0Test: ExpectType<{}, O0Props>;