Merge pull request #21947 from Microsoft/fixKeyofWildcard

Fix issue with 'keyof T' and conditional types
This commit is contained in:
Anders Hejlsberg 2018-02-15 12:44:51 -08:00 committed by GitHub
commit 0f697c376b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 316 additions and 0 deletions

View File

@ -7949,6 +7949,7 @@ namespace ts {
function getIndexType(type: Type): Type {
return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type) :
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
type === wildcardType ? wildcardType :
type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType :
getLiteralTypeFromPropertyNames(type);
}

View File

@ -447,4 +447,34 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(275,43): error TS
type A = Omit<{ a: void; b: never; }>; // 'a'
type B = Omit2<{ a: void; b: never; }>; // 'a'
}
// Repro from #21862
type OldDiff<T extends string, U extends string> = (
& { [P in T]: P; }
& { [P in U]: never; }
& { [x: string]: never; }
)[T];
type NewDiff<T, U> = T extends U ? never : T;
interface A {
a: 'a';
}
interface B1 extends A {
b: 'b';
c: OldDiff<keyof this, keyof A>;
}
interface B2 extends A {
b: 'b';
c: NewDiff<keyof this, keyof A>;
}
type c1 = B1['c']; // 'c' | 'b'
type c2 = B2['c']; // 'c' | 'b'
// Repro from #21929
type NonFooKeys1<T extends object> = OldDiff<keyof T, 'foo'>;
type NonFooKeys2<T extends object> = Exclude<keyof T, 'foo'>;
type Test1 = NonFooKeys1<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"
type Test2 = NonFooKeys2<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"

View File

@ -285,6 +285,36 @@ function f50() {
type A = Omit<{ a: void; b: never; }>; // 'a'
type B = Omit2<{ a: void; b: never; }>; // 'a'
}
// Repro from #21862
type OldDiff<T extends string, U extends string> = (
& { [P in T]: P; }
& { [P in U]: never; }
& { [x: string]: never; }
)[T];
type NewDiff<T, U> = T extends U ? never : T;
interface A {
a: 'a';
}
interface B1 extends A {
b: 'b';
c: OldDiff<keyof this, keyof A>;
}
interface B2 extends A {
b: 'b';
c: NewDiff<keyof this, keyof A>;
}
type c1 = B1['c']; // 'c' | 'b'
type c2 = B2['c']; // 'c' | 'b'
// Repro from #21929
type NonFooKeys1<T extends object> = OldDiff<keyof T, 'foo'>;
type NonFooKeys2<T extends object> = Exclude<keyof T, 'foo'>;
type Test1 = NonFooKeys1<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"
type Test2 = NonFooKeys2<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"
//// [conditionalTypes1.js]
@ -561,3 +591,36 @@ declare type T95<T> = T extends string ? boolean : number;
declare const f44: <U>(value: T94<U>) => T95<U>;
declare const f45: <U>(value: T95<U>) => T94<U>;
declare function f50(): void;
declare type OldDiff<T extends string, U extends string> = ({
[P in T]: P;
} & {
[P in U]: never;
} & {
[x: string]: never;
})[T];
declare type NewDiff<T, U> = T extends U ? never : T;
interface A {
a: 'a';
}
interface B1 extends A {
b: 'b';
c: OldDiff<keyof this, keyof A>;
}
interface B2 extends A {
b: 'b';
c: NewDiff<keyof this, keyof A>;
}
declare type c1 = B1['c'];
declare type c2 = B2['c'];
declare type NonFooKeys1<T extends object> = OldDiff<keyof T, 'foo'>;
declare type NonFooKeys2<T extends object> = Exclude<keyof T, 'foo'>;
declare type Test1 = NonFooKeys1<{
foo: 1;
bar: 2;
baz: 3;
}>;
declare type Test2 = NonFooKeys2<{
foo: 1;
bar: 2;
baz: 3;
}>;

View File

