Explicitly encode keyof behaviors for never and unknown into getIndexType (#30753)

* Explicitly encode keyof behaviors for never and unknown into getIndexType

* Merge similar cases
This commit is contained in:
Wesley Wigham 2019-04-15 17:52:13 -07:00 committed by GitHub
parent 3dc78b6f3b
commit d405662eb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1723 additions and 1307 deletions

View File

@ -9841,7 +9841,8 @@ namespace ts {
maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, stringsOnly) :
getObjectFlags(type) & ObjectFlags.Mapped ? filterType(getConstraintTypeFromMappedType(<MappedType>type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number))) :
type === wildcardType ? wildcardType :
type.flags & TypeFlags.Any ? keyofConstraintType :
type.flags & TypeFlags.Unknown ? neverType :
type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType :
stringsOnly ? !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromProperties(type, TypeFlags.StringLiteral) :
!noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromProperties(type, TypeFlags.UniqueESSymbol)]) :
!noIndexSignatures && getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :

View File

@ -0,0 +1,85 @@
tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts(33,5): error TS2322: Type '{ type: T; localChannelId: string; }' is not assignable to type 'NewChannel<ChannelOfType<T, TextChannel> | ChannelOfType<T, EmailChannel>>'.
Type '{ type: T; localChannelId: string; }' is not assignable to type 'Pick<ChannelOfType<T, TextChannel> | ChannelOfType<T, EmailChannel>, "type">'.
Types of property 'type' are incompatible.
Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
Type '"text"' is not assignable to type 'T & "text"'.
Type '"text"' is not assignable to type 'T'.
Type 'T' is not assignable to type 'T & "text"'.
Type '"text" | "email"' is not assignable to type 'T & "text"'.
Type '"text"' is not assignable to type 'T & "text"'.
Type '"text"' is not assignable to type 'T'.
Type 'T' is not assignable to type '"text"'.
Type '"text" | "email"' is not assignable to type '"text"'.
Type '"email"' is not assignable to type '"text"'.
==== tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts (1 errors) ====
interface TextChannel {
id: string;
type: 'text';
phoneNumber: string;
}
interface EmailChannel {
id: string;
type: 'email';
addres: string;
}
type Channel = TextChannel | EmailChannel;
export type ChannelType = Channel extends { type: infer R } ? R : never;
type Omit<T, K extends keyof T> = Pick<
T,
({ [P in keyof T]: P } & { [P in K]: never } & { [x: string]: never })[keyof T]
>;
type ChannelOfType<T extends ChannelType, A = Channel> = A extends { type: T }
? A
: never;
export type NewChannel<T extends Channel> = Pick<T, 'type'> &
Partial<Omit<T, 'type' | 'id'>> & { localChannelId: string };
export function makeNewChannel<T extends ChannelType>(type: T): NewChannel<ChannelOfType<T>> {
const localChannelId = `blahblahblah`;
return { type, localChannelId };
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type '{ type: T; localChannelId: string; }' is not assignable to type 'NewChannel<ChannelOfType<T, TextChannel> | ChannelOfType<T, EmailChannel>>'.
!!! error TS2322: Type '{ type: T; localChannelId: string; }' is not assignable to type 'Pick<ChannelOfType<T, TextChannel> | ChannelOfType<T, EmailChannel>, "type">'.
!!! error TS2322: Types of property 'type' are incompatible.
!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
!!! error TS2322: Type 'T' is not assignable to type 'T & "text"'.
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'T & "text"'.
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
!!! error TS2322: Type 'T' is not assignable to type '"text"'.
!!! error TS2322: Type '"text" | "email"' is not assignable to type '"text"'.
!!! error TS2322: Type '"email"' is not assignable to type '"text"'.
}
const newTextChannel = makeNewChannel('text');
// This should work
newTextChannel.phoneNumber = '613-555-1234';
const newTextChannel2 : NewChannel<TextChannel> = makeNewChannel('text');
// Compare with this, which ofc works.
newTextChannel2.phoneNumber = '613-555-1234';

View File

