Skip to content

Commit 743f49a

Browse files
committed
Use homomorphic templated type for Omit
1 parent 203a5ce commit 743f49a

10 files changed

+103
-28
lines changed

Diff for: src/compiler/checker.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -17925,7 +17925,7 @@ namespace ts {
1792517925
}
1792617926
}
1792717927
}
17928-
else if (isGenericMappedType(target) && !target.declaration.nameType) {
17928+
else if (isGenericMappedType(target) && (!target.declaration.nameType || relation === comparableRelation)) {
1792917929
// A source type T is related to a target type { [P in X]: T[P] }
1793017930
const template = getTemplateTypeFromMappedType(target);
1793117931
const modifiers = getMappedTypeModifiers(target);
@@ -17935,7 +17935,7 @@ namespace ts {
1793517935
return Ternary.True;
1793617936
}
1793717937
if (!isGenericMappedType(source)) {
17938-
const targetConstraint = getConstraintTypeFromMappedType(target);
17938+
const targetConstraint = relation === comparableRelation ? getNameTypeFromMappedType(target) || getConstraintTypeFromMappedType(target) : getConstraintTypeFromMappedType(target);
1793917939
const sourceKeys = getIndexType(source, /*stringsOnly*/ undefined, /*noIndexSignatures*/ true);
1794017940
const includeOptional = modifiers & MappedTypeModifiers.IncludeOptional;
1794117941
const filteredByApplicability = includeOptional ? intersectTypes(targetConstraint, sourceKeys) : undefined;

Diff for: src/lib/es5.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1493,7 +1493,7 @@ type Extract<T, U> = T extends U ? T : never;
14931493
/**
14941494
* Construct a type with the properties of T except for those in type K.
14951495
*/
1496-
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
1496+
type Omit<T, K extends keyof any> = {[_K in keyof T as Exclude<_K, K>]: T[_K]};
14971497

14981498
/**
14991499
* Exclude null and undefined from T
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [omitOfTypeExtendingIndexSignature.ts]
2+
// #36981
3+
type AnyRecord = Record<string, any>;
4+
interface ExtendsAny extends AnyRecord {
5+
myKey1: string;
6+
myKey2: string;
7+
}
8+
9+
type OmitsKey = Omit<ExtendsAny, "myKey2">;
10+
type OmitsKey1 = OmitsKey["myKey1"]; // should be `string`
11+
type OmitsKey2 = OmitsKey["myKey2"]; // should be `any`
12+
13+
//// [omitOfTypeExtendingIndexSignature.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
=== tests/cases/compiler/omitOfTypeExtendingIndexSignature.ts ===
2+
// #36981
3+
type AnyRecord = Record<string, any>;
4+
>AnyRecord : Symbol(AnyRecord, Decl(omitOfTypeExtendingIndexSignature.ts, 0, 0))
5+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
6+
7+
interface ExtendsAny extends AnyRecord {
8+
>ExtendsAny : Symbol(ExtendsAny, Decl(omitOfTypeExtendingIndexSignature.ts, 1, 37))
9+
>AnyRecord : Symbol(AnyRecord, Decl(omitOfTypeExtendingIndexSignature.ts, 0, 0))
10+
11+
myKey1: string;
12+
>myKey1 : Symbol(ExtendsAny.myKey1, Decl(omitOfTypeExtendingIndexSignature.ts, 2, 40))
13+
14+
myKey2: string;
15+
>myKey2 : Symbol(ExtendsAny.myKey2, Decl(omitOfTypeExtendingIndexSignature.ts, 3, 19))
16+
}
17+
18+
type OmitsKey = Omit<ExtendsAny, "myKey2">;
19+
>OmitsKey : Symbol(OmitsKey, Decl(omitOfTypeExtendingIndexSignature.ts, 5, 1))
20+
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
21+
>ExtendsAny : Symbol(ExtendsAny, Decl(omitOfTypeExtendingIndexSignature.ts, 1, 37))
22+
23+
type OmitsKey1 = OmitsKey["myKey1"]; // should be `string`
24+
>OmitsKey1 : Symbol(OmitsKey1, Decl(omitOfTypeExtendingIndexSignature.ts, 7, 43))
25+
>OmitsKey : Symbol(OmitsKey, Decl(omitOfTypeExtendingIndexSignature.ts, 5, 1))
26+
27+
type OmitsKey2 = OmitsKey["myKey2"]; // should be `any`
28+
>OmitsKey2 : Symbol(OmitsKey2, Decl(omitOfTypeExtendingIndexSignature.ts, 8, 36))
29+
>OmitsKey : Symbol(OmitsKey, Decl(omitOfTypeExtendingIndexSignature.ts, 5, 1))
30+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/compiler/omitOfTypeExtendingIndexSignature.ts ===
2+
// #36981
3+
type AnyRecord = Record<string, any>;
4+
>AnyRecord : AnyRecord
5+
6+
interface ExtendsAny extends AnyRecord {
7+
myKey1: string;
8+
>myKey1 : string
9+
10+
myKey2: string;
11+
>myKey2 : string
12+
}
13+
14+
type OmitsKey = Omit<ExtendsAny, "myKey2">;
15+
>OmitsKey : Omit<ExtendsAny, "myKey2">
16+
17+
type OmitsKey1 = OmitsKey["myKey1"]; // should be `string`
18+
>OmitsKey1 : string
19+
20+
type OmitsKey2 = OmitsKey["myKey2"]; // should be `any`
21+
>OmitsKey2 : any
22+

Diff for: tests/baselines/reference/omitTypeHelperModifiers01.types

+9-9
Original file line numberDiff line numberDiff line change
@@ -17,55 +17,55 @@ type A = {
1717
};
1818

1919
type B = Omit<A, 'a'>;
20-
>B : B
20+
>B : Omit<A, "a">
2121

2222
function f(x: B) {
2323
>f : (x: B) => void
24-
>x : B
24+
>x : Omit<A, "a">
2525

2626
const b = x.b;
2727
>b : string | undefined
2828
>x.b : string | undefined
29-
>x : B
29+
>x : Omit<A, "a">
3030
>b : string | undefined
3131

3232
x.b = "hello";
3333
>x.b = "hello" : "hello"
3434
>x.b : string | undefined
35-
>x : B
35+
>x : Omit<A, "a">
3636
>b : string | undefined
3737
>"hello" : "hello"
3838

3939
x.b = undefined;
4040
>x.b = undefined : undefined
4141
>x.b : string | undefined
42-
>x : B
42+
>x : Omit<A, "a">
4343
>b : string | undefined
4444
>undefined : undefined
4545

4646
const c = x.c;
4747
>c : boolean
4848
>x.c : boolean
49-
>x : B
49+
>x : Omit<A, "a">
5050
>c : boolean
5151

5252
x.c = true;
5353
>x.c = true : true
5454
>x.c : any
55-
>x : B
55+
>x : Omit<A, "a">
5656
>c : any
5757
>true : true
5858

5959
const d = x.d;
6060
>d : unknown
6161
>x.d : unknown
62-
>x : B
62+
>x : Omit<A, "a">
6363
>d : unknown
6464

6565
x.d = d;
6666
>x.d = d : unknown
6767
>x.d : unknown
68-
>x : B
68+
>x : Omit<A, "a">
6969
>d : unknown
7070
>d : unknown
7171
}

Diff for: tests/baselines/reference/omitTypeTestErrors01.errors.txt

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
tests/cases/compiler/omitTypeTestErrors01.ts(11,16): error TS2339: Property 'c' does not exist on type 'Bar'.
2-
tests/cases/compiler/omitTypeTestErrors01.ts(15,16): error TS2339: Property 'b' does not exist on type 'Baz'.
1+
tests/cases/compiler/omitTypeTestErrors01.ts(11,16): error TS2339: Property 'c' does not exist on type 'Omit<Foo, "c">'.
2+
tests/cases/compiler/omitTypeTestErrors01.ts(15,16): error TS2339: Property 'b' does not exist on type 'Omit<Foo, "c" | "b">'.
33

44

55
==== tests/cases/compiler/omitTypeTestErrors01.ts (2 errors) ====
@@ -15,13 +15,13 @@ tests/cases/compiler/omitTypeTestErrors01.ts(15,16): error TS2339: Property 'b'
1515
export function getBarC(bar: Bar) {
1616
return bar.c;
1717
~
18-
!!! error TS2339: Property 'c' does not exist on type 'Bar'.
18+
!!! error TS2339: Property 'c' does not exist on type 'Omit<Foo, "c">'.
1919
}
2020

2121
export function getBazB(baz: Baz) {
2222
return baz.b;
2323
~
24-
!!! error TS2339: Property 'b' does not exist on type 'Baz'.
24+
!!! error TS2339: Property 'b' does not exist on type 'Omit<Foo, "c" | "b">'.
2525
}
2626

2727

Diff for: tests/baselines/reference/omitTypeTestErrors01.types

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,28 @@ interface Foo {
1111
}
1212

1313
export type Bar = Omit<Foo, "c">;
14-
>Bar : Bar
14+
>Bar : Omit<Foo, "c">
1515

1616
export type Baz = Omit<Foo, "b" | "c">;
17-
>Baz : Baz
17+
>Baz : Omit<Foo, "c" | "b">
1818

1919
export function getBarC(bar: Bar) {
2020
>getBarC : (bar: Bar) => any
21-
>bar : Bar
21+
>bar : Omit<Foo, "c">
2222

2323
return bar.c;
2424
>bar.c : any
25-
>bar : Bar
25+
>bar : Omit<Foo, "c">
2626
>c : any
2727
}
2828

2929
export function getBazB(baz: Baz) {
3030
>getBazB : (baz: Baz) => any
31-
>baz : Baz
31+
>baz : Omit<Foo, "c" | "b">
3232

3333
return baz.b;
3434
>baz.b : any
35-
>baz : Baz
35+
>baz : Omit<Foo, "c" | "b">
3636
>b : any
3737
}
3838

Diff for: tests/baselines/reference/omitTypeTests01.types

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,28 @@ interface Foo {
1111
}
1212

1313
export type Bar = Omit<Foo, "c">;
14-
>Bar : Bar
14+
>Bar : Omit<Foo, "c">
1515

1616
export type Baz = Omit<Foo, "b" | "c">;
17-
>Baz : Baz
17+
>Baz : Omit<Foo, "c" | "b">
1818

1919
export function getBarA(bar: Bar) {
2020
>getBarA : (bar: Bar) => string
21-
>bar : Bar
21+
>bar : Omit<Foo, "c">
2222

2323
return bar.a;
2424
>bar.a : string
25-
>bar : Bar
25+
>bar : Omit<Foo, "c">
2626
>a : string
2727
}
2828

2929
export function getBazA(baz: Baz) {
3030
>getBazA : (baz: Baz) => string
31-
>baz : Baz
31+
>baz : Omit<Foo, "c" | "b">
3232

3333
return baz.a;
3434
>baz.a : string
35-
>baz : Baz
35+
>baz : Omit<Foo, "c" | "b">
3636
>a : string
3737
}
3838

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// #36981
2+
type AnyRecord = Record<string, any>;
3+
interface ExtendsAny extends AnyRecord {
4+
myKey1: string;
5+
myKey2: string;
6+
}
7+
8+
type OmitsKey = Omit<ExtendsAny, "myKey2">;
9+
type OmitsKey1 = OmitsKey["myKey1"]; // should be `string`
10+
type OmitsKey2 = OmitsKey["myKey2"]; // should be `any`

0 commit comments

Comments
 (0)