Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 4 commits into from
Mar 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
121 changes: 121 additions & 0 deletions tests/baselines/reference/indexingTypesWithNever.js
Original file line number Diff line number Diff line change
@@ -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];
Loading