@ -0,0 +1,59 @@
//// [complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts]
interface TextChannel {
id: string;
type: 'text';
phoneNumber: string;
}
interface EmailChannel {
id: string;
type: 'email';
addres: string;
}
type Channel = TextChannel | EmailChannel;
export type ChannelType = Channel extends { type: infer R } ? R : never;
type Omit<T, K extends keyof T> = Pick<
T,
({ [P in keyof T]: P } & { [P in K]: never } & { [x: string]: never })[keyof T]
>;
type ChannelOfType<T extends ChannelType, A = Channel> = A extends { type: T }
? A
: never;
export type NewChannel<T extends Channel> = Pick<T, 'type'> &
Partial<Omit<T, 'type' | 'id'>> & { localChannelId: string };
export function makeNewChannel<T extends ChannelType>(type: T): NewChannel<ChannelOfType<T>> {
const localChannelId = `blahblahblah`;
return { type, localChannelId };
}
const newTextChannel = makeNewChannel('text');
// This should work
newTextChannel.phoneNumber = '613-555-1234';
const newTextChannel2 : NewChannel<TextChannel> = makeNewChannel('text');
// Compare with this, which ofc works.
newTextChannel2.phoneNumber = '613-555-1234';
//// [complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.js]
"use strict";
exports.__esModule = true;
function makeNewChannel(type) {
var localChannelId = "blahblahblah";
return { type: type, localChannelId: localChannelId };
}
exports.makeNewChannel = makeNewChannel;
var newTextChannel = makeNewChannel('text');
// This should work
newTextChannel.phoneNumber = '613-555-1234';
var newTextChannel2 = makeNewChannel('text');
// Compare with this, which ofc works.
newTextChannel2.phoneNumber = '613-555-1234';

View File

@ -0,0 +1,130 @@
=== tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts ===
interface TextChannel {
>TextChannel : Symbol(TextChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 0, 0))
id: string;
>id : Symbol(TextChannel.id, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 0, 23))
type: 'text';
>type : Symbol(TextChannel.type, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 1, 15))
phoneNumber: string;
>phoneNumber : Symbol(TextChannel.phoneNumber, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 2, 17))
}
interface EmailChannel {
>EmailChannel : Symbol(EmailChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 4, 1))
id: string;
>id : Symbol(EmailChannel.id, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 6, 24))
type: 'email';
>type : Symbol(EmailChannel.type, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 7, 15))
addres: string;
>addres : Symbol(EmailChannel.addres, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 8, 18))
}
type Channel = TextChannel | EmailChannel;
>Channel : Symbol(Channel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 10, 1))
>TextChannel : Symbol(TextChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 0, 0))
>EmailChannel : Symbol(EmailChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 4, 1))
export type ChannelType = Channel extends { type: infer R } ? R : never;
>ChannelType : Symbol(ChannelType, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 12, 42))
>Channel : Symbol(Channel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 10, 1))
>type : Symbol(type, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 14, 43))
>R : Symbol(R, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 14, 55))
>R : Symbol(R, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 14, 55))
type Omit<T, K extends keyof T> = Pick<
>Omit : Symbol(Omit, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 14, 72))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 16, 10))
>K : Symbol(K, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 16, 12))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 16, 10))
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --))
T,
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 16, 10))
({ [P in keyof T]: P } & { [P in K]: never } & { [x: string]: never })[keyof T]
>P : Symbol(P, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 18, 8))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 16, 10))
>P : Symbol(P, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 18, 8))
>P : Symbol(P, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 18, 32))
>K : Symbol(K, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 16, 12))
>x : Symbol(x, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 18, 54))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 16, 10))
>;
type ChannelOfType<T extends ChannelType, A = Channel> = A extends { type: T }
>ChannelOfType : Symbol(ChannelOfType, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 19, 2))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 21, 19))
>ChannelType : Symbol(ChannelType, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 12, 42))
>A : Symbol(A, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 21, 41))
>Channel : Symbol(Channel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 10, 1))
>A : Symbol(A, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 21, 41))
>type : Symbol(type, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 21, 68))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 21, 19))
? A
>A : Symbol(A, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 21, 41))
: never;
export type NewChannel<T extends Channel> = Pick<T, 'type'> &
>NewChannel : Symbol(NewChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 23, 12))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 26, 23))
>Channel : Symbol(Channel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 10, 1))
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 26, 23))
Partial<Omit<T, 'type' | 'id'>> & { localChannelId: string };
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
>Omit : Symbol(Omit, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 14, 72))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 26, 23))
>localChannelId : Symbol(localChannelId, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 27, 39))
export function makeNewChannel<T extends ChannelType>(type: T): NewChannel<ChannelOfType<T>> {
>makeNewChannel : Symbol(makeNewChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 27, 65))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 30, 31))
>ChannelType : Symbol(ChannelType, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 12, 42))
>type : Symbol(type, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 30, 54))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 30, 31))
>NewChannel : Symbol(NewChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 23, 12))
>ChannelOfType : Symbol(ChannelOfType, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 19, 2))
>T : Symbol(T, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 30, 31))
const localChannelId = `blahblahblah`;
>localChannelId : Symbol(localChannelId, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 31, 9))
return { type, localChannelId };
>type : Symbol(type, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 32, 12))
>localChannelId : Symbol(localChannelId, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 32, 18))
}
const newTextChannel = makeNewChannel('text');
>newTextChannel : Symbol(newTextChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 35, 5))
>makeNewChannel : Symbol(makeNewChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 27, 65))
// This should work
newTextChannel.phoneNumber = '613-555-1234';
>newTextChannel.phoneNumber : Symbol(phoneNumber, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 2, 17))
>newTextChannel : Symbol(newTextChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 35, 5))
>phoneNumber : Symbol(phoneNumber, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 2, 17))
const newTextChannel2 : NewChannel<TextChannel> = makeNewChannel('text');
>newTextChannel2 : Symbol(newTextChannel2, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 39, 5))
>NewChannel : Symbol(NewChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 23, 12))
>TextChannel : Symbol(TextChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 0, 0))
>makeNewChannel : Symbol(makeNewChannel, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 27, 65))
// Compare with this, which ofc works.
newTextChannel2.phoneNumber = '613-555-1234';
>newTextChannel2.phoneNumber : Symbol(phoneNumber, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 2, 17))
>newTextChannel2 : Symbol(newTextChannel2, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 39, 5))
>phoneNumber : Symbol(phoneNumber, Decl(complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts, 2, 17))

