Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 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: 2 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8252,7 +8252,8 @@ namespace ts {
}

function getIndexType(type: Type, includeDeclaredTypes?: boolean): Type {
return type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t, includeDeclaredTypes))) :
return type.flags & TypeFlags.Union ? getIntersectionType(map((<IntersectionType>type).types, t => getIndexType(t, includeDeclaredTypes))) :
type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t, includeDeclaredTypes))) :
maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, includeDeclaredTypes) :
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
type === wildcardType ? wildcardType :
Expand Down
47 changes: 47 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess.js
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,25 @@ function f3<T, K extends keyof T>(t: T, k: K, tk: T[K]): void {
type Predicates<TaggedRecord> = {
[T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T]
}


// Repro from #23618

type DBBoolTable<K extends string> = { [k in K]: 0 | 1 }
enum Flag {
FLAG_1 = "flag_1",
FLAG_2 = "flag_2"
}

type SimpleDBRecord<Flag extends string> = { staticField: number } & DBBoolTable<Flag>
function getFlagsFromSimpleRecord<Flag extends string>(record: SimpleDBRecord<Flag>, flags: Flag[]) {
return record[flags[0]];
}

type DynamicDBRecord<Flag extends string> = ({ dynamicField: number } | { dynamicField: string }) & DBBoolTable<Flag>
function getFlagsFromDynamicRecord<Flag extends string>(record: DynamicDBRecord<Flag>, flags: Flag[]) {
return record[flags[0]];
}


//// [keyofAndIndexedAccess.js]
Expand Down Expand Up @@ -948,6 +967,17 @@ function f3(t, k, tk) {
t[key] = tk; // ok, T[K] ==> T[keyof T]
}
}
var Flag;
(function (Flag) {
Flag["FLAG_1"] = "flag_1";
Flag["FLAG_2"] = "flag_2";
})(Flag || (Flag = {}));
function getFlagsFromSimpleRecord(record, flags) {
return record[flags[0]];
}
function getFlagsFromDynamicRecord(record, flags) {
return record[flags[0]];
}


//// [keyofAndIndexedAccess.d.ts]
Expand Down Expand Up @@ -1212,3 +1242,20 @@ declare function f3<T, K extends keyof T>(t: T, k: K, tk: T[K]): void;
declare type Predicates<TaggedRecord> = {
[T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T];
};
declare type DBBoolTable<K extends string> = {
[k in K]: 0 | 1;
};
declare enum Flag {
FLAG_1 = "flag_1",
FLAG_2 = "flag_2"
}
declare type SimpleDBRecord<Flag extends string> = {
staticField: number;
} & DBBoolTable<Flag>;
declare function getFlagsFromSimpleRecord<Flag extends string>(record: SimpleDBRecord<Flag>, flags: Flag[]): SimpleDBRecord<Flag>[Flag];
declare type DynamicDBRecord<Flag extends string> = ({
dynamicField: number;
} | {
dynamicField: string;
}) & DBBoolTable<Flag>;
declare function getFlagsFromDynamicRecord<Flag extends string>(record: DynamicDBRecord<Flag>, flags: Flag[]): DynamicDBRecord<Flag>[Flag];
62 changes: 62 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -2007,3 +2007,65 @@ type Predicates<TaggedRecord> = {
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 564, 3))
}


// Repro from #23618

type DBBoolTable<K extends string> = { [k in K]: 0 | 1 }
>DBBoolTable : Symbol(DBBoolTable, Decl(keyofAndIndexedAccess.ts, 565, 1))
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 570, 17))
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 570, 40))
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 570, 17))

enum Flag {
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 570, 56))

FLAG_1 = "flag_1",
>FLAG_1 : Symbol(Flag.FLAG_1, Decl(keyofAndIndexedAccess.ts, 571, 11))

FLAG_2 = "flag_2"
>FLAG_2 : Symbol(Flag.FLAG_2, Decl(keyofAndIndexedAccess.ts, 572, 22))
}

type SimpleDBRecord<Flag extends string> = { staticField: number } & DBBoolTable<Flag>
>SimpleDBRecord : Symbol(SimpleDBRecord, Decl(keyofAndIndexedAccess.ts, 574, 1))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 576, 20))
>staticField : Symbol(staticField, Decl(keyofAndIndexedAccess.ts, 576, 44))
>DBBoolTable : Symbol(DBBoolTable, Decl(keyofAndIndexedAccess.ts, 565, 1))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 576, 20))