@ -1121,3 +1121,99 @@ function f50() {
>b : Symbol(b, Decl(conditionalTypes1.ts, 284, 29))
}
// Repro from #21862
type OldDiff<T extends string, U extends string> = (
>OldDiff : Symbol(OldDiff, Decl(conditionalTypes1.ts, 285, 1))
>T : Symbol(T, Decl(conditionalTypes1.ts, 289, 13))
>U : Symbol(U, Decl(conditionalTypes1.ts, 289, 30))
& { [P in T]: P; }
>P : Symbol(P, Decl(conditionalTypes1.ts, 290, 9))
>T : Symbol(T, Decl(conditionalTypes1.ts, 289, 13))
>P : Symbol(P, Decl(conditionalTypes1.ts, 290, 9))
& { [P in U]: never; }
>P : Symbol(P, Decl(conditionalTypes1.ts, 291, 9))
>U : Symbol(U, Decl(conditionalTypes1.ts, 289, 30))
& { [x: string]: never; }
>x : Symbol(x, Decl(conditionalTypes1.ts, 292, 9))
)[T];
>T : Symbol(T, Decl(conditionalTypes1.ts, 289, 13))
type NewDiff<T, U> = T extends U ? never : T;
>NewDiff : Symbol(NewDiff, Decl(conditionalTypes1.ts, 293, 5))
>T : Symbol(T, Decl(conditionalTypes1.ts, 294, 13))
>U : Symbol(U, Decl(conditionalTypes1.ts, 294, 15))
>T : Symbol(T, Decl(conditionalTypes1.ts, 294, 13))
>U : Symbol(U, Decl(conditionalTypes1.ts, 294, 15))
>T : Symbol(T, Decl(conditionalTypes1.ts, 294, 13))
interface A {
>A : Symbol(A, Decl(conditionalTypes1.ts, 294, 45))
a: 'a';
>a : Symbol(A.a, Decl(conditionalTypes1.ts, 295, 13))
}
interface B1 extends A {
>B1 : Symbol(B1, Decl(conditionalTypes1.ts, 297, 1))
>A : Symbol(A, Decl(conditionalTypes1.ts, 294, 45))
b: 'b';
>b : Symbol(B1.b, Decl(conditionalTypes1.ts, 298, 24))
c: OldDiff<keyof this, keyof A>;
>c : Symbol(B1.c, Decl(conditionalTypes1.ts, 299, 11))
>OldDiff : Symbol(OldDiff, Decl(conditionalTypes1.ts, 285, 1))
>A : Symbol(A, Decl(conditionalTypes1.ts, 294, 45))
}
interface B2 extends A {
>B2 : Symbol(B2, Decl(conditionalTypes1.ts, 301, 1))
>A : Symbol(A, Decl(conditionalTypes1.ts, 294, 45))
b: 'b';
>b : Symbol(B2.b, Decl(conditionalTypes1.ts, 302, 24))
c: NewDiff<keyof this, keyof A>;
>c : Symbol(B2.c, Decl(conditionalTypes1.ts, 303, 11))
>NewDiff : Symbol(NewDiff, Decl(conditionalTypes1.ts, 293, 5))
>A : Symbol(A, Decl(conditionalTypes1.ts, 294, 45))
}
type c1 = B1['c']; // 'c' | 'b'
>c1 : Symbol(c1, Decl(conditionalTypes1.ts, 305, 1))
>B1 : Symbol(B1, Decl(conditionalTypes1.ts, 297, 1))
type c2 = B2['c']; // 'c' | 'b'
>c2 : Symbol(c2, Decl(conditionalTypes1.ts, 306, 18))
>B2 : Symbol(B2, Decl(conditionalTypes1.ts, 301, 1))
// Repro from #21929
type NonFooKeys1<T extends object> = OldDiff<keyof T, 'foo'>;
>NonFooKeys1 : Symbol(NonFooKeys1, Decl(conditionalTypes1.ts, 307, 18))
>T : Symbol(T, Decl(conditionalTypes1.ts, 311, 17))
>OldDiff : Symbol(OldDiff, Decl(conditionalTypes1.ts, 285, 1))
>T : Symbol(T, Decl(conditionalTypes1.ts, 311, 17))
type NonFooKeys2<T extends object> = Exclude<keyof T, 'foo'>;
>NonFooKeys2 : Symbol(NonFooKeys2, Decl(conditionalTypes1.ts, 311, 61))
>T : Symbol(T, Decl(conditionalTypes1.ts, 312, 17))
>Exclude : Symbol(Exclude, Decl(lib.d.ts, --, --))
>T : Symbol(T, Decl(conditionalTypes1.ts, 312, 17))
type Test1 = NonFooKeys1<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"
>Test1 : Symbol(Test1, Decl(conditionalTypes1.ts, 312, 61))
>NonFooKeys1 : Symbol(NonFooKeys1, Decl(conditionalTypes1.ts, 307, 18))
>foo : Symbol(foo, Decl(conditionalTypes1.ts, 314, 26))
>bar : Symbol(bar, Decl(conditionalTypes1.ts, 314, 33))
>baz : Symbol(baz, Decl(conditionalTypes1.ts, 314, 41))
type Test2 = NonFooKeys2<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"
>Test2 : Symbol(Test2, Decl(conditionalTypes1.ts, 314, 51))
>NonFooKeys2 : Symbol(NonFooKeys2, Decl(conditionalTypes1.ts, 311, 61))
>foo : Symbol(foo, Decl(conditionalTypes1.ts, 315, 26))
>bar : Symbol(bar, Decl(conditionalTypes1.ts, 315, 33))
>baz : Symbol(baz, Decl(conditionalTypes1.ts, 315, 41))