View File

@ -0,0 +1,96 @@
=== tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts ===
interface TextChannel {
id: string;
>id : string
type: 'text';
>type : "text"
phoneNumber: string;
>phoneNumber : string
}
interface EmailChannel {
id: string;
>id : string
type: 'email';
>type : "email"
addres: string;
>addres : string
}
type Channel = TextChannel | EmailChannel;
>Channel : Channel
export type ChannelType = Channel extends { type: infer R } ? R : never;
>ChannelType : "text" | "email"
>type : R
type Omit<T, K extends keyof T> = Pick<
>Omit : Pick<T, ({ [P in keyof T]: P; } & { [P in K]: never; } & { [x: string]: never; })[keyof T]>
T,
({ [P in keyof T]: P } & { [P in K]: never } & { [x: string]: never })[keyof T]
>x : string
>;
type ChannelOfType<T extends ChannelType, A = Channel> = A extends { type: T }
>ChannelOfType : ChannelOfType<T, A>
>type : T
? A
: never;
export type NewChannel<T extends Channel> = Pick<T, 'type'> &
>NewChannel : NewChannel<T>
Partial<Omit<T, 'type' | 'id'>> & { localChannelId: string };
>localChannelId : string
export function makeNewChannel<T extends ChannelType>(type: T): NewChannel<ChannelOfType<T>> {
>makeNewChannel : <T extends "text" | "email">(type: T) => NewChannel<ChannelOfType<T, TextChannel> | ChannelOfType<T, EmailChannel>>
>type : T
const localChannelId = `blahblahblah`;
>localChannelId : "blahblahblah"
>`blahblahblah` : "blahblahblah"
return { type, localChannelId };
>{ type, localChannelId } : { type: T; localChannelId: string; }
>type : T
>localChannelId : string
}
const newTextChannel = makeNewChannel('text');
>newTextChannel : NewChannel<TextChannel>
>makeNewChannel('text') : NewChannel<TextChannel>
>makeNewChannel : <T extends "text" | "email">(type: T) => NewChannel<ChannelOfType<T, TextChannel> | ChannelOfType<T, EmailChannel>>
>'text' : "text"
// This should work
newTextChannel.phoneNumber = '613-555-1234';
>newTextChannel.phoneNumber = '613-555-1234' : "613-555-1234"
>newTextChannel.phoneNumber : string
>newTextChannel : NewChannel<TextChannel>
>phoneNumber : string
>'613-555-1234' : "613-555-1234"
const newTextChannel2 : NewChannel<TextChannel> = makeNewChannel('text');
>newTextChannel2 : NewChannel<TextChannel>
>makeNewChannel('text') : NewChannel<TextChannel>
>makeNewChannel : <T extends "text" | "email">(type: T) => NewChannel<ChannelOfType<T, TextChannel> | ChannelOfType<T, EmailChannel>>
>'text' : "text"
// Compare with this, which ofc works.
newTextChannel2.phoneNumber = '613-555-1234';
>newTextChannel2.phoneNumber = '613-555-1234' : "613-555-1234"
>newTextChannel2.phoneNumber : string
>newTextChannel2 : NewChannel<TextChannel>
>phoneNumber : string
>'613-555-1234' : "613-555-1234"

