From ef9f6ee40bb78f83bf4d18e49748c61d50098a35 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 20 Aug 2018 14:23:06 -0700 Subject: [PATCH] Retain errorType when it is used as a marker for the lack of a constraint --- src/compiler/checker.ts | 34 +- ...ropertyNamesContextualType9_ES5.errors.txt | 19 +- ...ropertyNamesContextualType9_ES6.errors.txt | 19 +- .../keyofAndIndexedAccess.errors.txt | 665 ------------------ .../reference/keyofAndIndexedAccess.types | 2 +- .../reference/mappedTypeErrors2.errors.txt | 15 +- ...tiveConstraintOfIndexAccessType.errors.txt | 26 +- 7 files changed, 70 insertions(+), 710 deletions(-) delete mode 100644 tests/baselines/reference/keyofAndIndexedAccess.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 65cb17e1723fc..550dd2577829e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6908,7 +6908,7 @@ namespace ts { function getConstraintOfIndexedAccess(type: IndexedAccessType) { const objectType = getBaseConstraintOfType(type.objectType) || type.objectType; const indexType = getBaseConstraintOfType(type.indexType) || type.indexType; - const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType) : undefined; + const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType, /*accessNode*/ undefined, errorType) : undefined; return constraint && constraint !== errorType ? constraint : undefined; } @@ -7059,7 +7059,7 @@ namespace ts { if (t.flags & TypeFlags.IndexedAccess) { const baseObjectType = getBaseConstraint((t).objectType); const baseIndexType = getBaseConstraint((t).indexType); - const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined; + const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType, /*accessNode*/ undefined, errorType) : undefined; return baseIndexedAccess && baseIndexedAccess !== errorType ? getBaseConstraint(baseIndexedAccess) : undefined; } if (t.flags & TypeFlags.Conditional) { @@ -9144,7 +9144,7 @@ namespace ts { return false; } - function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | undefined, cacheSymbol: boolean) { + function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | undefined, cacheSymbol: boolean, missingType: Type) { const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; const propName = isTypeUsableAsLateBoundName(indexType) ? getLateBoundNameFromType(indexType) : accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ? @@ -9216,7 +9216,7 @@ namespace ts { } } } - return accessNode ? errorType : unknownType; + return missingType; } } if (isJSLiteralType(objectType)) { @@ -9237,7 +9237,7 @@ namespace ts { if (isTypeAny(indexType)) { return indexType; } - return accessNode ? errorType : unknownType; + return missingType; } function isGenericObjectType(type: Type): boolean { @@ -9290,7 +9290,7 @@ namespace ts { return instantiateType(getTemplateTypeFromMappedType(objectType), templateMapper); } - function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode): Type { + function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode, missingType = accessNode ? errorType : unknownType): Type { if (objectType === wildcardType || indexType === wildcardType) { return wildcardType; } @@ -9318,18 +9318,15 @@ namespace ts { if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) { const propTypes: Type[] = []; for (const t of (indexType).types) { - const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false); - if (propType === unknownType) { - return unknownType; - } - if (propType === errorType) { - return errorType; + const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false, missingType); + if (propType === missingType) { + return missingType; } propTypes.push(propType); } return getUnionType(propTypes); } - return getPropertyTypeForIndexType(apparentObjectType, indexType, accessNode, /*cacheSymbol*/ true); + return getPropertyTypeForIndexType(apparentObjectType, indexType, accessNode, /*cacheSymbol*/ true, missingType); } function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) { @@ -10476,8 +10473,13 @@ namespace ts { return false; } + function isOrHasGenericConditional(type: Type): boolean { + return !!(type.flags & TypeFlags.Conditional || (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isOrHasGenericConditional))); + } + function elaborateError(node: Expression | undefined, source: Type, target: Type): boolean { if (!node) return false; + if (isOrHasGenericConditional(target)) return false; switch (node.kind) { case SyntaxKind.JsxExpression: case SyntaxKind.ParenthesizedExpression: @@ -10510,9 +10512,9 @@ namespace ts { let reportedError = false; for (let status = iterator.next(); !status.done; status = iterator.next()) { const { errorNode: prop, innerExpression: next, nameType, errorMessage } = status.value; - const sourcePropType = getIndexedAccessType(source, nameType); - const targetPropType = getIndexedAccessType(target, nameType); - if (!isTypeAssignableTo(sourcePropType, targetPropType)) { + const sourcePropType = getIndexedAccessType(source, nameType, /*accessNode*/ undefined, errorType); + const targetPropType = getIndexedAccessType(target, nameType, /*accessNode*/ undefined, errorType); + if (sourcePropType !== errorType && targetPropType !== errorType && !isTypeAssignableTo(sourcePropType, targetPropType)) { const elaborated = next && elaborateError(next, sourcePropType, targetPropType); if (elaborated) { reportedError = true; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType9_ES5.errors.txt b/tests/baselines/reference/computedPropertyNamesContextualType9_ES5.errors.txt index d5fb590732513..e76b3a704dc6e 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType9_ES5.errors.txt +++ b/tests/baselines/reference/computedPropertyNamesContextualType9_ES5.errors.txt @@ -1,20 +1,21 @@ -tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts(7,5): error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'. -tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts(8,5): error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'. +tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts(6,5): error TS2322: Type '{ [x: number]: string | number; }' is not assignable to type 'I'. + Index signatures are incompatible. + Type 'string | number' is not assignable to type 'boolean'. + Type 'string' is not assignable to type 'boolean'. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts (2 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts (1 errors) ==== interface I { [s: string]: boolean; [s: number]: boolean; } var o: I = { + ~ +!!! error TS2322: Type '{ [x: number]: string | number; }' is not assignable to type 'I'. +!!! error TS2322: Index signatures are incompatible. +!!! error TS2322: Type 'string | number' is not assignable to type 'boolean'. +!!! error TS2322: Type 'string' is not assignable to type 'boolean'. [+"foo"]: "", - ~~~~~~~~ -!!! error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'. -!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts:2:5: The expected type comes from this index signature. [+"bar"]: 0 - ~~~~~~~~ -!!! error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'. -!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts:2:5: The expected type comes from this index signature. } \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyNamesContextualType9_ES6.errors.txt b/tests/baselines/reference/computedPropertyNamesContextualType9_ES6.errors.txt index 16b4ffb2bae37..468ad400c26cc 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType9_ES6.errors.txt +++ b/tests/baselines/reference/computedPropertyNamesContextualType9_ES6.errors.txt @@ -1,20 +1,21 @@ -tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts(7,5): error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'. -tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts(8,5): error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'. +tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts(6,5): error TS2322: Type '{ [x: number]: string | number; }' is not assignable to type 'I'. + Index signatures are incompatible. + Type 'string | number' is not assignable to type 'boolean'. + Type 'string' is not assignable to type 'boolean'. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts (2 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts (1 errors) ==== interface I { [s: string]: boolean; [s: number]: boolean; } var o: I = { + ~ +!!! error TS2322: Type '{ [x: number]: string | number; }' is not assignable to type 'I'. +!!! error TS2322: Index signatures are incompatible. +!!! error TS2322: Type 'string | number' is not assignable to type 'boolean'. +!!! error TS2322: Type 'string' is not assignable to type 'boolean'. [+"foo"]: "", - ~~~~~~~~ -!!! error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'. -!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts:2:5: The expected type comes from this index signature. [+"bar"]: 0 - ~~~~~~~~ -!!! error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'. -!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts:2:5: The expected type comes from this index signature. } \ No newline at end of file diff --git a/tests/baselines/reference/keyofAndIndexedAccess.errors.txt b/tests/baselines/reference/keyofAndIndexedAccess.errors.txt deleted file mode 100644 index 41f429364463b..0000000000000 --- a/tests/baselines/reference/keyofAndIndexedAccess.errors.txt +++ /dev/null @@ -1,665 +0,0 @@ -tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(618,33): error TS2345: Argument of type 'T[K]' is not assignable to parameter of type '{} | null | undefined'. - Type 'unknown' is not assignable to type '{} | null | undefined'. - Type 'unknown' is not assignable to type '{}'. - Type 'T[K]' is not assignable to type '{}'. - Type 'unknown' is not assignable to type '{}'. - - -==== tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts (1 errors) ==== - class Shape { - name: string; - width: number; - height: number; - visible: boolean; - } - - class TaggedShape extends Shape { - tag: string; - } - - class Item { - name: string; - price: number; - } - - class Options { - visible: "yes" | "no"; - } - - type Dictionary = { [x: string]: T }; - type NumericallyIndexed = { [x: number]: T }; - - const enum E { A, B, C } - - type K00 = keyof any; // string - type K01 = keyof string; // "toString" | "charAt" | ... - type K02 = keyof number; // "toString" | "toFixed" | "toExponential" | ... - 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 K10 = keyof Shape; // "name" | "width" | "height" | "visible" - type K11 = keyof Shape[]; // "length" | "toString" | ... - type K12 = keyof Dictionary; // string - type K13 = keyof {}; // never - type K14 = keyof Object; // "constructor" | "toString" | ... - type K15 = keyof E; // "toString" | "toFixed" | "toExponential" | ... - type K16 = keyof [string, number]; // "0" | "1" | "length" | "toString" | ... - type K17 = keyof (Shape | Item); // "name" - type K18 = keyof (Shape & Item); // "name" | "width" | "height" | "visible" | "price" - type K19 = keyof NumericallyIndexed // never - - type KeyOf = keyof T; - - type K20 = KeyOf; // "name" | "width" | "height" | "visible" - type K21 = KeyOf>; // string - - type NAME = "name"; - type WIDTH_OR_HEIGHT = "width" | "height"; - - type Q10 = Shape["name"]; // string - type Q11 = Shape["width" | "height"]; // number - type Q12 = Shape["name" | "visible"]; // string | boolean - - type Q20 = Shape[NAME]; // string - type Q21 = Shape[WIDTH_OR_HEIGHT]; // number - - type Q30 = [string, number][0]; // string - type Q31 = [string, number][1]; // number - type Q32 = [string, number][2]; // string | number - type Q33 = [string, number][E.A]; // string - type Q34 = [string, number][E.B]; // number - type Q35 = [string, number][E.C]; // string | number - type Q36 = [string, number]["0"]; // string - type Q37 = [string, number]["1"]; // string - - type Q40 = (Shape | Options)["visible"]; // boolean | "yes" | "no" - type Q41 = (Shape & Options)["visible"]; // true & "yes" | true & "no" | false & "yes" | false & "no" - - type Q50 = Dictionary["howdy"]; // Shape - type Q51 = Dictionary[123]; // Shape - type Q52 = Dictionary[E.B]; // Shape - - declare let cond: boolean; - - function getProperty(obj: T, key: K) { - return obj[key]; - } - - function setProperty(obj: T, key: K, value: T[K]) { - obj[key] = value; - } - - function f10(shape: Shape) { - let name = getProperty(shape, "name"); // string - let widthOrHeight = getProperty(shape, cond ? "width" : "height"); // number - let nameOrVisible = getProperty(shape, cond ? "name" : "visible"); // string | boolean - setProperty(shape, "name", "rectangle"); - setProperty(shape, cond ? "width" : "height", 10); - setProperty(shape, cond ? "name" : "visible", true); // Technically not safe - } - - function f11(a: Shape[]) { - let len = getProperty(a, "length"); // number - setProperty(a, "length", len); - } - - function f12(t: [Shape, boolean]) { - let len = getProperty(t, "length"); - let s2 = getProperty(t, "0"); // Shape - let b2 = getProperty(t, "1"); // boolean - } - - function f13(foo: any, bar: any) { - let x = getProperty(foo, "x"); // any - let y = getProperty(foo, "100"); // any - let z = getProperty(foo, bar); // any - } - - class Component { - props: PropType; - getProperty(key: K) { - return this.props[key]; - } - setProperty(key: K, value: PropType[K]) { - this.props[key] = value; - } - } - - function f20(component: Component) { - let name = component.getProperty("name"); // string - let widthOrHeight = component.getProperty(cond ? "width" : "height"); // number - let nameOrVisible = component.getProperty(cond ? "name" : "visible"); // string | boolean - component.setProperty("name", "rectangle"); - component.setProperty(cond ? "width" : "height", 10) - component.setProperty(cond ? "name" : "visible", true); // Technically not safe - } - - function pluck(array: T[], key: K) { - return array.map(x => x[key]); - } - - function f30(shapes: Shape[]) { - let names = pluck(shapes, "name"); // string[] - let widths = pluck(shapes, "width"); // number[] - let nameOrVisibles = pluck(shapes, cond ? "name" : "visible"); // (string | boolean)[] - } - - function f31(key: K) { - const shape: Shape = { name: "foo", width: 5, height: 10, visible: true }; - return shape[key]; // Shape[K] - } - - function f32(key: K) { - const shape: Shape = { name: "foo", width: 5, height: 10, visible: true }; - return shape[key]; // Shape[K] - } - - function f33(shape: S, key: K) { - let name = getProperty(shape, "name"); - let prop = getProperty(shape, key); - return prop; - } - - function f34(ts: TaggedShape) { - let tag1 = f33(ts, "tag"); - let tag2 = getProperty(ts, "tag"); - } - - class C { - public x: string; - protected y: string; - private z: string; - } - - // Indexed access expressions have always permitted access to private and protected members. - // For consistency we also permit such access in indexed access types. - function f40(c: C) { - type X = C["x"]; - type Y = C["y"]; - type Z = C["z"]; - let x: X = c["x"]; - let y: Y = c["y"]; - let z: Z = c["z"]; - } - - function f50(k: keyof T, s: string) { - const x1 = s as keyof T; - const x2 = k as string; - } - - function f51(k: K, s: string) { - const x1 = s as keyof T; - const x2 = k as string; - } - - function f52(obj: { [x: string]: boolean }, k: Exclude, s: string, n: number) { - const x1 = obj[s]; - const x2 = obj[n]; - const x3 = obj[k]; - } - - function f53>(obj: { [x: string]: boolean }, k: K, s: string, n: number) { - const x1 = obj[s]; - const x2 = obj[n]; - const x3 = obj[k]; - } - - function f54(obj: T, key: keyof T) { - for (let s in obj[key]) { - } - const b = "foo" in obj[key]; - } - - function f55(obj: T, key: K) { - for (let s in obj[key]) { - } - const b = "foo" in obj[key]; - } - - function f60(source: T, target: T) { - for (let k in source) { - target[k] = source[k]; - } - } - - function f70(func: (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', 'b'); - func<{ a: any, b: any }, { a: any, c: any }>('a', 'c'); - } - - function f71(func: (x: T, y: U) => Partial) { - let x = func({ a: 1, b: "hello" }, { c: true }); - x.a; // number | undefined - x.b; // string | undefined - x.c; // boolean | undefined - } - - function f72(func: (x: T, y: U, k: K) => (T & U)[K]) { - let a = func({ a: 1, b: "hello" }, { c: true }, 'a'); // number - let b = func({ a: 1, b: "hello" }, { c: true }, 'b'); // string - let c = func({ a: 1, b: "hello" }, { c: true }, 'c'); // boolean - } - - function f73(func: (x: T, y: U, k: K) => (T & U)[K]) { - let a = func({ a: 1, b: "hello" }, { c: true }, 'a'); // number - let b = func({ a: 1, b: "hello" }, { c: true }, 'b'); // string - let c = func({ a: 1, b: "hello" }, { c: true }, 'c'); // boolean - } - - function f74(func: (x: T, y: U, k: K) => (T | U)[K]) { - let a = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'a'); // number - let b = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'b'); // string | boolean - } - - function f80(obj: T) { - let a1 = obj.a; // { x: any } - let a2 = obj['a']; // { x: any } - let a3 = obj['a'] as T['a']; // T["a"] - let x1 = obj.a.x; // any - let x2 = obj['a']['x']; // any - let x3 = obj['a']['x'] as T['a']['x']; // T["a"]["x"] - } - - function f81(obj: T) { - return obj['a']['x'] as T['a']['x']; - } - - function f82() { - let x1 = f81({ a: { x: "hello" } }); // string - let x2 = f81({ a: { x: 42 } }); // number - } - - function f83(obj: T, key: K) { - return obj[key]['x'] as T[K]['x']; - } - - function f84() { - let x1 = f83({ foo: { x: "hello" } }, "foo"); // string - let x2 = f83({ bar: { x: 42 } }, "bar"); // number - } - - class C1 { - x: number; - get(key: K) { - return this[key]; - } - set(key: K, value: this[K]) { - this[key] = value; - } - foo() { - let x1 = this.x; // number - let x2 = this["x"]; // number - let x3 = this.get("x"); // this["x"] - let x4 = getProperty(this, "x"); // this["x"] - this.x = 42; - this["x"] = 42; - this.set("x", 42); - setProperty(this, "x", 42); - } - } - - type S2 = { - a: string; - b: string; - }; - - function f90(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K], x4: T[K]) { - x1 = x2; - x1 = x3; - x1 = x4; - x2 = x1; - x2 = x3; - x2 = x4; - x3 = x1; - x3 = x2; - x3 = x4; - x4 = x1; - x4 = x2; - x4 = x3; - x1.length; - x2.length; - x3.length; - x4.length; - } - - function f91(x: T, y: T[keyof T], z: T[K]) { - let a: {}; - a = x; - a = y; - a = z; - } - - function f92(x: T, y: T[keyof T], z: T[K]) { - let a: {} | null | undefined; - a = x; - a = y; - a = z; - } - - // Repros from #12011 - - class Base { - get(prop: K) { - return this[prop]; - } - set(prop: K, value: this[K]) { - this[prop] = value; - } - } - - class Person extends Base { - parts: number; - constructor(parts: number) { - super(); - this.set("parts", parts); - } - getParts() { - return this.get("parts") - } - } - - class OtherPerson { - parts: number; - constructor(parts: number) { - setProperty(this, "parts", parts); - } - getParts() { - return getProperty(this, "parts") - } - } - - // Modified repro from #12544 - - function path(obj: T, key1: K1): T[K1]; - function path(obj: T, key1: K1, key2: K2): T[K1][K2]; - function path(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; - function path(obj: any, ...keys: (string | number)[]): any; - function path(obj: any, ...keys: (string | number)[]): any { - let result = obj; - for (let k of keys) { - result = result[k]; - } - return result; - } - - type Thing = { - a: { x: number, y: string }, - b: boolean - }; - - - function f1(thing: Thing) { - let x1 = path(thing, 'a'); // { x: number, y: string } - let x2 = path(thing, 'a', 'y'); // string - let x3 = path(thing, 'b'); // boolean - let x4 = path(thing, ...['a', 'x']); // any - } - - // Repro from comment in #12114 - - const assignTo2 = (object: T, key1: K1, key2: K2) => - (value: T[K1][K2]) => object[key1][key2] = value; - - // Modified repro from #12573 - - declare function one(handler: (t: T) => void): T - var empty = one(() => {}) // inferred as {}, expected - - type Handlers = { [K in keyof T]: (t: T[K]) => void } - declare function on(handlerHash: Handlers): T - var hashOfEmpty1 = on({ test: () => {} }); // {} - var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean } - - // Repro from #12624 - - interface Options1 { - data?: Data - computed?: Computed; - } - - declare class Component1 { - constructor(options: Options1); - get(key: K): (Data & Computed)[K]; - } - - let c1 = new Component1({ - data: { - hello: "" - } - }); - - c1.get("hello"); - - // Repro from #12625 - - interface Options2 { - data?: Data - computed?: Computed; - } - - declare class Component2 { - constructor(options: Options2); - get(key: K): (Data & Computed)[K]; - } - - // Repro from #12641 - - interface R { - p: number; - } - - function f(p: K) { - let a: any; - a[p].add; // any - } - - // Repro from #12651 - - type MethodDescriptor = { - name: string; - args: any[]; - returnValue: any; - } - - declare function dispatchMethod(name: M['name'], args: M['args']): M['returnValue']; - - type SomeMethodDescriptor = { - name: "someMethod"; - args: [string, number]; - returnValue: string[]; - } - - let result = dispatchMethod("someMethod", ["hello", 35]); - - // Repro from #13073 - - type KeyTypes = "a" | "b" - let MyThingy: { [key in KeyTypes]: string[] }; - - function addToMyThingy(key: S) { - MyThingy[key].push("a"); - } - - // Repro from #13102 - - type Handler = { - onChange: (name: keyof T) => void; - }; - - function onChangeGenericFunction(handler: Handler) { - handler.onChange('preset') - } - - // Repro from #13285 - - function updateIds, K extends string>( - obj: T, - idFields: K[], - idMapping: { [oldId: string]: string } - ): Record { - for (const idField of idFields) { - const newId = idMapping[obj[idField]]; - if (newId) { - obj[idField] = newId; - } - } - return obj; - } - - // Repro from #13285 - - function updateIds2( - obj: T, - key: K, - stringMap: { [oldId: string]: string } - ) { - var x = obj[key]; - stringMap[x]; // Should be OK. - } - - // Repro from #13514 - - declare function head>(list: T): T[0]; - - // Repro from #13604 - - class A { - props: T & { foo: string }; - } - - class B extends A<{ x: number}> { - f(p: this["props"]) { - p.x; - } - } - - // Repro from #13749 - - class Form { - private childFormFactories: {[K in keyof T]: (v: T[K]) => Form} - - public set(prop: K, value: T[K]) { - this.childFormFactories[prop](value) - } - } - - // Repro from #13787 - - class SampleClass

{ - public props: Readonly

; - constructor(props: P) { - this.props = Object.freeze(props); - } - } - - interface Foo { - foo: string; - } - - declare function merge(obj1: T, obj2: U): T & U; - - class AnotherSampleClass extends SampleClass { - constructor(props: T) { - const foo: Foo = { foo: "bar" }; - super(merge(props, foo)); - } - - public brokenMethod() { - this.props.foo.concat; - } - } - new AnotherSampleClass({}); - - // Positive repro from #17166 - function f3>(t: T, k: K, tk: T[K]): void { - for (let key in t) { - key = k // ok, K ==> keyof T - t[key] = tk; // ok, T[K] ==> T[keyof T] - } - } - - // # 21185 - type Predicates = { - [T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T] - } - - // Repros from #23592 - - type Example = { [K in keyof T]: T[K]["prop"] }; - type Result = Example<{ a: { prop: string }; b: { prop: number } }>; - - type Helper2 = { [K in keyof T]: Extract }; - type Example2 = { [K in keyof Helper2]: Helper2[K]["prop"] }; - type Result2 = Example2<{ 1: { prop: string }; 2: { prop: number } }>; - - // Repro from #23618 - - type DBBoolTable = { [k in K]: 0 | 1 } - enum Flag { - FLAG_1 = "flag_1", - FLAG_2 = "flag_2" - } - - type SimpleDBRecord = { staticField: number } & DBBoolTable - function getFlagsFromSimpleRecord(record: SimpleDBRecord, flags: Flag[]) { - return record[flags[0]]; - } - - type DynamicDBRecord = ({ dynamicField: number } | { dynamicField: string }) & DBBoolTable - function getFlagsFromDynamicRecord(record: DynamicDBRecord, flags: Flag[]) { - return record[flags[0]]; - } - - // Repro from #21368 - - interface I { - foo: string; - } - - declare function take(p: T): void; - - function fn(o: T, k: K) { - take<{} | null | undefined>(o[k]); - ~~~~ -!!! error TS2345: Argument of type 'T[K]' is not assignable to parameter of type '{} | null | undefined'. -!!! error TS2345: Type 'unknown' is not assignable to type '{} | null | undefined'. -!!! error TS2345: Type 'unknown' is not assignable to type '{}'. -!!! error TS2345: Type 'T[K]' is not assignable to type '{}'. -!!! error TS2345: Type 'unknown' is not assignable to type '{}'. - take(o[k]); - } - - // Repro from #23133 - - class Unbounded { - foo(x: T[keyof T]) { - let y: {} | undefined | null = x; - } - } - - // Repro from #23940 - - interface I7 { - x: any; - } - type Foo7 = T; - declare function f7(type: K): Foo7; - - // Repro from #21770 - - type Dict = { [key in T]: number }; - type DictDict = { [key in V]: Dict }; - - function ff1(dd: DictDict, k1: V, k2: T): number { - return dd[k1][k2]; - } - - function ff2(dd: DictDict, k1: V, k2: T): number { - const d: Dict = dd[k1]; - return d[k2]; - } - \ No newline at end of file diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index 8cb00c8a577fb..3434d003d54d6 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -2100,7 +2100,7 @@ function fn(o: T, k: K) { >k : K take<{} | null | undefined>(o[k]); ->take<{} | null | undefined>(o[k]) : any +>take<{} | null | undefined>(o[k]) : void >take : (p: T) => void >null : null >o[k] : T[K] diff --git a/tests/baselines/reference/mappedTypeErrors2.errors.txt b/tests/baselines/reference/mappedTypeErrors2.errors.txt index 12209cd84ac17..9178731d1894d 100644 --- a/tests/baselines/reference/mappedTypeErrors2.errors.txt +++ b/tests/baselines/reference/mappedTypeErrors2.errors.txt @@ -1,15 +1,13 @@ tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(9,30): error TS2536: Type 'K' cannot be used to index type 'T1'. tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(13,30): error TS2536: Type 'K' cannot be used to index type 'T3'. +tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(15,38): error TS2536: Type 'S' cannot be used to index type '{ [key in AB[S]]: true; }'. tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(15,47): error TS2322: Type 'AB[S]' is not assignable to type 'string | number | symbol'. - Type 'unknown' is not assignable to type 'string | number | symbol'. - Type 'unknown' is not assignable to type 'symbol'. - Type 'AB[S]' is not assignable to type 'symbol'. - Type 'unknown' is not assignable to type 'symbol'. + Type 'AB[S]' is not assignable to type 'symbol'. tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(15,47): error TS2536: Type 'S' cannot be used to index type 'AB'. tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(17,49): error TS2536: Type 'L' cannot be used to index type '{ [key in AB[S]]: true; }'. -==== tests/cases/conformance/types/mapped/mappedTypeErrors2.ts (5 errors) ==== +==== tests/cases/conformance/types/mapped/mappedTypeErrors2.ts (6 errors) ==== // Repros from #17238 type AB = { @@ -29,12 +27,11 @@ tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(17,49): error TS2536: !!! error TS2536: Type 'K' cannot be used to index type 'T3'. type T5 = {[key in AB[S]]: true}[S]; // Error + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2536: Type 'S' cannot be used to index type '{ [key in AB[S]]: true; }'. ~~~~~ !!! error TS2322: Type 'AB[S]' is not assignable to type 'string | number | symbol'. -!!! error TS2322: Type 'unknown' is not assignable to type 'string | number | symbol'. -!!! error TS2322: Type 'unknown' is not assignable to type 'symbol'. -!!! error TS2322: Type 'AB[S]' is not assignable to type 'symbol'. -!!! error TS2322: Type 'unknown' is not assignable to type 'symbol'. +!!! error TS2322: Type 'AB[S]' is not assignable to type 'symbol'. ~~~~~ !!! error TS2536: Type 'S' cannot be used to index type 'AB'. diff --git a/tests/baselines/reference/nonPrimitiveConstraintOfIndexAccessType.errors.txt b/tests/baselines/reference/nonPrimitiveConstraintOfIndexAccessType.errors.txt index 7cff0aec55d71..5784d8c46d0b4 100644 --- a/tests/baselines/reference/nonPrimitiveConstraintOfIndexAccessType.errors.txt +++ b/tests/baselines/reference/nonPrimitiveConstraintOfIndexAccessType.errors.txt @@ -1,22 +1,38 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(3,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(6,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(9,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(12,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(15,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. Type 'string' is not assignable to type 'never'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(18,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(21,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(24,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(27,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts(30,5): error TS2322: Type 'string' is not assignable to type 'T[P]'. Type 'string' is not assignable to type 'number'. -==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts (2 errors) ==== +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.ts (10 errors) ==== // test for #15371 function f(s: string, tp: T[P]): void { tp = s; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'T[P]'. } function g(s: string, tp: T[P]): void { tp = s; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'T[P]'. } function h(s: string, tp: T[P]): void { tp = s; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'T[P]'. } function i(s: string, tp: T[P]): void { tp = s; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'T[P]'. } function j(s: string, tp: T[P]): void { tp = s; @@ -26,15 +42,23 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessTy } function k(s: string, tp: T[P]): void { tp = s; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'T[P]'. } function o(s: string, tp: T[P]): void { tp = s; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'T[P]'. } function l(s: string, tp: T[P]): void { tp = s; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'T[P]'. } function m(s: string, tp: T[P]): void { tp = s; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'T[P]'. } function n(s: string, tp: T[P]): void { tp = s;