function getFlagsFromSimpleRecord<Flag extends string>(record: SimpleDBRecord<Flag>, flags: Flag[]) {
>getFlagsFromSimpleRecord : Symbol(getFlagsFromSimpleRecord, Decl(keyofAndIndexedAccess.ts, 576, 86))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 577, 34))
>record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 577, 55))
>SimpleDBRecord : Symbol(SimpleDBRecord, Decl(keyofAndIndexedAccess.ts, 574, 1))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 577, 34))
>flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 577, 84))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 577, 34))

return record[flags[0]];
>record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 577, 55))
>flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 577, 84))
}

type DynamicDBRecord<Flag extends string> = ({ dynamicField: number } | { dynamicField: string }) & DBBoolTable<Flag>
>DynamicDBRecord : Symbol(DynamicDBRecord, Decl(keyofAndIndexedAccess.ts, 579, 1))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 581, 21))
>dynamicField : Symbol(dynamicField, Decl(keyofAndIndexedAccess.ts, 581, 46))
>dynamicField : Symbol(dynamicField, Decl(keyofAndIndexedAccess.ts, 581, 73))
>DBBoolTable : Symbol(DBBoolTable, Decl(keyofAndIndexedAccess.ts, 565, 1))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 581, 21))

function getFlagsFromDynamicRecord<Flag extends string>(record: DynamicDBRecord<Flag>, flags: Flag[]) {
>getFlagsFromDynamicRecord : Symbol(getFlagsFromDynamicRecord, Decl(keyofAndIndexedAccess.ts, 581, 117))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 582, 35))
>record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 582, 56))
>DynamicDBRecord : Symbol(DynamicDBRecord, Decl(keyofAndIndexedAccess.ts, 579, 1))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 582, 35))
>flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 582, 86))
>Flag : Symbol(Flag, Decl(keyofAndIndexedAccess.ts, 582, 35))

return record[flags[0]];
>record : Symbol(record, Decl(keyofAndIndexedAccess.ts, 582, 56))
>flags : Symbol(flags, Decl(keyofAndIndexedAccess.ts, 582, 86))
}

90 changes: 80 additions & 10 deletions tests/baselines/reference/keyofAndIndexedAccess.types
Original file line number Diff line number Diff line change
Expand Up @@ -888,11 +888,11 @@ function f60<T>(source: T, target: T) {
}