View File

@ -1274,3 +1274,99 @@ function f50() {
>b : never
}
// Repro from #21862
type OldDiff<T extends string, U extends string> = (
>OldDiff : ({ [P in T]: P; } & { [P in U]: never; } & { [x: string]: never; })[T]
>T : T
>U : U
& { [P in T]: P; }
>P : P
>T : T
>P : P
& { [P in U]: never; }
>P : P
>U : U
& { [x: string]: never; }
>x : string
)[T];
>T : T
type NewDiff<T, U> = T extends U ? never : T;
>NewDiff : NewDiff<T, U>
>T : T
>U : U
>T : T
>U : U
>T : T
interface A {
>A : A
a: 'a';
>a : "a"
}
interface B1 extends A {
>B1 : B1
>A : A
b: 'b';
>b : "b"
c: OldDiff<keyof this, keyof A>;
>c : ({ [P in keyof this]: P; } & { a: never; } & { [x: string]: never; })[keyof this]
>OldDiff : ({ [P in T]: P; } & { [P in U]: never; } & { [x: string]: never; })[T]
>A : A
}
interface B2 extends A {
>B2 : B2
>A : A
b: 'b';
>b : "b"
c: NewDiff<keyof this, keyof A>;
>c : NewDiff<keyof this, "a">
>NewDiff : NewDiff<T, U>
>A : A
}
type c1 = B1['c']; // 'c' | 'b'
>c1 : "b" | "c"
>B1 : B1
type c2 = B2['c']; // 'c' | 'b'
>c2 : "b" | "c"
>B2 : B2
// Repro from #21929
type NonFooKeys1<T extends object> = OldDiff<keyof T, 'foo'>;
>NonFooKeys1 : ({ [P in keyof T]: P; } & { foo: never; } & { [x: string]: never; })[keyof T]
>T : T
>OldDiff : ({ [P in T]: P; } & { [P in U]: never; } & { [x: string]: never; })[T]
>T : T
type NonFooKeys2<T extends object> = Exclude<keyof T, 'foo'>;
>NonFooKeys2 : Exclude<keyof T, "foo">
>T : T
>Exclude : Exclude<T, U>
>T : T
type Test1 = NonFooKeys1<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"
>Test1 : "bar" | "baz"
>NonFooKeys1 : ({ [P in keyof T]: P; } & { foo: never; } & { [x: string]: never; })[keyof T]
>foo : 1
>bar : 2
>baz : 3
type Test2 = NonFooKeys2<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"
>Test2 : "bar" | "baz"
>NonFooKeys2 : Exclude<keyof T, "foo">
>foo : 1
>bar : 2
>baz : 3

View File

@ -287,3 +287,33 @@ function f50() {
type A = Omit<{ a: void; b: never; }>; // 'a'
type B = Omit2<{ a: void; b: never; }>; // 'a'
}
// Repro from #21862
type OldDiff<T extends string, U extends string> = (
& { [P in T]: P; }
& { [P in U]: never; }
& { [x: string]: never; }
)[T];
type NewDiff<T, U> = T extends U ? never : T;
interface A {
a: 'a';
}
interface B1 extends A {
b: 'b';
c: OldDiff<keyof this, keyof A>;
}
interface B2 extends A {
b: 'b';
c: NewDiff<keyof this, keyof A>;
}
type c1 = B1['c']; // 'c' | 'b'
type c2 = B2['c']; // 'c' | 'b'
// Repro from #21929
type NonFooKeys1<T extends object> = OldDiff<keyof T, 'foo'>;
type NonFooKeys2<T extends object> = Exclude<keyof T, 'foo'>;
type Test1 = NonFooKeys1<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"
type Test2 = NonFooKeys2<{foo: 1, bar: 2, baz: 3}>; // "bar" | "baz"