diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c9809acc781c2..abd86a2b3a94b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17870,8 +17870,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); } - function getSimplifiedType(type: Type, writing: boolean): Type { - return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) : + function getSimplifiedType(type: Type, writing: boolean, distributeIndexOverMappedType = false): Type { + return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing, distributeIndexOverMappedType) : type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) : type; } @@ -17898,8 +17898,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Transform an indexed access to a simpler form, if possible. Return the simpler form, or return // the type itself if no transformation is possible. The writing flag indicates that the type is // the target of an assignment. - function getSimplifiedIndexedAccessType(type: IndexedAccessType, writing: boolean): Type { - const cache = writing ? "simplifiedForWriting" : "simplifiedForReading"; + function getSimplifiedIndexedAccessType(type: IndexedAccessType, writing: boolean, distributeIndexOverMappedType: boolean): Type { + const cache = writing ? "simplifiedForWriting" : `simplifiedForReading${distributeIndexOverMappedType ? "D" : ""}` as const; if (type[cache]) { return type[cache] === circularConstraintType ? type : type[cache]!; } @@ -17941,6 +17941,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // For example, for an index access { [P in K]: Box }[X], we construct the type Box. if (isGenericMappedType(objectType)) { if (!getNameTypeFromMappedType(objectType) || isFilteringMappedType(objectType)) { + if (distributeIndexOverMappedType && !writing) { + const indexConstraint = indexType.flags & TypeFlags.Instantiable && getBaseConstraintOfType(indexType); + if (indexConstraint && indexConstraint.flags & TypeFlags.Union) { + return type[cache] = getSimplifiedType(getIndexedAccessType(objectType, getIntersectionType([indexType, indexConstraint])), writing); + } + } + return type[cache] = mapType(substituteIndexedMappedType(objectType, type.indexType), t => getSimplifiedType(t, writing)); } } @@ -20593,7 +20600,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : getSingleBaseForNonAugmentingSubtype(type) || type : type.flags & TypeFlags.UnionOrIntersection ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) : type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : getSubstitutionIntersection(type as SubstitutionType) : - type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) : + type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing, /*distributeIndexOverMappedType*/ true) : type; if (t === type) return t; type = t; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2096b177c5930..e260a5a185dd2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6555,6 +6555,7 @@ export interface IndexedAccessType extends InstantiableType { constraint?: Type; simplifiedForReading?: Type; simplifiedForWriting?: Type; + simplifiedForReadingD?: Type; } export type TypeVariable = TypeParameter | IndexedAccessType; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index dcea4be64289a..23d038153720c 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -7209,6 +7209,7 @@ declare namespace ts { constraint?: Type; simplifiedForReading?: Type; simplifiedForWriting?: Type; + simplifiedForReadingD?: Type; } type TypeVariable = TypeParameter | IndexedAccessType; interface IndexType extends InstantiableType { diff --git a/tests/baselines/reference/conditionalTypes1.errors.txt b/tests/baselines/reference/conditionalTypes1.errors.txt index 6c6443b045c59..dbec98f0f09f8 100644 --- a/tests/baselines/reference/conditionalTypes1.errors.txt +++ b/tests/baselines/reference/conditionalTypes1.errors.txt @@ -8,7 +8,7 @@ conditionalTypes1.ts(17,5): error TS2322: Type 'T' is not assignable to type 'No Type 'T' is not assignable to type '{}'. Type 'string | undefined' is not assignable to type '{}'. Type 'undefined' is not assignable to type '{}'. -conditionalTypes1.ts(24,5): error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'NonNullable[keyof T]>'. +conditionalTypes1.ts(24,5): error TS2322: Type 'T[keyof T & string] | T[keyof T & number] | T[keyof T & symbol] | undefined' is not assignable to type 'NonNullable[keyof T]>'. Type 'undefined' is not assignable to type 'T[keyof T] & {}'. Type 'undefined' is not assignable to type 'T[keyof T]'. 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'undefined'. @@ -25,32 +25,28 @@ conditionalTypes1.ts(104,5): error TS2322: Type 'NonFunctionProperties' is no 'T' could be instantiated with an arbitrary type which could be unrelated to 'NonFunctionProperties'. conditionalTypes1.ts(106,5): error TS2322: Type 'NonFunctionProperties' is not assignable to type 'FunctionProperties'. Type 'FunctionPropertyNames' is not assignable to type 'NonFunctionPropertyNames'. - Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. - Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. - Type 'string' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. - Type 'keyof T' is not assignable to type 'never'. - Type 'string | number | symbol' is not assignable to type 'never'. - Type 'string' is not assignable to type 'never'. + Type 'T[keyof T & string] extends Function ? keyof T & string : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type 'keyof T & string' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type 'keyof T & string' is not assignable to type 'never'. conditionalTypes1.ts(108,5): error TS2322: Type 'FunctionProperties' is not assignable to type 'NonFunctionProperties'. Type 'NonFunctionPropertyNames' is not assignable to type 'FunctionPropertyNames'. - Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. - Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. - Type 'string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. - Type 'keyof T' is not assignable to type 'never'. + Type 'T[keyof T & string] extends Function ? never : keyof T & string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type 'keyof T & string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type 'keyof T & string' is not assignable to type 'never'. conditionalTypes1.ts(114,5): error TS2322: Type 'keyof T' is not assignable to type 'FunctionPropertyNames'. Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. Type 'string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. conditionalTypes1.ts(115,5): error TS2322: Type 'NonFunctionPropertyNames' is not assignable to type 'FunctionPropertyNames'. - Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. - Type 'keyof T' is not assignable to type 'never'. - Type 'string | number | symbol' is not assignable to type 'never'. - Type 'string' is not assignable to type 'never'. + Type 'T[keyof T & string] extends Function ? never : keyof T & string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type 'keyof T & string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type 'keyof T & string' is not assignable to type 'never'. conditionalTypes1.ts(116,5): error TS2322: Type 'keyof T' is not assignable to type 'NonFunctionPropertyNames'. Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. Type 'string' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. conditionalTypes1.ts(117,5): error TS2322: Type 'FunctionPropertyNames' is not assignable to type 'NonFunctionPropertyNames'. - Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. - Type 'keyof T' is not assignable to type 'never'. + Type 'T[keyof T & string] extends Function ? keyof T & string : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type 'keyof T & string' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type 'keyof T & string' is not assignable to type 'never'. conditionalTypes1.ts(134,10): error TS2540: Cannot assign to 'id' because it is a read-only property. conditionalTypes1.ts(135,5): error TS2542: Index signature in type 'DeepReadonlyArray' only permits reading. conditionalTypes1.ts(136,22): error TS2540: Cannot assign to 'id' because it is a read-only property. @@ -108,7 +104,7 @@ conditionalTypes1.ts(288,43): error TS2322: Type 'T95' is not assignable to t x = y; y = x; // Error ~ -!!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'NonNullable[keyof T]>'. +!!! error TS2322: Type 'T[keyof T & string] | T[keyof T & number] | T[keyof T & symbol] | undefined' is not assignable to type 'NonNullable[keyof T]>'. !!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T] & {}'. !!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'. !!! error TS2322: 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'undefined'. @@ -211,21 +207,17 @@ conditionalTypes1.ts(288,43): error TS2322: Type 'T95' is not assignable to t ~ !!! error TS2322: Type 'NonFunctionProperties' is not assignable to type 'FunctionProperties'. !!! error TS2322: Type 'FunctionPropertyNames' is not assignable to type 'NonFunctionPropertyNames'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. -!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. -!!! error TS2322: Type 'string' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'never'. -!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'never'. -!!! error TS2322: Type 'string' is not assignable to type 'never'. +!!! error TS2322: Type 'T[keyof T & string] extends Function ? keyof T & string : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type 'keyof T & string' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type 'keyof T & string' is not assignable to type 'never'. z = x; z = y; // Error ~ !!! error TS2322: Type 'FunctionProperties' is not assignable to type 'NonFunctionProperties'. !!! error TS2322: Type 'NonFunctionPropertyNames' is not assignable to type 'FunctionPropertyNames'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. -!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. -!!! error TS2322: Type 'string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'never'. +!!! error TS2322: Type 'T[keyof T & string] extends Function ? never : keyof T & string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type 'keyof T & string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type 'keyof T & string' is not assignable to type 'never'. } function f8(x: keyof T, y: FunctionPropertyNames, z: NonFunctionPropertyNames) { @@ -239,10 +231,9 @@ conditionalTypes1.ts(288,43): error TS2322: Type 'T95' is not assignable to t y = z; // Error ~ !!! error TS2322: Type 'NonFunctionPropertyNames' is not assignable to type 'FunctionPropertyNames'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'never'. -!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'never'. -!!! error TS2322: Type 'string' is not assignable to type 'never'. +!!! error TS2322: Type 'T[keyof T & string] extends Function ? never : keyof T & string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type 'keyof T & string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type 'keyof T & string' is not assignable to type 'never'. z = x; // Error ~ !!! error TS2322: Type 'keyof T' is not assignable to type 'NonFunctionPropertyNames'. @@ -251,8 +242,9 @@ conditionalTypes1.ts(288,43): error TS2322: Type 'T95' is not assignable to t z = y; // Error ~ !!! error TS2322: Type 'FunctionPropertyNames' is not assignable to type 'NonFunctionPropertyNames'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'never'. +!!! error TS2322: Type 'T[keyof T & string] extends Function ? keyof T & string : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type 'keyof T & string' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type 'keyof T & string' is not assignable to type 'never'. } type DeepReadonly = diff --git a/tests/baselines/reference/correlatedUnions.errors.txt b/tests/baselines/reference/correlatedUnions.errors.txt new file mode 100644 index 0000000000000..3a07bca4f88f7 --- /dev/null +++ b/tests/baselines/reference/correlatedUnions.errors.txt @@ -0,0 +1,343 @@ +correlatedUnions.ts(327,23): error TS2345: Argument of type 'Pointer2' is not assignable to parameter of type 'Pointer'. + Type '{ table: T & "d"; id: string; }' is not assignable to type 'Pointer'. + Type '{ table: T & "d"; id: string; }' is not assignable to type '{ table: "c"; id: string; }'. + Types of property 'table' are incompatible. + Type 'T & "d"' is not assignable to type '"c"'. + + +==== correlatedUnions.ts (1 errors) ==== + // Various repros from #30581 + + type RecordMap = { n: number, s: string, b: boolean }; + type UnionRecord = { [P in K]: { + kind: P, + v: RecordMap[P], + f: (v: RecordMap[P]) => void + }}[K]; + + function processRecord(rec: UnionRecord) { + rec.f(rec.v); + } + + declare const r1: UnionRecord<'n'>; // { kind: 'n', v: number, f: (v: number) => void } + declare const r2: UnionRecord; // { kind: 'n', ... } | { kind: 's', ... } | { kind: 'b', ... } + + processRecord(r1); + processRecord(r2); + processRecord({ kind: 'n', v: 42, f: v => v.toExponential() }); + + // -------- + + type TextFieldData = { value: string } + type SelectFieldData = { options: string[], selectedValue: string } + + type FieldMap = { + text: TextFieldData; + select: SelectFieldData; + } + + type FormField = { type: K, data: FieldMap[K] }; + + type RenderFunc = (props: FieldMap[K]) => void; + type RenderFuncMap = { [K in keyof FieldMap]: RenderFunc }; + + function renderTextField(props: TextFieldData) {} + function renderSelectField(props: SelectFieldData) {} + + const renderFuncs: RenderFuncMap = { + text: renderTextField, + select: renderSelectField, + }; + + function renderField(field: FormField) { + const renderFn = renderFuncs[field.type]; + renderFn(field.data); + } + + // -------- + + type TypeMap = { + foo: string, + bar: number + }; + + type Keys = keyof TypeMap; + + type HandlerMap = { [P in Keys]: (x: TypeMap[P]) => void }; + + const handlers: HandlerMap = { + foo: s => s.length, + bar: n => n.toFixed(2) + }; + + type DataEntry = { [P in K]: { + type: P, + data: TypeMap[P] + }}[K]; + + const data: DataEntry[] = [ + { type: 'foo', data: 'abc' }, + { type: 'foo', data: 'def' }, + { type: 'bar', data: 42 }, + ]; + + function process(data: DataEntry[]) { + data.forEach(block => { + if (block.type in handlers) { + handlers[block.type](block.data) + } + }); + } + + process(data); + process([{ type: 'foo', data: 'abc' }]); + + // -------- + + type LetterMap = { A: string, B: number } + type LetterCaller = { [P in K]: { letter: Record, caller: (x: Record) => void } }[K]; + + function call({ letter, caller }: LetterCaller): void { + caller(letter); + } + + type A = { A: string }; + type B = { B: number }; + type ACaller = (a: A) => void; + type BCaller = (b: B) => void; + + declare const xx: { letter: A, caller: ACaller } | { letter: B, caller: BCaller }; + + call(xx); + + // -------- + + type Ev = { [P in K]: { + readonly name: P; + readonly once?: boolean; + readonly callback: (ev: DocumentEventMap[P]) => void; + }}[K]; + + function processEvents(events: Ev[]) { + for (const event of events) { + document.addEventListener(event.name, (ev) => event.callback(ev), { once: event.once }); + } + } + + function createEventListener({ name, once = false, callback }: Ev): Ev { + return { name, once, callback }; + } + + const clickEvent = createEventListener({ + name: "click", + callback: ev => console.log(ev), + }); + + const scrollEvent = createEventListener({ + name: "scroll", + callback: ev => console.log(ev), + }); + + processEvents([clickEvent, scrollEvent]); + + processEvents([ + { name: "click", callback: ev => console.log(ev) }, + { name: "scroll", callback: ev => console.log(ev) }, + ]); + + // -------- + + function ff1() { + type ArgMap = { + sum: [a: number, b: number], + concat: [a: string, b: string, c: string] + } + type Keys = keyof ArgMap; + const funs: { [P in Keys]: (...args: ArgMap[P]) => void } = { + sum: (a, b) => a + b, + concat: (a, b, c) => a + b + c + } + function apply(funKey: K, ...args: ArgMap[K]) { + const fn = funs[funKey]; + fn(...args); + } + const x1 = apply('sum', 1, 2) + const x2 = apply('concat', 'str1', 'str2', 'str3' ) + } + + // Repro from #47368 + + type ArgMap = { a: number, b: string }; + type Func = (x: ArgMap[K]) => void; + type Funcs = { [K in keyof ArgMap]: Func }; + + function f1(funcs: Funcs, key: K, arg: ArgMap[K]) { + funcs[key](arg); + } + + function f2(funcs: Funcs, key: K, arg: ArgMap[K]) { + const func = funcs[key]; // Type Funcs[K] + func(arg); + } + + function f3(funcs: Funcs, key: K, arg: ArgMap[K]) { + const func: Func = funcs[key]; + func(arg); + } + + function f4(x: Funcs[keyof ArgMap], y: Funcs[K]) { + x = y; + } + + // Repro from #47890 + + interface MyObj { + someKey: { + name: string; + } + someOtherKey: { + name: number; + } + } + + const ref: MyObj = { + someKey: { name: "" }, + someOtherKey: { name: 42 } + }; + + function func(k: K): MyObj[K]['name'] | undefined { + const myObj: Partial[K] = ref[k]; + if (myObj) { + return myObj.name; + } + const myObj2: Partial[keyof MyObj] = ref[k]; + if (myObj2) { + return myObj2.name; + } + return undefined; + } + + // Repro from #48157 + + interface Foo { + bar?: string + } + + function foo(prop: T, f: Required) { + bar(f[prop]); + } + + declare function bar(t: string): void; + + // Repro from #48246 + + declare function makeCompleteLookupMapping, Attr extends keyof T[number]>( + ops: T, attr: Attr): { [Item in T[number]as Item[Attr]]: Item }; + + const ALL_BARS = [{ name: 'a'}, {name: 'b'}] as const; + + const BAR_LOOKUP = makeCompleteLookupMapping(ALL_BARS, 'name'); + + type BarLookup = typeof BAR_LOOKUP; + + type Baz = { [K in keyof BarLookup]: BarLookup[K]['name'] }; + + // repro from #43982 + + interface Original { + prop1: { + subProp1: string; + subProp2: string; + }; + prop2: { + subProp3: string; + subProp4: string; + }; + } + type KeyOfOriginal = keyof Original; + type NestedKeyOfOriginalFor = keyof Original[T]; + + type SameKeys = { + [K in keyof T]: { + [K2 in keyof T[K]]: number; + }; + }; + + type MappedFromOriginal = SameKeys; + + const getStringAndNumberFromOriginalAndMapped = < + K extends KeyOfOriginal, + N extends NestedKeyOfOriginalFor + >( + original: Original, + mappedFromOriginal: MappedFromOriginal, + key: K, + nestedKey: N + ): [Original[K][N], MappedFromOriginal[K][N]] => { + return [original[key][nestedKey], mappedFromOriginal[key][nestedKey]]; + }; + + // repro from #31675 + interface Config { + string: string; + number: number; + } + + function getConfigOrDefault( + userConfig: Partial, + key: T, + defaultValue: Config[T] + ): Config[T] { + const userValue = userConfig[key]; + const assertedCheck = userValue ? userValue! : defaultValue; + return assertedCheck; + } + + // repro from #47523 + + type Foo1 = { + x: number; + y: string; + }; + + function getValueConcrete( + o: Partial, + k: K + ): Foo1[K] | undefined { + return o[k]; + } + + // https://github.com/microsoft/TypeScript/issues/54892 + type TableToRecord = { + a: { a: number }; + b: { b: string }; + c: { c: string[] }; + }; + type Table = keyof TableToRecord; + type Pointer = { + [K in T]: { table: K; id: string }; + }[T]; + declare function something(pointer: Pointer): void; + function run(pointer: Pointer) { + const x = something(pointer); + } + function run2(pointer: Pointer) { + const x = something(pointer); + } + function run3>(pointer: Pointer) { + const x = something(pointer); + } + type Table2 = keyof TableToRecord | 'd'; + type Pointer2 = { + [K in T]: { table: K; id: string }; + }[T]; + function run4(pointer: Pointer2) { + const x = something(pointer); // error + ~~~~~~~ +!!! error TS2345: Argument of type 'Pointer2' is not assignable to parameter of type 'Pointer'. +!!! error TS2345: Type '{ table: T & "d"; id: string; }' is not assignable to type 'Pointer'. +!!! error TS2345: Type '{ table: T & "d"; id: string; }' is not assignable to type '{ table: "c"; id: string; }'. +!!! error TS2345: Types of property 'table' are incompatible. +!!! error TS2345: Type 'T & "d"' is not assignable to type '"c"'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/correlatedUnions.js b/tests/baselines/reference/correlatedUnions.js index 5335811054601..395beb6a66f47 100644 --- a/tests/baselines/reference/correlatedUnions.js +++ b/tests/baselines/reference/correlatedUnions.js @@ -301,6 +301,34 @@ function getValueConcrete( ): Foo1[K] | undefined { return o[k]; } + +// https://github.com/microsoft/TypeScript/issues/54892 +type TableToRecord = { + a: { a: number }; + b: { b: string }; + c: { c: string[] }; +}; +type Table = keyof TableToRecord; +type Pointer = { + [K in T]: { table: K; id: string }; +}[T]; +declare function something(pointer: Pointer): void; +function run(pointer: Pointer) { + const x = something(pointer); +} +function run2(pointer: Pointer) { + const x = something(pointer); +} +function run3>(pointer: Pointer) { + const x = something(pointer); +} +type Table2 = keyof TableToRecord | 'd'; +type Pointer2 = { + [K in T]: { table: K; id: string }; +}[T]; +function run4(pointer: Pointer2) { + const x = something(pointer); // error +} //// [correlatedUnions.js] @@ -433,6 +461,18 @@ function getConfigOrDefault(userConfig, key, defaultValue) { function getValueConcrete(o, k) { return o[k]; } +function run(pointer) { + var x = something(pointer); +} +function run2(pointer) { + var x = something(pointer); +} +function run3(pointer) { + var x = something(pointer); +} +function run4(pointer) { + var x = something(pointer); // error +} //// [correlatedUnions.d.ts] @@ -613,3 +653,33 @@ type Foo1 = { y: string; }; declare function getValueConcrete(o: Partial, k: K): Foo1[K] | undefined; +type TableToRecord = { + a: { + a: number; + }; + b: { + b: string; + }; + c: { + c: string[]; + }; +}; +type Table = keyof TableToRecord; +type Pointer = { + [K in T]: { + table: K; + id: string; + }; +}[T]; +declare function something(pointer: Pointer): void; +declare function run(pointer: Pointer): void; +declare function run2(pointer: Pointer): void; +declare function run3>(pointer: Pointer): void; +type Table2 = keyof TableToRecord | 'd'; +type Pointer2 = { + [K in T]: { + table: K; + id: string; + }; +}[T]; +declare function run4(pointer: Pointer2): void; diff --git a/tests/baselines/reference/correlatedUnions.symbols b/tests/baselines/reference/correlatedUnions.symbols index bf5fe9d678045..553022e603eea 100644 --- a/tests/baselines/reference/correlatedUnions.symbols +++ b/tests/baselines/reference/correlatedUnions.symbols @@ -1016,3 +1016,120 @@ function getValueConcrete( >k : Symbol(k, Decl(correlatedUnions.ts, 295, 19)) } +// https://github.com/microsoft/TypeScript/issues/54892 +type TableToRecord = { +>TableToRecord : Symbol(TableToRecord, Decl(correlatedUnions.ts, 299, 1)) + + a: { a: number }; +>a : Symbol(a, Decl(correlatedUnions.ts, 302, 22)) +>a : Symbol(a, Decl(correlatedUnions.ts, 303, 6)) + + b: { b: string }; +>b : Symbol(b, Decl(correlatedUnions.ts, 303, 19)) +>b : Symbol(b, Decl(correlatedUnions.ts, 304, 6)) + + c: { c: string[] }; +>c : Symbol(c, Decl(correlatedUnions.ts, 304, 19)) +>c : Symbol(c, Decl(correlatedUnions.ts, 305, 6)) + +}; +type Table = keyof TableToRecord; +>Table : Symbol(Table, Decl(correlatedUnions.ts, 306, 2)) +>TableToRecord : Symbol(TableToRecord, Decl(correlatedUnions.ts, 299, 1)) + +type Pointer = { +>Pointer : Symbol(Pointer, Decl(correlatedUnions.ts, 307, 33)) +>T : Symbol(T, Decl(correlatedUnions.ts, 308, 13)) +>Table : Symbol(Table, Decl(correlatedUnions.ts, 306, 2)) +>Table : Symbol(Table, Decl(correlatedUnions.ts, 306, 2)) + + [K in T]: { table: K; id: string }; +>K : Symbol(K, Decl(correlatedUnions.ts, 309, 3)) +>T : Symbol(T, Decl(correlatedUnions.ts, 308, 13)) +>table : Symbol(table, Decl(correlatedUnions.ts, 309, 13)) +>K : Symbol(K, Decl(correlatedUnions.ts, 309, 3)) +>id : Symbol(id, Decl(correlatedUnions.ts, 309, 23)) + +}[T]; +>T : Symbol(T, Decl(correlatedUnions.ts, 308, 13)) + +declare function something(pointer: Pointer): void; +>something : Symbol(something, Decl(correlatedUnions.ts, 310, 5)) +>pointer : Symbol(pointer, Decl(correlatedUnions.ts, 311, 27)) +>Pointer : Symbol(Pointer, Decl(correlatedUnions.ts, 307, 33)) + +function run(pointer: Pointer) { +>run : Symbol(run, Decl(correlatedUnions.ts, 311, 51)) +>T : Symbol(T, Decl(correlatedUnions.ts, 312, 13)) +>Table : Symbol(Table, Decl(correlatedUnions.ts, 306, 2)) +>pointer : Symbol(pointer, Decl(correlatedUnions.ts, 312, 30)) +>Pointer : Symbol(Pointer, Decl(correlatedUnions.ts, 307, 33)) +>T : Symbol(T, Decl(correlatedUnions.ts, 312, 13)) + + const x = something(pointer); +>x : Symbol(x, Decl(correlatedUnions.ts, 313, 7)) +>something : Symbol(something, Decl(correlatedUnions.ts, 310, 5)) +>pointer : Symbol(pointer, Decl(correlatedUnions.ts, 312, 30)) +} +function run2(pointer: Pointer) { +>run2 : Symbol(run2, Decl(correlatedUnions.ts, 314, 1)) +>T : Symbol(T, Decl(correlatedUnions.ts, 315, 14)) +>Table : Symbol(Table, Decl(correlatedUnions.ts, 306, 2)) +>pointer : Symbol(pointer, Decl(correlatedUnions.ts, 315, 31)) +>Pointer : Symbol(Pointer, Decl(correlatedUnions.ts, 307, 33)) +>T : Symbol(T, Decl(correlatedUnions.ts, 315, 14)) +>Table : Symbol(Table, Decl(correlatedUnions.ts, 306, 2)) + + const x = something(pointer); +>x : Symbol(x, Decl(correlatedUnions.ts, 316, 7)) +>something : Symbol(something, Decl(correlatedUnions.ts, 310, 5)) +>pointer : Symbol(pointer, Decl(correlatedUnions.ts, 315, 31)) +} +function run3>(pointer: Pointer) { +>run3 : Symbol(run3, Decl(correlatedUnions.ts, 317, 1)) +>T : Symbol(T, Decl(correlatedUnions.ts, 318, 14)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>Table : Symbol(Table, Decl(correlatedUnions.ts, 306, 2)) +>pointer : Symbol(pointer, Decl(correlatedUnions.ts, 318, 45)) +>Pointer : Symbol(Pointer, Decl(correlatedUnions.ts, 307, 33)) +>T : Symbol(T, Decl(correlatedUnions.ts, 318, 14)) + + const x = something(pointer); +>x : Symbol(x, Decl(correlatedUnions.ts, 319, 7)) +>something : Symbol(something, Decl(correlatedUnions.ts, 310, 5)) +>pointer : Symbol(pointer, Decl(correlatedUnions.ts, 318, 45)) +} +type Table2 = keyof TableToRecord | 'd'; +>Table2 : Symbol(Table2, Decl(correlatedUnions.ts, 320, 1)) +>TableToRecord : Symbol(TableToRecord, Decl(correlatedUnions.ts, 299, 1)) + +type Pointer2 = { +>Pointer2 : Symbol(Pointer2, Decl(correlatedUnions.ts, 321, 40)) +>T : Symbol(T, Decl(correlatedUnions.ts, 322, 14)) +>Table2 : Symbol(Table2, Decl(correlatedUnions.ts, 320, 1)) +>Table2 : Symbol(Table2, Decl(correlatedUnions.ts, 320, 1)) + + [K in T]: { table: K; id: string }; +>K : Symbol(K, Decl(correlatedUnions.ts, 323, 3)) +>T : Symbol(T, Decl(correlatedUnions.ts, 322, 14)) +>table : Symbol(table, Decl(correlatedUnions.ts, 323, 13)) +>K : Symbol(K, Decl(correlatedUnions.ts, 323, 3)) +>id : Symbol(id, Decl(correlatedUnions.ts, 323, 23)) + +}[T]; +>T : Symbol(T, Decl(correlatedUnions.ts, 322, 14)) + +function run4(pointer: Pointer2) { +>run4 : Symbol(run4, Decl(correlatedUnions.ts, 324, 5)) +>T : Symbol(T, Decl(correlatedUnions.ts, 325, 14)) +>Table2 : Symbol(Table2, Decl(correlatedUnions.ts, 320, 1)) +>pointer : Symbol(pointer, Decl(correlatedUnions.ts, 325, 32)) +>Pointer2 : Symbol(Pointer2, Decl(correlatedUnions.ts, 321, 40)) +>T : Symbol(T, Decl(correlatedUnions.ts, 325, 14)) + + const x = something(pointer); // error +>x : Symbol(x, Decl(correlatedUnions.ts, 326, 7)) +>something : Symbol(something, Decl(correlatedUnions.ts, 310, 5)) +>pointer : Symbol(pointer, Decl(correlatedUnions.ts, 325, 32)) +} + diff --git a/tests/baselines/reference/correlatedUnions.types b/tests/baselines/reference/correlatedUnions.types index 8d328d6c66f79..d68f27ed4863b 100644 --- a/tests/baselines/reference/correlatedUnions.types +++ b/tests/baselines/reference/correlatedUnions.types @@ -900,3 +900,87 @@ function getValueConcrete( >k : K } +// https://github.com/microsoft/TypeScript/issues/54892 +type TableToRecord = { +>TableToRecord : { a: { a: number;}; b: { b: string;}; c: { c: string[];}; } + + a: { a: number }; +>a : { a: number; } +>a : number + + b: { b: string }; +>b : { b: string; } +>b : string + + c: { c: string[] }; +>c : { c: string[]; } +>c : string[] + +}; +type Table = keyof TableToRecord; +>Table : keyof TableToRecord + +type Pointer = { +>Pointer : Pointer + + [K in T]: { table: K; id: string }; +>table : K +>id : string + +}[T]; +declare function something(pointer: Pointer): void; +>something : (pointer: Pointer) => void +>pointer : Pointer + +function run(pointer: Pointer) { +>run : (pointer: Pointer) => void +>pointer : Pointer + + const x = something(pointer); +>x : void +>something(pointer) : void +>something : (pointer: Pointer) => void +>pointer : Pointer +} +function run2(pointer: Pointer) { +>run2 : (pointer: Pointer) => void +>pointer : Pointer + + const x = something(pointer); +>x : void +>something(pointer) : void +>something : (pointer: Pointer) => void +>pointer : { table: T & "b"; id: string; } | { table: T & "a"; id: string; } | { table: T & "c"; id: string; } +} +function run3>(pointer: Pointer) { +>run3 : (pointer: Pointer) => void +>pointer : Pointer + + const x = something(pointer); +>x : void +>something(pointer) : void +>something : (pointer: Pointer) => void +>pointer : Pointer +} +type Table2 = keyof TableToRecord | 'd'; +>Table2 : keyof TableToRecord | "d" + +type Pointer2 = { +>Pointer2 : Pointer2 + + [K in T]: { table: K; id: string }; +>table : K +>id : string + +}[T]; +function run4(pointer: Pointer2) { +>run4 : (pointer: Pointer2) => void +>pointer : Pointer2 + + const x = something(pointer); // error +>x : void +>something(pointer) : void +>something : (pointer: Pointer) => void +>pointer : Pointer2 +} + diff --git a/tests/baselines/reference/mappedTypeRelationships.errors.txt b/tests/baselines/reference/mappedTypeRelationships.errors.txt index 1918a9532f32d..86bf6169bc1a0 100644 --- a/tests/baselines/reference/mappedTypeRelationships.errors.txt +++ b/tests/baselines/reference/mappedTypeRelationships.errors.txt @@ -8,17 +8,17 @@ mappedTypeRelationships.ts(20,5): error TS2536: Type 'keyof U' cannot be used to mappedTypeRelationships.ts(21,12): error TS2536: Type 'keyof U' cannot be used to index type 'T'. mappedTypeRelationships.ts(25,5): error TS2536: Type 'K' cannot be used to index type 'T'. mappedTypeRelationships.ts(26,12): error TS2536: Type 'K' cannot be used to index type 'T'. -mappedTypeRelationships.ts(30,5): error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'. - 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'T[keyof T] | undefined'. -mappedTypeRelationships.ts(35,5): error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[K]'. - 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'T[K] | undefined'. -mappedTypeRelationships.ts(40,5): error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'. - 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'U[keyof T] | undefined'. +mappedTypeRelationships.ts(30,5): error TS2322: Type 'T[keyof T & string] | T[keyof T & number] | T[keyof T & symbol] | undefined' is not assignable to type 'T[keyof T]'. + 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'T[keyof T & string] | T[keyof T & number] | T[keyof T & symbol] | undefined'. +mappedTypeRelationships.ts(35,5): error TS2322: Type 'T[K & string] | T[K & number] | T[K & symbol] | undefined' is not assignable to type 'T[K]'. + 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'T[K & string] | T[K & number] | T[K & symbol] | undefined'. +mappedTypeRelationships.ts(40,5): error TS2322: Type 'U[keyof T & string] | U[keyof T & number] | U[keyof T & symbol] | undefined' is not assignable to type 'T[keyof T]'. + 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'U[keyof T & string] | U[keyof T & number] | U[keyof T & symbol] | undefined'. mappedTypeRelationships.ts(41,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'. Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'U[keyof T] | undefined'. Type 'T[string]' is not assignable to type 'U[keyof T] | undefined'. -mappedTypeRelationships.ts(45,5): error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[K]'. - 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'U[K] | undefined'. +mappedTypeRelationships.ts(45,5): error TS2322: Type 'U[K & string] | U[K & number] | U[K & symbol] | undefined' is not assignable to type 'T[K]'. + 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'U[K & string] | U[K & number] | U[K & symbol] | undefined'. mappedTypeRelationships.ts(46,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K] | undefined'. Type 'T[keyof T]' is not assignable to type 'U[K] | undefined'. Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'U[K] | undefined'. @@ -123,24 +123,24 @@ mappedTypeRelationships.ts(168,5): error TS2322: Type '{ [P in K]: T[P]; }' is n function f10(x: T, y: Partial, k: keyof T) { x[k] = y[k]; // Error ~~~~ -!!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'. -!!! error TS2322: 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'T[keyof T] | undefined'. +!!! error TS2322: Type 'T[keyof T & string] | T[keyof T & number] | T[keyof T & symbol] | undefined' is not assignable to type 'T[keyof T]'. +!!! error TS2322: 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'T[keyof T & string] | T[keyof T & number] | T[keyof T & symbol] | undefined'. y[k] = x[k]; } function f11(x: T, y: Partial, k: K) { x[k] = y[k]; // Error ~~~~ -!!! error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[K]'. -!!! error TS2322: 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'T[K] | undefined'. +!!! error TS2322: Type 'T[K & string] | T[K & number] | T[K & symbol] | undefined' is not assignable to type 'T[K]'. +!!! error TS2322: 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'T[K & string] | T[K & number] | T[K & symbol] | undefined'. y[k] = x[k]; } function f12(x: T, y: Partial, k: keyof T) { x[k] = y[k]; // Error ~~~~ -!!! error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'. -!!! error TS2322: 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'U[keyof T] | undefined'. +!!! error TS2322: Type 'U[keyof T & string] | U[keyof T & number] | U[keyof T & symbol] | undefined' is not assignable to type 'T[keyof T]'. +!!! error TS2322: 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'U[keyof T & string] | U[keyof T & number] | U[keyof T & symbol] | undefined'. y[k] = x[k]; // Error ~~~~ !!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'. @@ -151,8 +151,8 @@ mappedTypeRelationships.ts(168,5): error TS2322: Type '{ [P in K]: T[P]; }' is n function f13(x: T, y: Partial, k: K) { x[k] = y[k]; // Error ~~~~ -!!! error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[K]'. -!!! error TS2322: 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'U[K] | undefined'. +!!! error TS2322: Type 'U[K & string] | U[K & number] | U[K & symbol] | undefined' is not assignable to type 'T[K]'. +!!! error TS2322: 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'U[K & string] | U[K & number] | U[K & symbol] | undefined'. y[k] = x[k]; // Error ~~~~ !!! error TS2322: Type 'T[K]' is not assignable to type 'U[K] | undefined'. diff --git a/tests/cases/compiler/correlatedUnions.ts b/tests/cases/compiler/correlatedUnions.ts index 460ddf408a104..99f44ac884456 100644 --- a/tests/cases/compiler/correlatedUnions.ts +++ b/tests/cases/compiler/correlatedUnions.ts @@ -301,3 +301,31 @@ function getValueConcrete( ): Foo1[K] | undefined { return o[k]; } + +// https://github.com/microsoft/TypeScript/issues/54892 +type TableToRecord = { + a: { a: number }; + b: { b: string }; + c: { c: string[] }; +}; +type Table = keyof TableToRecord; +type Pointer = { + [K in T]: { table: K; id: string }; +}[T]; +declare function something(pointer: Pointer): void; +function run(pointer: Pointer) { + const x = something(pointer); +} +function run2(pointer: Pointer) { + const x = something(pointer); +} +function run3>(pointer: Pointer) { + const x = something(pointer); +} +type Table2 = keyof TableToRecord | 'd'; +type Pointer2 = { + [K in T]: { table: K; id: string }; +}[T]; +function run4(pointer: Pointer2) { + const x = something(pointer); // error +}