function f70(func: <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void) {
>f70 : (func: <T, U>(k1: keyof (T | U), k2: keyof T | keyof U) => void) => void
>func : <T, U>(k1: keyof (T | U), k2: keyof T | keyof U) => void
>f70 : (func: <T, U>(k1: keyof T & keyof U, k2: keyof T | keyof U) => void) => void
>func : <T, U>(k1: keyof T & keyof U, k2: keyof T | keyof U) => void
>T : T
>U : U
>k1 : keyof (T | U)
>k1 : keyof T & keyof U
>T : T
>U : U
>k2 : keyof T | keyof U
Expand All @@ -901,7 +901,7 @@ function f70(func: <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void) {

func<{ a: any, b: any }, { a: any, c: any }>('a', 'a');
>func<{ a: any, b: any }, { a: any, c: any }>('a', 'a') : void
>func : <T, U>(k1: keyof (T | U), k2: keyof T | keyof U) => void
>func : <T, U>(k1: keyof T & keyof U, k2: keyof T | keyof U) => void
>a : any
>b : any
>a : any
Expand All @@ -911,7 +911,7 @@ function f70(func: <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void) {

func<{ a: any, b: any }, { a: any, c: any }>('a', 'b');
>func<{ a: any, b: any }, { a: any, c: any }>('a', 'b') : void
>func : <T, U>(k1: keyof (T | U), k2: keyof T | keyof U) => void
>func : <T, U>(k1: keyof T & keyof U, k2: keyof T | keyof U) => void
>a : any
>b : any
>a : any
Expand All @@ -921,7 +921,7 @@ function f70(func: <T, U>(k1: keyof (T | U), k2: keyof (T & U)) => void) {

func<{ a: any, b: any }, { a: any, c: any }>('a', 'c');
>func<{ a: any, b: any }, { a: any, c: any }>('a', 'c') : void
>func : <T, U>(k1: keyof (T | U), k2: keyof T | keyof U) => void
>func : <T, U>(k1: keyof T & keyof U, k2: keyof T | keyof U) => void
>a : any
>b : any
>a : any
Expand Down Expand Up @@ -1095,8 +1095,8 @@ function f73(func: <T, U, K extends keyof (T & U)>(x: T, y: U, k: K) => (T & U)[
}

function f74(func: <T, U, K extends keyof (T | U)>(x: T, y: U, k: K) => (T | U)[K]) {
>f74 : (func: <T, U, K extends keyof (T | U)>(x: T, y: U, k: K) => (T | U)[K]) => void
>func : <T, U, K extends keyof (T | U)>(x: T, y: U, k: K) => (T | U)[K]
>f74 : (func: <T, U, K extends keyof T & keyof U>(x: T, y: U, k: K) => (T | U)[K]) => void
>func : <T, U, K extends keyof T & keyof U>(x: T, y: U, k: K) => (T | U)[K]
>T : T
>U : U
>K : K
Expand All @@ -1115,7 +1115,7 @@ function f74(func: <T, U, K extends keyof (T | U)>(x: T, y: U, k: K) => (T | U)[
let a = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'a'); // number
>a : number
>func({ a: 1, b: "hello" }, { a: 2, b: true }, 'a') : number
>func : <T, U, K extends keyof (T | U)>(x: T, y: U, k: K) => (T | U)[K]
>func : <T, U, K extends keyof T & keyof U>(x: T, y: U, k: K) => (T | U)[K]
>{ a: 1, b: "hello" } : { a: number; b: string; }
>a : number
>1 : 1
Expand All @@ -1131,7 +1131,7 @@ function f74(func: <T, U, K extends keyof (T | U)>(x: T, y: U, k: K) => (T | U)[
let b = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'b'); // string | boolean
>b : string | boolean
>func({ a: 1, b: "hello" }, { a: 2, b: true }, 'b') : string | boolean
>func : <T, U, K extends keyof (T | U)>(x: T, y: U, k: K) => (T | U)[K]
>func : <T, U, K extends keyof T & keyof U>(x: T, y: U, k: K) => (T | U)[K]
>{ a: 1, b: "hello" } : { a: number; b: string; }
>a : number
>1 : 1
Expand Down Expand Up @@ -2342,3 +2342,73 @@ type Predicates<TaggedRecord> = {
>T : T
}


// Repro from #23618

type DBBoolTable<K extends string> = { [k in K]: 0 | 1 }
>DBBoolTable : DBBoolTable<K>
>K : K
>k : k
>K : K

enum Flag {
>Flag : Flag

FLAG_1 = "flag_1",
>FLAG_1 : Flag.FLAG_1
>"flag_1" : "flag_1"

FLAG_2 = "flag_2"
>FLAG_2 : Flag.FLAG_2
>"flag_2" : "flag_2"
}

type SimpleDBRecord<Flag extends string> = { staticField: number } & DBBoolTable<Flag>
>SimpleDBRecord : SimpleDBRecord<Flag>
>Flag : Flag
>staticField : number
>DBBoolTable : DBBoolTable<K>
>Flag : Flag

function getFlagsFromSimpleRecord<Flag extends string>(record: SimpleDBRecord<Flag>, flags: Flag[]) {
>getFlagsFromSimpleRecord : <Flag extends string>(record: SimpleDBRecord<Flag>, flags: Flag[]) => SimpleDBRecord<Flag>[Flag]
>Flag : Flag
>record : SimpleDBRecord<Flag>
>SimpleDBRecord : SimpleDBRecord<Flag>
>Flag : Flag
>flags : Flag[]
>Flag : Flag

return record[flags[0]];
>record[flags[0]] : SimpleDBRecord<Flag>[Flag]
>record : SimpleDBRecord<Flag>
>flags[0] : Flag
>flags : Flag[]
>0 : 0
}

type DynamicDBRecord<Flag extends string> = ({ dynamicField: number } | { dynamicField: string }) & DBBoolTable<Flag>
>DynamicDBRecord : DynamicDBRecord<Flag>
>Flag : Flag
>dynamicField : number
>dynamicField : string
>DBBoolTable : DBBoolTable<K>
>Flag : Flag

function getFlagsFromDynamicRecord<Flag extends string>(record: DynamicDBRecord<Flag>, flags: Flag[]) {
>getFlagsFromDynamicRecord : <Flag extends string>(record: DynamicDBRecord<Flag>, flags: Flag[]) => DynamicDBRecord<Flag>[Flag]
>Flag : Flag
>record : DynamicDBRecord<Flag>
>DynamicDBRecord : DynamicDBRecord<Flag>
>Flag : Flag
>flags : Flag[]
>Flag : Flag

return record[flags[0]];
>record[flags[0]] : DynamicDBRecord<Flag>[Flag]
>record : DynamicDBRecord<Flag>
>flags[0] : Flag
>flags : Flag[]
>0 : 0
}

Loading