View File

@ -1,12 +1,10 @@
tests/cases/compiler/infiniteConstraints.ts(4,37): error TS2536: Type '"val"' cannot be used to index type 'B[Exclude<keyof B, K>]'.
tests/cases/compiler/infiniteConstraints.ts(21,21): error TS2536: Type '"val"' cannot be used to index type 'Extract<T[K], Record<"val", string>>'.
tests/cases/compiler/infiniteConstraints.ts(21,57): error TS2536: Type '"val"' cannot be used to index type 'Extract<T[Exclude<keyof T, K>], Record<"val", string>>'.
tests/cases/compiler/infiniteConstraints.ts(31,43): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
tests/cases/compiler/infiniteConstraints.ts(31,63): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.
==== tests/cases/compiler/infiniteConstraints.ts (6 errors) ====
==== tests/cases/compiler/infiniteConstraints.ts (4 errors) ====
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
@ -30,10 +28,6 @@ tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' c
declare function ensureNoDuplicates<
T extends {
[K in keyof T]: Extract<T[K], Value>["val"] extends Extract<T[Exclude<keyof T, K>], Value>["val"]
~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2536: Type '"val"' cannot be used to index type 'Extract<T[K], Record<"val", string>>'.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2536: Type '"val"' cannot be used to index type 'Extract<T[Exclude<keyof T, K>], Record<"val", string>>'.
? never
: any
}

View File

@ -31,7 +31,8 @@ type K03 = keyof boolean; // "valueOf"
type K04 = keyof void; // never
type K05 = keyof undefined; // never
type K06 = keyof null; // never
type K07 = keyof never; // never
type K07 = keyof never; // string | number | symbol
type K08 = keyof unknown; // never
type K10 = keyof Shape; // "name" | "width" | "height" | "visible"
type K11 = keyof Shape[]; // "length" | "toString" | ...
@ -1124,6 +1125,7 @@ declare type K04 = keyof void;
declare type K05 = keyof undefined;
declare type K06 = keyof null;
declare type K07 = keyof never;
declare type K08 = keyof unknown;
declare type K10 = keyof Shape;
declare type K11 = keyof Shape[];
declare type K12 = keyof Dictionary<Shape>;

File diff suppressed because it is too large Load Diff

View File

@ -76,8 +76,11 @@ type K06 = keyof null; // never
>K06 : never
>null : null
type K07 = keyof never; // never
>K07 : never
type K07 = keyof never; // string | number | symbol
>K07 : string | number | symbol
type K08 = keyof unknown; // never
>K08 : never
type K10 = keyof Shape; // "name" | "width" | "height" | "visible"
>K10 : "name" | "width" | "height" | "visible"

View File

@ -0,0 +1,42 @@
interface TextChannel {
id: string;
type: 'text';
phoneNumber: string;
}
interface EmailChannel {
id: string;
type: 'email';
addres: string;
}
type Channel = TextChannel | EmailChannel;
export type ChannelType = Channel extends { type: infer R } ? R : never;
type Omit<T, K extends keyof T> = Pick<
T,
({ [P in keyof T]: P } & { [P in K]: never } & { [x: string]: never })[keyof T]
>;
type ChannelOfType<T extends ChannelType, A = Channel> = A extends { type: T }
? A
: never;
export type NewChannel<T extends Channel> = Pick<T, 'type'> &
Partial<Omit<T, 'type' | 'id'>> & { localChannelId: string };
export function makeNewChannel<T extends ChannelType>(type: T): NewChannel<ChannelOfType<T>> {
const localChannelId = `blahblahblah`;
return { type, localChannelId };
}
const newTextChannel = makeNewChannel('text');
// This should work
newTextChannel.phoneNumber = '613-555-1234';
const newTextChannel2 : NewChannel<TextChannel> = makeNewChannel('text');
// Compare with this, which ofc works.
newTextChannel2.phoneNumber = '613-555-1234';

View File

@ -33,7 +33,8 @@ type K03 = keyof boolean; // "valueOf"
type K04 = keyof void; // never
type K05 = keyof undefined; // never
type K06 = keyof null; // never
type K07 = keyof never; // never
type K07 = keyof never; // string | number | symbol
type K08 = keyof unknown; // never
type K10 = keyof Shape; // "name" | "width" | "height" | "visible"
type K11 = keyof Shape[]; // "length" | "toString" | ...