From ba7f084d53fdd8005ac1ae1357e258370218f14a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 15 Dec 2023 08:52:55 -0800 Subject: [PATCH 1/9] Add NoInfer intrinsic represented as special substitution type --- src/compiler/checker.ts | 50 ++++++++++++++++++++++++++++++++++------- src/compiler/types.ts | 5 +++-- src/lib/es5.d.ts | 5 +++++ 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cd89bbf688a53..41a1883b717b3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1363,6 +1363,7 @@ const enum IntrinsicTypeKind { Lowercase, Capitalize, Uncapitalize, + NoInfer, } const intrinsicTypeKinds: ReadonlyMap = new Map(Object.entries({ @@ -1370,6 +1371,7 @@ const intrinsicTypeKinds: ReadonlyMap = new Map(Objec Lowercase: IntrinsicTypeKind.Lowercase, Capitalize: IntrinsicTypeKind.Capitalize, Uncapitalize: IntrinsicTypeKind.Uncapitalize, + NoInfer: IntrinsicTypeKind.NoInfer, })); const SymbolLinks = class implements SymbolLinks { @@ -6710,7 +6712,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return visitAndTransformType(type, type => conditionalTypeToTypeNode(type as ConditionalType)); } if (type.flags & TypeFlags.Substitution) { - return typeToTypeNodeHelper((type as SubstitutionType).baseType, context); + const typeNode = typeToTypeNodeHelper((type as SubstitutionType).baseType, context); + return isNoInferType(type) ? factory.createTypeReferenceNode("NoInfer", [typeNode]) : typeNode; } return Debug.fail("Should be unreachable."); @@ -15866,8 +15869,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeAliasInstantiation(symbol: Symbol, typeArguments: readonly Type[] | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { const type = getDeclaredTypeOfSymbol(symbol); - if (type === intrinsicMarkerType && intrinsicTypeKinds.has(symbol.escapedName as string) && typeArguments && typeArguments.length === 1) { - return getStringMappingType(symbol, typeArguments[0]); + if (type === intrinsicMarkerType) { + const typeKind = intrinsicTypeKinds.get(symbol.escapedName as string); + if (typeKind !== undefined && typeArguments && typeArguments.length === 1) { + return typeKind === IntrinsicTypeKind.NoInfer ? getNoInferType(typeArguments[0]) : getStringMappingType(symbol, typeArguments[0]); + } } const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters!; @@ -16049,10 +16055,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.resolvedJSDocType; } + function getNoInferType(type: Type) { + return isNoInferTargetType(type) ? getOrCreateSubstitutionType(type, unknownType) : type; + } + + function isNoInferTargetType(type: Type): boolean { + // This is effectively a more conservative and predictable form of couldContainTypeVariables. We want to + // preserve NoInfer only for types that could contain type variables, but we don't want to exhaustively + // examine all object type members. + return !!(type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, isNoInferTargetType) || + type.flags & TypeFlags.Substitution && !isNoInferType(type) && isNoInferTargetType((type as SubstitutionType).baseType) || + type.flags & TypeFlags.Object && !isEmptyAnonymousObjectType(type) || + type.flags & (TypeFlags.Instantiable & ~TypeFlags.Substitution) && !isPatternLiteralType(type)); + } + + function isNoInferType(type: Type) { + // A NoInfer type is represented as a substitution type with a TypeFlags.Unknown constraint. + return !!(type.flags & TypeFlags.Substitution && (type as SubstitutionType).constraint.flags & TypeFlags.Unknown); + } + function getSubstitutionType(baseType: Type, constraint: Type) { - if (constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || baseType.flags & TypeFlags.Any) { - return baseType; - } + return constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || baseType.flags & TypeFlags.Any ? + baseType : + getOrCreateSubstitutionType(baseType, constraint); + } + + function getOrCreateSubstitutionType(baseType: Type, constraint: Type) { const id = `${getTypeId(baseType)}>${getTypeId(constraint)}`; const cached = substitutionTypes.get(id); if (cached) { @@ -16066,7 +16094,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getSubstitutionIntersection(substitutionType: SubstitutionType) { - return getIntersectionType([substitutionType.constraint, substitutionType.baseType]); + return isNoInferType(substitutionType) ? substitutionType.baseType : getIntersectionType([substitutionType.constraint, substitutionType.baseType]); } function isUnaryTupleTypeNode(node: TypeNode) { @@ -19822,6 +19850,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (flags & TypeFlags.Substitution) { const newBaseType = instantiateType((type as SubstitutionType).baseType, mapper); + if (isNoInferType(type)) { + return getNoInferType(newBaseType); + } const newConstraint = instantiateType((type as SubstitutionType).constraint, mapper); // A substitution type originates in the true branch of a conditional type and can be resolved // to just the base type in the same cases as the conditional type resolves to its true branch @@ -25281,7 +25312,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferFromTypes(originalSource, originalTarget); function inferFromTypes(source: Type, target: Type): void { - if (!couldContainTypeVariables(target)) { + if (!couldContainTypeVariables(target) || isNoInferType(target)) { return; } if (source === wildcardType || source === blockedStringType) { @@ -25354,6 +25385,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) { + if (isNoInferType(target)) { + return; + } target = getActualTypeVariable(target); } if (target.flags & TypeFlags.TypeVariable) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0bd4d4a1c9da0..fb373750ec6be 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6705,8 +6705,9 @@ export interface StringMappingType extends InstantiableType { // Substitution types are created for type parameters or indexed access types that occur in the // true branch of a conditional type. For example, in 'T extends string ? Foo : Bar', the // reference to T in Foo is resolved as a substitution type that substitutes 'string & T' for T. -// Thus, if Foo has a 'string' constraint on its type parameter, T will satisfy it. Substitution -// types disappear upon instantiation (just like type parameters). +// Thus, if Foo has a 'string' constraint on its type parameter, T will satisfy it. +// Substitution type are also created for NoInfer types. Those are represented as substitution +// types where the constraint is type 'unknown' (which is never generated for the case above). export interface SubstitutionType extends InstantiableType { objectFlags: ObjectFlags; baseType: Type; // Target type diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index f3df23047022d..1177ed2b51395 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -1648,6 +1648,11 @@ type Capitalize = intrinsic; */ type Uncapitalize = intrinsic; +/** + * Marker for non-inference type position + */ +type NoInfer = intrinsic; + /** * Marker for contextual 'this' type */ From 411205ef4c39a47321c965de16caf92c6f3c3436 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 15 Dec 2023 09:07:23 -0800 Subject: [PATCH 2/9] Update tests --- src/harness/fourslashInterfaceImpl.ts | 1 + .../autoImportProvider_namespaceSameNameAsIntrinsic.js | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 52e028c5070bb..309dc84fb45f4 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1195,6 +1195,7 @@ export namespace Completion { typeEntry("Lowercase"), typeEntry("Capitalize"), typeEntry("Uncapitalize"), + typeEntry("NoInfer"), interfaceEntry("ThisType"), varEntry("ArrayBuffer"), interfaceEntry("ArrayBufferTypes"), diff --git a/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_namespaceSameNameAsIntrinsic.js b/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_namespaceSameNameAsIntrinsic.js index f09783085489c..5cfac18b02449 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_namespaceSameNameAsIntrinsic.js +++ b/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_namespaceSameNameAsIntrinsic.js @@ -704,6 +704,12 @@ Info seq [hh:mm:ss:mss] response: "kindModifiers": "declare", "sortText": "15" }, + { + "name": "NoInfer", + "kind": "type", + "kindModifiers": "declare", + "sortText": "15" + }, { "name": "NonNullable", "kind": "type", From b25bf3ea054f2563020a73dd769e41645e5b968b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 15 Dec 2023 09:19:22 -0800 Subject: [PATCH 3/9] Add tests --- tests/baselines/reference/noInfer.errors.txt | 119 +++++++ tests/baselines/reference/noInfer.js | 185 +++++++++++ tests/baselines/reference/noInfer.symbols | 307 ++++++++++++++++++ tests/baselines/reference/noInfer.types | 286 ++++++++++++++++ .../typeInference/noInfer.ts | 78 +++++ 5 files changed, 975 insertions(+) create mode 100644 tests/baselines/reference/noInfer.errors.txt create mode 100644 tests/baselines/reference/noInfer.js create mode 100644 tests/baselines/reference/noInfer.symbols create mode 100644 tests/baselines/reference/noInfer.types create mode 100644 tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts diff --git a/tests/baselines/reference/noInfer.errors.txt b/tests/baselines/reference/noInfer.errors.txt new file mode 100644 index 0000000000000..8bb5c10706b42 --- /dev/null +++ b/tests/baselines/reference/noInfer.errors.txt @@ -0,0 +1,119 @@ +noInfer.ts(29,13): error TS2345: Argument of type '"bar"' is not assignable to parameter of type '"foo"'. +noInfer.ts(30,14): error TS2322: Type '"bar"' is not assignable to type '"foo"'. +noInfer.ts(31,14): error TS2322: Type '"bar"' is not assignable to type '"foo"'. +noInfer.ts(32,15): error TS2322: Type '"bar"' is not assignable to type '"foo"'. +noInfer.ts(33,15): error TS2322: Type '"bar"' is not assignable to type '"foo"'. +noInfer.ts(41,30): error TS2741: Property 'woof' is missing in type 'Animal' but required in type 'Dog'. +noInfer.ts(47,16): error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type '{ x: number; y: number; }'. + Property 'y' is missing in type '{ x: number; }' but required in type '{ x: number; y: number; }'. +noInfer.ts(52,22): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; }'. +noInfer.ts(53,14): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; }'. +noInfer.ts(60,14): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ foo: number; }'. + Property 'foo' is missing in type '{}' but required in type '{ foo: number; }'. + + +==== noInfer.ts (10 errors) ==== + // NoInfer is erased for primitives + + type T00 = NoInfer; + type T01 = NoInfer; + type T02 = NoInfer; + type T03 = NoInfer<"foo">; + type T04 = NoInfer<`foo${string}`>; + type T05 = NoInfer<`foo${string}` & `${string}bar`>; + type T06 = NoInfer<{}>; + + // NoInfer is preserved for object types + + type T10 = NoInfer; + type T11 = NoInfer<{ x: string }>; + + // NoInfer is erased if it has no effect + + type T20 = NoInfer>; + type T21 = NoInfer & string>; + type T22 = NoInfer & string[]>; + + declare function foo1(a: T, b: NoInfer): void + declare function foo2(a: T, b: NoInfer[]): void + declare function foo3(a: T, b: NoInfer): void + declare function foo4(a: T, b: { x: NoInfer }): void + declare function foo5(a: T, b: NoInfer<{ x: T }>): void + + foo1('foo', 'foo') // ok + foo1('foo', 'bar') // error + ~~~~~ +!!! error TS2345: Argument of type '"bar"' is not assignable to parameter of type '"foo"'. + foo2('foo', ['bar']) // error + ~~~~~ +!!! error TS2322: Type '"bar"' is not assignable to type '"foo"'. + foo3('foo', ['bar']) // error + ~~~~~ +!!! error TS2322: Type '"bar"' is not assignable to type '"foo"'. + foo4('foo', { x: 'bar' }) // error + ~ +!!! error TS2322: Type '"bar"' is not assignable to type '"foo"'. +!!! related TS6500 noInfer.ts:25:52: The expected type comes from property 'x' which is declared here on type '{ x: "foo"; }' + foo5('foo', { x: 'bar' }) // error + ~ +!!! error TS2322: Type '"bar"' is not assignable to type '"foo"'. +!!! related TS6500 noInfer.ts:26:60: The expected type comes from property 'x' which is declared here on type 'NoInfer<{ x: "foo"; }>' + + declare class Animal { move(): void } + declare class Dog extends Animal { woof(): void } + declare function doSomething(value: T, getDefault: () => NoInfer): void; + + doSomething(new Animal(), () => new Animal()); // ok + doSomething(new Animal(), () => new Dog()); // ok + doSomething(new Dog(), () => new Animal()); // error + ~~~~~~~~~~~~ +!!! error TS2741: Property 'woof' is missing in type 'Animal' but required in type 'Dog'. +!!! related TS2728 noInfer.ts:36:36: 'woof' is declared here. +!!! related TS6502 noInfer.ts:37:55: The expected type comes from the return type of this signature. + + declare function assertEqual(actual: T, expected: NoInfer): boolean; + + assertEqual({ x: 1 }, { x: 3 }); // ok + const g = { x: 3, y: 2 }; + assertEqual(g, { x: 3 }); // error + ~~~~~~~~ +!!! error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type '{ x: number; y: number; }'. +!!! error TS2345: Property 'y' is missing in type '{ x: number; }' but required in type '{ x: number; y: number; }'. +!!! related TS2728 noInfer.ts:46:19: 'y' is declared here. + + declare function invoke(func: (value: T) => R, value: NoInfer): R; + declare function test(value: { x: number; }): number; + + invoke(test, { x: 1, y: 2 }); // error + ~ +!!! error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; }'. + test({ x: 1, y: 2 }); // error + ~ +!!! error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; }'. + + type Component = { props: Props; }; + declare function doWork(Component: Component, props: NoInfer): void; + declare const comp: Component<{ foo: number }>; + + doWork(comp, { foo: 42 }); // ok + doWork(comp, {}); // error + ~~ +!!! error TS2345: Argument of type '{}' is not assignable to parameter of type '{ foo: number; }'. +!!! error TS2345: Property 'foo' is missing in type '{}' but required in type '{ foo: number; }'. +!!! related TS2728 noInfer.ts:57:33: 'foo' is declared here. + + declare function mutate(callback: (a: NoInfer, b: number) => T): T; + const mutate1 = mutate((a, b) => b); + + declare class ExampleClass {} + class OkClass { + constructor(private clazz: ExampleClass, private _value: NoInfer) {} + + get value(): T { + return this._value; // ok + } + } + class OkClass2 { + constructor(private clazz: ExampleClass, public _value: NoInfer) {} + } + \ No newline at end of file diff --git a/tests/baselines/reference/noInfer.js b/tests/baselines/reference/noInfer.js new file mode 100644 index 0000000000000..77f55dfb23ba3 --- /dev/null +++ b/tests/baselines/reference/noInfer.js @@ -0,0 +1,185 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts] //// + +//// [noInfer.ts] +// NoInfer is erased for primitives + +type T00 = NoInfer; +type T01 = NoInfer; +type T02 = NoInfer; +type T03 = NoInfer<"foo">; +type T04 = NoInfer<`foo${string}`>; +type T05 = NoInfer<`foo${string}` & `${string}bar`>; +type T06 = NoInfer<{}>; + +// NoInfer is preserved for object types + +type T10 = NoInfer; +type T11 = NoInfer<{ x: string }>; + +// NoInfer is erased if it has no effect + +type T20 = NoInfer>; +type T21 = NoInfer & string>; +type T22 = NoInfer & string[]>; + +declare function foo1(a: T, b: NoInfer): void +declare function foo2(a: T, b: NoInfer[]): void +declare function foo3(a: T, b: NoInfer): void +declare function foo4(a: T, b: { x: NoInfer }): void +declare function foo5(a: T, b: NoInfer<{ x: T }>): void + +foo1('foo', 'foo') // ok +foo1('foo', 'bar') // error +foo2('foo', ['bar']) // error +foo3('foo', ['bar']) // error +foo4('foo', { x: 'bar' }) // error +foo5('foo', { x: 'bar' }) // error + +declare class Animal { move(): void } +declare class Dog extends Animal { woof(): void } +declare function doSomething(value: T, getDefault: () => NoInfer): void; + +doSomething(new Animal(), () => new Animal()); // ok +doSomething(new Animal(), () => new Dog()); // ok +doSomething(new Dog(), () => new Animal()); // error + +declare function assertEqual(actual: T, expected: NoInfer): boolean; + +assertEqual({ x: 1 }, { x: 3 }); // ok +const g = { x: 3, y: 2 }; +assertEqual(g, { x: 3 }); // error + +declare function invoke(func: (value: T) => R, value: NoInfer): R; +declare function test(value: { x: number; }): number; + +invoke(test, { x: 1, y: 2 }); // error +test({ x: 1, y: 2 }); // error + +type Component = { props: Props; }; +declare function doWork(Component: Component, props: NoInfer): void; +declare const comp: Component<{ foo: number }>; + +doWork(comp, { foo: 42 }); // ok +doWork(comp, {}); // error + +declare function mutate(callback: (a: NoInfer, b: number) => T): T; +const mutate1 = mutate((a, b) => b); + +declare class ExampleClass {} +class OkClass { + constructor(private clazz: ExampleClass, private _value: NoInfer) {} + + get value(): T { + return this._value; // ok + } +} +class OkClass2 { + constructor(private clazz: ExampleClass, public _value: NoInfer) {} +} + + +//// [noInfer.js] +"use strict"; +// NoInfer is erased for primitives +foo1('foo', 'foo'); // ok +foo1('foo', 'bar'); // error +foo2('foo', ['bar']); // error +foo3('foo', ['bar']); // error +foo4('foo', { x: 'bar' }); // error +foo5('foo', { x: 'bar' }); // error +doSomething(new Animal(), function () { return new Animal(); }); // ok +doSomething(new Animal(), function () { return new Dog(); }); // ok +doSomething(new Dog(), function () { return new Animal(); }); // error +assertEqual({ x: 1 }, { x: 3 }); // ok +var g = { x: 3, y: 2 }; +assertEqual(g, { x: 3 }); // error +invoke(test, { x: 1, y: 2 }); // error +test({ x: 1, y: 2 }); // error +doWork(comp, { foo: 42 }); // ok +doWork(comp, {}); // error +var mutate1 = mutate(function (a, b) { return b; }); +var OkClass = /** @class */ (function () { + function OkClass(clazz, _value) { + this.clazz = clazz; + this._value = _value; + } + Object.defineProperty(OkClass.prototype, "value", { + get: function () { + return this._value; // ok + }, + enumerable: false, + configurable: true + }); + return OkClass; +}()); +var OkClass2 = /** @class */ (function () { + function OkClass2(clazz, _value) { + this.clazz = clazz; + this._value = _value; + } + return OkClass2; +}()); + + +//// [noInfer.d.ts] +type T00 = NoInfer; +type T01 = NoInfer; +type T02 = NoInfer; +type T03 = NoInfer<"foo">; +type T04 = NoInfer<`foo${string}`>; +type T05 = NoInfer<`foo${string}` & `${string}bar`>; +type T06 = NoInfer<{}>; +type T10 = NoInfer; +type T11 = NoInfer<{ + x: string; +}>; +type T20 = NoInfer>; +type T21 = NoInfer & string>; +type T22 = NoInfer & string[]>; +declare function foo1(a: T, b: NoInfer): void; +declare function foo2(a: T, b: NoInfer[]): void; +declare function foo3(a: T, b: NoInfer): void; +declare function foo4(a: T, b: { + x: NoInfer; +}): void; +declare function foo5(a: T, b: NoInfer<{ + x: T; +}>): void; +declare class Animal { + move(): void; +} +declare class Dog extends Animal { + woof(): void; +} +declare function doSomething(value: T, getDefault: () => NoInfer): void; +declare function assertEqual(actual: T, expected: NoInfer): boolean; +declare const g: { + x: number; + y: number; +}; +declare function invoke(func: (value: T) => R, value: NoInfer): R; +declare function test(value: { + x: number; +}): number; +type Component = { + props: Props; +}; +declare function doWork(Component: Component, props: NoInfer): void; +declare const comp: Component<{ + foo: number; +}>; +declare function mutate(callback: (a: NoInfer, b: number) => T): T; +declare const mutate1: unknown; +declare class ExampleClass { +} +declare class OkClass { + private clazz; + private _value; + constructor(clazz: ExampleClass, _value: NoInfer); + get value(): T; +} +declare class OkClass2 { + private clazz; + _value: NoInfer; + constructor(clazz: ExampleClass, _value: NoInfer); +} diff --git a/tests/baselines/reference/noInfer.symbols b/tests/baselines/reference/noInfer.symbols new file mode 100644 index 0000000000000..67d5ca7538a57 --- /dev/null +++ b/tests/baselines/reference/noInfer.symbols @@ -0,0 +1,307 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts] //// + +=== noInfer.ts === +// NoInfer is erased for primitives + +type T00 = NoInfer; +>T00 : Symbol(T00, Decl(noInfer.ts, 0, 0)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +type T01 = NoInfer; +>T01 : Symbol(T01, Decl(noInfer.ts, 2, 27)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +type T02 = NoInfer; +>T02 : Symbol(T02, Decl(noInfer.ts, 3, 46)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +type T03 = NoInfer<"foo">; +>T03 : Symbol(T03, Decl(noInfer.ts, 4, 30)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +type T04 = NoInfer<`foo${string}`>; +>T04 : Symbol(T04, Decl(noInfer.ts, 5, 26)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +type T05 = NoInfer<`foo${string}` & `${string}bar`>; +>T05 : Symbol(T05, Decl(noInfer.ts, 6, 35)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +type T06 = NoInfer<{}>; +>T06 : Symbol(T06, Decl(noInfer.ts, 7, 52)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +// NoInfer is preserved for object types + +type T10 = NoInfer; +>T10 : Symbol(T10, Decl(noInfer.ts, 8, 23)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +type T11 = NoInfer<{ x: string }>; +>T11 : Symbol(T11, Decl(noInfer.ts, 12, 29)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(noInfer.ts, 13, 20)) + +// NoInfer is erased if it has no effect + +type T20 = NoInfer>; +>T20 : Symbol(T20, Decl(noInfer.ts, 13, 34)) +>T : Symbol(T, Decl(noInfer.ts, 17, 9)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 17, 9)) + +type T21 = NoInfer & string>; +>T21 : Symbol(T21, Decl(noInfer.ts, 17, 34)) +>T : Symbol(T, Decl(noInfer.ts, 18, 9)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 18, 9)) + +type T22 = NoInfer & string[]>; +>T22 : Symbol(T22, Decl(noInfer.ts, 18, 43)) +>T : Symbol(T, Decl(noInfer.ts, 19, 9)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 19, 9)) + +declare function foo1(a: T, b: NoInfer): void +>foo1 : Symbol(foo1, Decl(noInfer.ts, 19, 45)) +>T : Symbol(T, Decl(noInfer.ts, 21, 22)) +>a : Symbol(a, Decl(noInfer.ts, 21, 40)) +>T : Symbol(T, Decl(noInfer.ts, 21, 22)) +>b : Symbol(b, Decl(noInfer.ts, 21, 45)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 21, 22)) + +declare function foo2(a: T, b: NoInfer[]): void +>foo2 : Symbol(foo2, Decl(noInfer.ts, 21, 66)) +>T : Symbol(T, Decl(noInfer.ts, 22, 22)) +>a : Symbol(a, Decl(noInfer.ts, 22, 40)) +>T : Symbol(T, Decl(noInfer.ts, 22, 22)) +>b : Symbol(b, Decl(noInfer.ts, 22, 45)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 22, 22)) + +declare function foo3(a: T, b: NoInfer): void +>foo3 : Symbol(foo3, Decl(noInfer.ts, 22, 68)) +>T : Symbol(T, Decl(noInfer.ts, 23, 22)) +>a : Symbol(a, Decl(noInfer.ts, 23, 40)) +>T : Symbol(T, Decl(noInfer.ts, 23, 22)) +>b : Symbol(b, Decl(noInfer.ts, 23, 45)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 23, 22)) + +declare function foo4(a: T, b: { x: NoInfer }): void +>foo4 : Symbol(foo4, Decl(noInfer.ts, 23, 68)) +>T : Symbol(T, Decl(noInfer.ts, 24, 22)) +>a : Symbol(a, Decl(noInfer.ts, 24, 40)) +>T : Symbol(T, Decl(noInfer.ts, 24, 22)) +>b : Symbol(b, Decl(noInfer.ts, 24, 45)) +>x : Symbol(x, Decl(noInfer.ts, 24, 50)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 24, 22)) + +declare function foo5(a: T, b: NoInfer<{ x: T }>): void +>foo5 : Symbol(foo5, Decl(noInfer.ts, 24, 73)) +>T : Symbol(T, Decl(noInfer.ts, 25, 22)) +>a : Symbol(a, Decl(noInfer.ts, 25, 40)) +>T : Symbol(T, Decl(noInfer.ts, 25, 22)) +>b : Symbol(b, Decl(noInfer.ts, 25, 45)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(noInfer.ts, 25, 58)) +>T : Symbol(T, Decl(noInfer.ts, 25, 22)) + +foo1('foo', 'foo') // ok +>foo1 : Symbol(foo1, Decl(noInfer.ts, 19, 45)) + +foo1('foo', 'bar') // error +>foo1 : Symbol(foo1, Decl(noInfer.ts, 19, 45)) + +foo2('foo', ['bar']) // error +>foo2 : Symbol(foo2, Decl(noInfer.ts, 21, 66)) + +foo3('foo', ['bar']) // error +>foo3 : Symbol(foo3, Decl(noInfer.ts, 22, 68)) + +foo4('foo', { x: 'bar' }) // error +>foo4 : Symbol(foo4, Decl(noInfer.ts, 23, 68)) +>x : Symbol(x, Decl(noInfer.ts, 31, 13)) + +foo5('foo', { x: 'bar' }) // error +>foo5 : Symbol(foo5, Decl(noInfer.ts, 24, 73)) +>x : Symbol(x, Decl(noInfer.ts, 32, 13)) + +declare class Animal { move(): void } +>Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) +>move : Symbol(Animal.move, Decl(noInfer.ts, 34, 22)) + +declare class Dog extends Animal { woof(): void } +>Dog : Symbol(Dog, Decl(noInfer.ts, 34, 37)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) +>woof : Symbol(Dog.woof, Decl(noInfer.ts, 35, 34)) + +declare function doSomething(value: T, getDefault: () => NoInfer): void; +>doSomething : Symbol(doSomething, Decl(noInfer.ts, 35, 49)) +>T : Symbol(T, Decl(noInfer.ts, 36, 29)) +>value : Symbol(value, Decl(noInfer.ts, 36, 32)) +>T : Symbol(T, Decl(noInfer.ts, 36, 29)) +>getDefault : Symbol(getDefault, Decl(noInfer.ts, 36, 41)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 36, 29)) + +doSomething(new Animal(), () => new Animal()); // ok +>doSomething : Symbol(doSomething, Decl(noInfer.ts, 35, 49)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) + +doSomething(new Animal(), () => new Dog()); // ok +>doSomething : Symbol(doSomething, Decl(noInfer.ts, 35, 49)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) +>Dog : Symbol(Dog, Decl(noInfer.ts, 34, 37)) + +doSomething(new Dog(), () => new Animal()); // error +>doSomething : Symbol(doSomething, Decl(noInfer.ts, 35, 49)) +>Dog : Symbol(Dog, Decl(noInfer.ts, 34, 37)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) + +declare function assertEqual(actual: T, expected: NoInfer): boolean; +>assertEqual : Symbol(assertEqual, Decl(noInfer.ts, 40, 43)) +>T : Symbol(T, Decl(noInfer.ts, 42, 29)) +>actual : Symbol(actual, Decl(noInfer.ts, 42, 32)) +>T : Symbol(T, Decl(noInfer.ts, 42, 29)) +>expected : Symbol(expected, Decl(noInfer.ts, 42, 42)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 42, 29)) + +assertEqual({ x: 1 }, { x: 3 }); // ok +>assertEqual : Symbol(assertEqual, Decl(noInfer.ts, 40, 43)) +>x : Symbol(x, Decl(noInfer.ts, 44, 13)) +>x : Symbol(x, Decl(noInfer.ts, 44, 23)) + +const g = { x: 3, y: 2 }; +>g : Symbol(g, Decl(noInfer.ts, 45, 5)) +>x : Symbol(x, Decl(noInfer.ts, 45, 11)) +>y : Symbol(y, Decl(noInfer.ts, 45, 17)) + +assertEqual(g, { x: 3 }); // error +>assertEqual : Symbol(assertEqual, Decl(noInfer.ts, 40, 43)) +>g : Symbol(g, Decl(noInfer.ts, 45, 5)) +>x : Symbol(x, Decl(noInfer.ts, 46, 16)) + +declare function invoke(func: (value: T) => R, value: NoInfer): R; +>invoke : Symbol(invoke, Decl(noInfer.ts, 46, 25)) +>T : Symbol(T, Decl(noInfer.ts, 48, 24)) +>R : Symbol(R, Decl(noInfer.ts, 48, 26)) +>func : Symbol(func, Decl(noInfer.ts, 48, 30)) +>value : Symbol(value, Decl(noInfer.ts, 48, 37)) +>T : Symbol(T, Decl(noInfer.ts, 48, 24)) +>R : Symbol(R, Decl(noInfer.ts, 48, 26)) +>value : Symbol(value, Decl(noInfer.ts, 48, 52)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 48, 24)) +>R : Symbol(R, Decl(noInfer.ts, 48, 26)) + +declare function test(value: { x: number; }): number; +>test : Symbol(test, Decl(noInfer.ts, 48, 75)) +>value : Symbol(value, Decl(noInfer.ts, 49, 22)) +>x : Symbol(x, Decl(noInfer.ts, 49, 30)) + +invoke(test, { x: 1, y: 2 }); // error +>invoke : Symbol(invoke, Decl(noInfer.ts, 46, 25)) +>test : Symbol(test, Decl(noInfer.ts, 48, 75)) +>x : Symbol(x, Decl(noInfer.ts, 51, 14)) +>y : Symbol(y, Decl(noInfer.ts, 51, 20)) + +test({ x: 1, y: 2 }); // error +>test : Symbol(test, Decl(noInfer.ts, 48, 75)) +>x : Symbol(x, Decl(noInfer.ts, 52, 6)) +>y : Symbol(y, Decl(noInfer.ts, 52, 12)) + +type Component = { props: Props; }; +>Component : Symbol(Component, Decl(noInfer.ts, 52, 21)) +>Props : Symbol(Props, Decl(noInfer.ts, 54, 15)) +>props : Symbol(props, Decl(noInfer.ts, 54, 25)) +>Props : Symbol(Props, Decl(noInfer.ts, 54, 15)) + +declare function doWork(Component: Component, props: NoInfer): void; +>doWork : Symbol(doWork, Decl(noInfer.ts, 54, 42)) +>Props : Symbol(Props, Decl(noInfer.ts, 55, 24)) +>Component : Symbol(Component, Decl(noInfer.ts, 55, 31)) +>Component : Symbol(Component, Decl(noInfer.ts, 52, 21)) +>Props : Symbol(Props, Decl(noInfer.ts, 55, 24)) +>props : Symbol(props, Decl(noInfer.ts, 55, 59)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>Props : Symbol(Props, Decl(noInfer.ts, 55, 24)) + +declare const comp: Component<{ foo: number }>; +>comp : Symbol(comp, Decl(noInfer.ts, 56, 13)) +>Component : Symbol(Component, Decl(noInfer.ts, 52, 21)) +>foo : Symbol(foo, Decl(noInfer.ts, 56, 31)) + +doWork(comp, { foo: 42 }); // ok +>doWork : Symbol(doWork, Decl(noInfer.ts, 54, 42)) +>comp : Symbol(comp, Decl(noInfer.ts, 56, 13)) +>foo : Symbol(foo, Decl(noInfer.ts, 58, 14)) + +doWork(comp, {}); // error +>doWork : Symbol(doWork, Decl(noInfer.ts, 54, 42)) +>comp : Symbol(comp, Decl(noInfer.ts, 56, 13)) + +declare function mutate(callback: (a: NoInfer, b: number) => T): T; +>mutate : Symbol(mutate, Decl(noInfer.ts, 59, 17)) +>T : Symbol(T, Decl(noInfer.ts, 61, 24)) +>callback : Symbol(callback, Decl(noInfer.ts, 61, 27)) +>a : Symbol(a, Decl(noInfer.ts, 61, 38)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 61, 24)) +>b : Symbol(b, Decl(noInfer.ts, 61, 52)) +>T : Symbol(T, Decl(noInfer.ts, 61, 24)) +>T : Symbol(T, Decl(noInfer.ts, 61, 24)) + +const mutate1 = mutate((a, b) => b); +>mutate1 : Symbol(mutate1, Decl(noInfer.ts, 62, 5)) +>mutate : Symbol(mutate, Decl(noInfer.ts, 59, 17)) +>a : Symbol(a, Decl(noInfer.ts, 62, 24)) +>b : Symbol(b, Decl(noInfer.ts, 62, 26)) +>b : Symbol(b, Decl(noInfer.ts, 62, 26)) + +declare class ExampleClass {} +>ExampleClass : Symbol(ExampleClass, Decl(noInfer.ts, 62, 36)) +>T : Symbol(T, Decl(noInfer.ts, 64, 27)) + +class OkClass { +>OkClass : Symbol(OkClass, Decl(noInfer.ts, 64, 32)) +>T : Symbol(T, Decl(noInfer.ts, 65, 14)) + + constructor(private clazz: ExampleClass, private _value: NoInfer) {} +>clazz : Symbol(OkClass.clazz, Decl(noInfer.ts, 66, 16)) +>ExampleClass : Symbol(ExampleClass, Decl(noInfer.ts, 62, 36)) +>T : Symbol(T, Decl(noInfer.ts, 65, 14)) +>_value : Symbol(OkClass._value, Decl(noInfer.ts, 66, 47)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 65, 14)) + + get value(): T { +>value : Symbol(OkClass.value, Decl(noInfer.ts, 66, 78)) +>T : Symbol(T, Decl(noInfer.ts, 65, 14)) + + return this._value; // ok +>this._value : Symbol(OkClass._value, Decl(noInfer.ts, 66, 47)) +>this : Symbol(OkClass, Decl(noInfer.ts, 64, 32)) +>_value : Symbol(OkClass._value, Decl(noInfer.ts, 66, 47)) + } +} +class OkClass2 { +>OkClass2 : Symbol(OkClass2, Decl(noInfer.ts, 71, 1)) +>T : Symbol(T, Decl(noInfer.ts, 72, 15)) + + constructor(private clazz: ExampleClass, public _value: NoInfer) {} +>clazz : Symbol(OkClass2.clazz, Decl(noInfer.ts, 73, 16)) +>ExampleClass : Symbol(ExampleClass, Decl(noInfer.ts, 62, 36)) +>T : Symbol(T, Decl(noInfer.ts, 72, 15)) +>_value : Symbol(OkClass2._value, Decl(noInfer.ts, 73, 47)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 72, 15)) +} + diff --git a/tests/baselines/reference/noInfer.types b/tests/baselines/reference/noInfer.types new file mode 100644 index 0000000000000..c1427c8878daf --- /dev/null +++ b/tests/baselines/reference/noInfer.types @@ -0,0 +1,286 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts] //// + +=== noInfer.ts === +// NoInfer is erased for primitives + +type T00 = NoInfer; +>T00 : string + +type T01 = NoInfer; +>T01 : string | number | boolean + +type T02 = NoInfer; +>T02 : undefined + +type T03 = NoInfer<"foo">; +>T03 : "foo" + +type T04 = NoInfer<`foo${string}`>; +>T04 : `foo${string}` + +type T05 = NoInfer<`foo${string}` & `${string}bar`>; +>T05 : `foo${string}` & `${string}bar` + +type T06 = NoInfer<{}>; +>T06 : {} + +// NoInfer is preserved for object types + +type T10 = NoInfer; +>T10 : NoInfer + +type T11 = NoInfer<{ x: string }>; +>T11 : NoInfer<{ x: string; }> +>x : string + +// NoInfer is erased if it has no effect + +type T20 = NoInfer>; +>T20 : NoInfer + +type T21 = NoInfer & string>; +>T21 : NoInfer & string + +type T22 = NoInfer & string[]>; +>T22 : NoInfer & string[]> + +declare function foo1(a: T, b: NoInfer): void +>foo1 : (a: T, b: NoInfer) => void +>a : T +>b : NoInfer + +declare function foo2(a: T, b: NoInfer[]): void +>foo2 : (a: T, b: NoInfer[]) => void +>a : T +>b : NoInfer[] + +declare function foo3(a: T, b: NoInfer): void +>foo3 : (a: T, b: NoInfer) => void +>a : T +>b : NoInfer + +declare function foo4(a: T, b: { x: NoInfer }): void +>foo4 : (a: T, b: { x: NoInfer;}) => void +>a : T +>b : { x: NoInfer; } +>x : NoInfer + +declare function foo5(a: T, b: NoInfer<{ x: T }>): void +>foo5 : (a: T, b: NoInfer<{ x: T;}>) => void +>a : T +>b : NoInfer<{ x: T; }> +>x : T + +foo1('foo', 'foo') // ok +>foo1('foo', 'foo') : void +>foo1 : (a: T, b: NoInfer) => void +>'foo' : "foo" +>'foo' : "foo" + +foo1('foo', 'bar') // error +>foo1('foo', 'bar') : void +>foo1 : (a: T, b: NoInfer) => void +>'foo' : "foo" +>'bar' : "bar" + +foo2('foo', ['bar']) // error +>foo2('foo', ['bar']) : void +>foo2 : (a: T, b: NoInfer[]) => void +>'foo' : "foo" +>['bar'] : "bar"[] +>'bar' : "bar" + +foo3('foo', ['bar']) // error +>foo3('foo', ['bar']) : void +>foo3 : (a: T, b: NoInfer) => void +>'foo' : "foo" +>['bar'] : "bar"[] +>'bar' : "bar" + +foo4('foo', { x: 'bar' }) // error +>foo4('foo', { x: 'bar' }) : void +>foo4 : (a: T, b: { x: NoInfer; }) => void +>'foo' : "foo" +>{ x: 'bar' } : { x: "bar"; } +>x : "bar" +>'bar' : "bar" + +foo5('foo', { x: 'bar' }) // error +>foo5('foo', { x: 'bar' }) : void +>foo5 : (a: T, b: NoInfer<{ x: T; }>) => void +>'foo' : "foo" +>{ x: 'bar' } : { x: "bar"; } +>x : "bar" +>'bar' : "bar" + +declare class Animal { move(): void } +>Animal : Animal +>move : () => void + +declare class Dog extends Animal { woof(): void } +>Dog : Dog +>Animal : Animal +>woof : () => void + +declare function doSomething(value: T, getDefault: () => NoInfer): void; +>doSomething : (value: T, getDefault: () => NoInfer) => void +>value : T +>getDefault : () => NoInfer + +doSomething(new Animal(), () => new Animal()); // ok +>doSomething(new Animal(), () => new Animal()) : void +>doSomething : (value: T, getDefault: () => NoInfer) => void +>new Animal() : Animal +>Animal : typeof Animal +>() => new Animal() : () => Animal +>new Animal() : Animal +>Animal : typeof Animal + +doSomething(new Animal(), () => new Dog()); // ok +>doSomething(new Animal(), () => new Dog()) : void +>doSomething : (value: T, getDefault: () => NoInfer) => void +>new Animal() : Animal +>Animal : typeof Animal +>() => new Dog() : () => Dog +>new Dog() : Dog +>Dog : typeof Dog + +doSomething(new Dog(), () => new Animal()); // error +>doSomething(new Dog(), () => new Animal()) : void +>doSomething : (value: T, getDefault: () => NoInfer) => void +>new Dog() : Dog +>Dog : typeof Dog +>() => new Animal() : () => Animal +>new Animal() : Animal +>Animal : typeof Animal + +declare function assertEqual(actual: T, expected: NoInfer): boolean; +>assertEqual : (actual: T, expected: NoInfer) => boolean +>actual : T +>expected : NoInfer + +assertEqual({ x: 1 }, { x: 3 }); // ok +>assertEqual({ x: 1 }, { x: 3 }) : boolean +>assertEqual : (actual: T, expected: NoInfer) => boolean +>{ x: 1 } : { x: number; } +>x : number +>1 : 1 +>{ x: 3 } : { x: number; } +>x : number +>3 : 3 + +const g = { x: 3, y: 2 }; +>g : { x: number; y: number; } +>{ x: 3, y: 2 } : { x: number; y: number; } +>x : number +>3 : 3 +>y : number +>2 : 2 + +assertEqual(g, { x: 3 }); // error +>assertEqual(g, { x: 3 }) : boolean +>assertEqual : (actual: T, expected: NoInfer) => boolean +>g : { x: number; y: number; } +>{ x: 3 } : { x: number; } +>x : number +>3 : 3 + +declare function invoke(func: (value: T) => R, value: NoInfer): R; +>invoke : (func: (value: T) => R, value: NoInfer) => R +>func : (value: T) => R +>value : T +>value : NoInfer + +declare function test(value: { x: number; }): number; +>test : (value: { x: number;}) => number +>value : { x: number; } +>x : number + +invoke(test, { x: 1, y: 2 }); // error +>invoke(test, { x: 1, y: 2 }) : number +>invoke : (func: (value: T) => R, value: NoInfer) => R +>test : (value: { x: number; }) => number +>{ x: 1, y: 2 } : { x: number; y: number; } +>x : number +>1 : 1 +>y : number +>2 : 2 + +test({ x: 1, y: 2 }); // error +>test({ x: 1, y: 2 }) : number +>test : (value: { x: number; }) => number +>{ x: 1, y: 2 } : { x: number; y: number; } +>x : number +>1 : 1 +>y : number +>2 : 2 + +type Component = { props: Props; }; +>Component : Component +>props : Props + +declare function doWork(Component: Component, props: NoInfer): void; +>doWork : (Component: Component, props: NoInfer) => void +>Component : Component +>props : NoInfer + +declare const comp: Component<{ foo: number }>; +>comp : Component<{ foo: number; }> +>foo : number + +doWork(comp, { foo: 42 }); // ok +>doWork(comp, { foo: 42 }) : void +>doWork : (Component: Component, props: NoInfer) => void +>comp : Component<{ foo: number; }> +>{ foo: 42 } : { foo: number; } +>foo : number +>42 : 42 + +doWork(comp, {}); // error +>doWork(comp, {}) : void +>doWork : (Component: Component, props: NoInfer) => void +>comp : Component<{ foo: number; }> +>{} : {} + +declare function mutate(callback: (a: NoInfer, b: number) => T): T; +>mutate : (callback: (a: NoInfer, b: number) => T) => T +>callback : (a: NoInfer, b: number) => T +>a : NoInfer +>b : number + +const mutate1 = mutate((a, b) => b); +>mutate1 : unknown +>mutate((a, b) => b) : unknown +>mutate : (callback: (a: NoInfer, b: number) => T) => T +>(a, b) => b : (a: unknown, b: number) => number +>a : unknown +>b : number +>b : number + +declare class ExampleClass {} +>ExampleClass : ExampleClass + +class OkClass { +>OkClass : OkClass + + constructor(private clazz: ExampleClass, private _value: NoInfer) {} +>clazz : ExampleClass +>_value : NoInfer + + get value(): T { +>value : T + + return this._value; // ok +>this._value : NoInfer +>this : this +>_value : NoInfer + } +} +class OkClass2 { +>OkClass2 : OkClass2 + + constructor(private clazz: ExampleClass, public _value: NoInfer) {} +>clazz : ExampleClass +>_value : NoInfer +} + diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts b/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts new file mode 100644 index 0000000000000..30296f2a7cba3 --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts @@ -0,0 +1,78 @@ +// @strict: true +// @declaration: true + +// NoInfer is erased for primitives + +type T00 = NoInfer; +type T01 = NoInfer; +type T02 = NoInfer; +type T03 = NoInfer<"foo">; +type T04 = NoInfer<`foo${string}`>; +type T05 = NoInfer<`foo${string}` & `${string}bar`>; +type T06 = NoInfer<{}>; + +// NoInfer is preserved for object types + +type T10 = NoInfer; +type T11 = NoInfer<{ x: string }>; + +// NoInfer is erased if it has no effect + +type T20 = NoInfer>; +type T21 = NoInfer & string>; +type T22 = NoInfer & string[]>; + +declare function foo1(a: T, b: NoInfer): void +declare function foo2(a: T, b: NoInfer[]): void +declare function foo3(a: T, b: NoInfer): void +declare function foo4(a: T, b: { x: NoInfer }): void +declare function foo5(a: T, b: NoInfer<{ x: T }>): void + +foo1('foo', 'foo') // ok +foo1('foo', 'bar') // error +foo2('foo', ['bar']) // error +foo3('foo', ['bar']) // error +foo4('foo', { x: 'bar' }) // error +foo5('foo', { x: 'bar' }) // error + +declare class Animal { move(): void } +declare class Dog extends Animal { woof(): void } +declare function doSomething(value: T, getDefault: () => NoInfer): void; + +doSomething(new Animal(), () => new Animal()); // ok +doSomething(new Animal(), () => new Dog()); // ok +doSomething(new Dog(), () => new Animal()); // error + +declare function assertEqual(actual: T, expected: NoInfer): boolean; + +assertEqual({ x: 1 }, { x: 3 }); // ok +const g = { x: 3, y: 2 }; +assertEqual(g, { x: 3 }); // error + +declare function invoke(func: (value: T) => R, value: NoInfer): R; +declare function test(value: { x: number; }): number; + +invoke(test, { x: 1, y: 2 }); // error +test({ x: 1, y: 2 }); // error + +type Component = { props: Props; }; +declare function doWork(Component: Component, props: NoInfer): void; +declare const comp: Component<{ foo: number }>; + +doWork(comp, { foo: 42 }); // ok +doWork(comp, {}); // error + +declare function mutate(callback: (a: NoInfer, b: number) => T): T; +const mutate1 = mutate((a, b) => b); + +declare class ExampleClass {} +class OkClass { + constructor(private clazz: ExampleClass, private _value: NoInfer) {} + + get value(): T { + return this._value; // ok + } +} +class OkClass2 { + constructor(private clazz: ExampleClass, public _value: NoInfer) {} +} From 9438168a85b0adfc7ac870f0231e417b06083cd8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Dec 2023 07:57:03 -1000 Subject: [PATCH 4/9] Erase NoInfer in index types --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 41a1883b717b3..3d1ccfeed4f89 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17759,7 +17759,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function shouldDeferIndexType(type: Type, indexFlags = IndexFlags.None) { - return !!(type.flags & TypeFlags.InstantiableNonPrimitive || + return !!(type.flags & TypeFlags.InstantiableNonPrimitive && !isNoInferType(type) || isGenericTupleType(type) || isGenericMappedType(type) && (!hasDistributiveNameType(type) || getMappedTypeNameTypeKind(type) === MappedTypeNameTypeKind.Remapping) || type.flags & TypeFlags.Union && !(indexFlags & IndexFlags.NoReducibleCheck) && isGenericReducibleType(type) || @@ -17771,6 +17771,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return shouldDeferIndexType(type, indexFlags) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, indexFlags) : type.flags & TypeFlags.Union ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, indexFlags))) : type.flags & TypeFlags.Intersection ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, indexFlags))) : + type.flags & TypeFlags.Substitution ? getIndexType((type as SubstitutionType).baseType, indexFlags) : getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, indexFlags) : type === wildcardType ? wildcardType : type.flags & TypeFlags.Unknown ? neverType : From e49245167956ecda1e3f3d56078b36bc2a8cd25c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Dec 2023 07:57:11 -1000 Subject: [PATCH 5/9] Add tests --- tests/baselines/reference/noInfer.errors.txt | 38 ++- tests/baselines/reference/noInfer.js | 17 + tests/baselines/reference/noInfer.symbols | 318 ++++++++++-------- tests/baselines/reference/noInfer.types | 15 + .../typeInference/noInfer.ts | 6 + 5 files changed, 230 insertions(+), 164 deletions(-) diff --git a/tests/baselines/reference/noInfer.errors.txt b/tests/baselines/reference/noInfer.errors.txt index 8bb5c10706b42..acf06ca1f0325 100644 --- a/tests/baselines/reference/noInfer.errors.txt +++ b/tests/baselines/reference/noInfer.errors.txt @@ -1,14 +1,14 @@ -noInfer.ts(29,13): error TS2345: Argument of type '"bar"' is not assignable to parameter of type '"foo"'. -noInfer.ts(30,14): error TS2322: Type '"bar"' is not assignable to type '"foo"'. -noInfer.ts(31,14): error TS2322: Type '"bar"' is not assignable to type '"foo"'. -noInfer.ts(32,15): error TS2322: Type '"bar"' is not assignable to type '"foo"'. -noInfer.ts(33,15): error TS2322: Type '"bar"' is not assignable to type '"foo"'. -noInfer.ts(41,30): error TS2741: Property 'woof' is missing in type 'Animal' but required in type 'Dog'. -noInfer.ts(47,16): error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type '{ x: number; y: number; }'. +noInfer.ts(35,13): error TS2345: Argument of type '"bar"' is not assignable to parameter of type '"foo"'. +noInfer.ts(36,14): error TS2322: Type '"bar"' is not assignable to type '"foo"'. +noInfer.ts(37,14): error TS2322: Type '"bar"' is not assignable to type '"foo"'. +noInfer.ts(38,15): error TS2322: Type '"bar"' is not assignable to type '"foo"'. +noInfer.ts(39,15): error TS2322: Type '"bar"' is not assignable to type '"foo"'. +noInfer.ts(47,30): error TS2741: Property 'woof' is missing in type 'Animal' but required in type 'Dog'. +noInfer.ts(53,16): error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type '{ x: number; y: number; }'. Property 'y' is missing in type '{ x: number; }' but required in type '{ x: number; y: number; }'. -noInfer.ts(52,22): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; }'. -noInfer.ts(53,14): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; }'. -noInfer.ts(60,14): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ foo: number; }'. +noInfer.ts(58,22): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; }'. +noInfer.ts(59,14): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; }'. +noInfer.ts(66,14): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ foo: number; }'. Property 'foo' is missing in type '{}' but required in type '{ foo: number; }'. @@ -34,6 +34,12 @@ noInfer.ts(60,14): error TS2345: Argument of type '{}' is not assignable to para type T21 = NoInfer & string>; type T22 = NoInfer & string[]>; + // NoInfer is erased in index types and mapped types + + type T30 = keyof NoInfer<{ a: string, b: string }>; + type T31 = keyof NoInfer; + type T32 = { [K in keyof NoInfer<{ a: string, b: string }>]: K }; + declare function foo1(a: T, b: NoInfer): void declare function foo2(a: T, b: NoInfer[]): void declare function foo3(a: T, b: NoInfer): void @@ -53,11 +59,11 @@ noInfer.ts(60,14): error TS2345: Argument of type '{}' is not assignable to para foo4('foo', { x: 'bar' }) // error ~ !!! error TS2322: Type '"bar"' is not assignable to type '"foo"'. -!!! related TS6500 noInfer.ts:25:52: The expected type comes from property 'x' which is declared here on type '{ x: "foo"; }' +!!! related TS6500 noInfer.ts:31:52: The expected type comes from property 'x' which is declared here on type '{ x: "foo"; }' foo5('foo', { x: 'bar' }) // error ~ !!! error TS2322: Type '"bar"' is not assignable to type '"foo"'. -!!! related TS6500 noInfer.ts:26:60: The expected type comes from property 'x' which is declared here on type 'NoInfer<{ x: "foo"; }>' +!!! related TS6500 noInfer.ts:32:60: The expected type comes from property 'x' which is declared here on type 'NoInfer<{ x: "foo"; }>' declare class Animal { move(): void } declare class Dog extends Animal { woof(): void } @@ -68,8 +74,8 @@ noInfer.ts(60,14): error TS2345: Argument of type '{}' is not assignable to para doSomething(new Dog(), () => new Animal()); // error ~~~~~~~~~~~~ !!! error TS2741: Property 'woof' is missing in type 'Animal' but required in type 'Dog'. -!!! related TS2728 noInfer.ts:36:36: 'woof' is declared here. -!!! related TS6502 noInfer.ts:37:55: The expected type comes from the return type of this signature. +!!! related TS2728 noInfer.ts:42:36: 'woof' is declared here. +!!! related TS6502 noInfer.ts:43:55: The expected type comes from the return type of this signature. declare function assertEqual(actual: T, expected: NoInfer): boolean; @@ -79,7 +85,7 @@ noInfer.ts(60,14): error TS2345: Argument of type '{}' is not assignable to para ~~~~~~~~ !!! error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type '{ x: number; y: number; }'. !!! error TS2345: Property 'y' is missing in type '{ x: number; }' but required in type '{ x: number; y: number; }'. -!!! related TS2728 noInfer.ts:46:19: 'y' is declared here. +!!! related TS2728 noInfer.ts:52:19: 'y' is declared here. declare function invoke(func: (value: T) => R, value: NoInfer): R; declare function test(value: { x: number; }): number; @@ -100,7 +106,7 @@ noInfer.ts(60,14): error TS2345: Argument of type '{}' is not assignable to para ~~ !!! error TS2345: Argument of type '{}' is not assignable to parameter of type '{ foo: number; }'. !!! error TS2345: Property 'foo' is missing in type '{}' but required in type '{ foo: number; }'. -!!! related TS2728 noInfer.ts:57:33: 'foo' is declared here. +!!! related TS2728 noInfer.ts:63:33: 'foo' is declared here. declare function mutate(callback: (a: NoInfer, b: number) => T): T; const mutate1 = mutate((a, b) => b); diff --git a/tests/baselines/reference/noInfer.js b/tests/baselines/reference/noInfer.js index 77f55dfb23ba3..a090dbdebcf64 100644 --- a/tests/baselines/reference/noInfer.js +++ b/tests/baselines/reference/noInfer.js @@ -22,6 +22,12 @@ type T20 = NoInfer>; type T21 = NoInfer & string>; type T22 = NoInfer & string[]>; +// NoInfer is erased in index types and mapped types + +type T30 = keyof NoInfer<{ a: string, b: string }>; +type T31 = keyof NoInfer; +type T32 = { [K in keyof NoInfer<{ a: string, b: string }>]: K }; + declare function foo1(a: T, b: NoInfer): void declare function foo2(a: T, b: NoInfer[]): void declare function foo3(a: T, b: NoInfer): void @@ -136,6 +142,17 @@ type T11 = NoInfer<{ type T20 = NoInfer>; type T21 = NoInfer & string>; type T22 = NoInfer & string[]>; +type T30 = keyof NoInfer<{ + a: string; + b: string; +}>; +type T31 = keyof NoInfer; +type T32 = { + [K in keyof NoInfer<{ + a: string; + b: string; + }>]: K; +}; declare function foo1(a: T, b: NoInfer): void; declare function foo2(a: T, b: NoInfer[]): void; declare function foo3(a: T, b: NoInfer): void; diff --git a/tests/baselines/reference/noInfer.symbols b/tests/baselines/reference/noInfer.symbols index 67d5ca7538a57..1fcb74a3249f2 100644 --- a/tests/baselines/reference/noInfer.symbols +++ b/tests/baselines/reference/noInfer.symbols @@ -65,243 +65,265 @@ type T22 = NoInfer & string[]>; >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) >T : Symbol(T, Decl(noInfer.ts, 19, 9)) +// NoInfer is erased in index types and mapped types + +type T30 = keyof NoInfer<{ a: string, b: string }>; +>T30 : Symbol(T30, Decl(noInfer.ts, 19, 45)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(noInfer.ts, 23, 26)) +>b : Symbol(b, Decl(noInfer.ts, 23, 37)) + +type T31 = keyof NoInfer; +>T31 : Symbol(T31, Decl(noInfer.ts, 23, 51)) +>T : Symbol(T, Decl(noInfer.ts, 24, 9)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(noInfer.ts, 24, 9)) + +type T32 = { [K in keyof NoInfer<{ a: string, b: string }>]: K }; +>T32 : Symbol(T32, Decl(noInfer.ts, 24, 31)) +>K : Symbol(K, Decl(noInfer.ts, 25, 14)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(noInfer.ts, 25, 34)) +>b : Symbol(b, Decl(noInfer.ts, 25, 45)) +>K : Symbol(K, Decl(noInfer.ts, 25, 14)) + declare function foo1(a: T, b: NoInfer): void ->foo1 : Symbol(foo1, Decl(noInfer.ts, 19, 45)) ->T : Symbol(T, Decl(noInfer.ts, 21, 22)) ->a : Symbol(a, Decl(noInfer.ts, 21, 40)) ->T : Symbol(T, Decl(noInfer.ts, 21, 22)) ->b : Symbol(b, Decl(noInfer.ts, 21, 45)) +>foo1 : Symbol(foo1, Decl(noInfer.ts, 25, 65)) +>T : Symbol(T, Decl(noInfer.ts, 27, 22)) +>a : Symbol(a, Decl(noInfer.ts, 27, 40)) +>T : Symbol(T, Decl(noInfer.ts, 27, 22)) +>b : Symbol(b, Decl(noInfer.ts, 27, 45)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 21, 22)) +>T : Symbol(T, Decl(noInfer.ts, 27, 22)) declare function foo2(a: T, b: NoInfer[]): void ->foo2 : Symbol(foo2, Decl(noInfer.ts, 21, 66)) ->T : Symbol(T, Decl(noInfer.ts, 22, 22)) ->a : Symbol(a, Decl(noInfer.ts, 22, 40)) ->T : Symbol(T, Decl(noInfer.ts, 22, 22)) ->b : Symbol(b, Decl(noInfer.ts, 22, 45)) +>foo2 : Symbol(foo2, Decl(noInfer.ts, 27, 66)) +>T : Symbol(T, Decl(noInfer.ts, 28, 22)) +>a : Symbol(a, Decl(noInfer.ts, 28, 40)) +>T : Symbol(T, Decl(noInfer.ts, 28, 22)) +>b : Symbol(b, Decl(noInfer.ts, 28, 45)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 22, 22)) +>T : Symbol(T, Decl(noInfer.ts, 28, 22)) declare function foo3(a: T, b: NoInfer): void ->foo3 : Symbol(foo3, Decl(noInfer.ts, 22, 68)) ->T : Symbol(T, Decl(noInfer.ts, 23, 22)) ->a : Symbol(a, Decl(noInfer.ts, 23, 40)) ->T : Symbol(T, Decl(noInfer.ts, 23, 22)) ->b : Symbol(b, Decl(noInfer.ts, 23, 45)) +>foo3 : Symbol(foo3, Decl(noInfer.ts, 28, 68)) +>T : Symbol(T, Decl(noInfer.ts, 29, 22)) +>a : Symbol(a, Decl(noInfer.ts, 29, 40)) +>T : Symbol(T, Decl(noInfer.ts, 29, 22)) +>b : Symbol(b, Decl(noInfer.ts, 29, 45)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 23, 22)) +>T : Symbol(T, Decl(noInfer.ts, 29, 22)) declare function foo4(a: T, b: { x: NoInfer }): void ->foo4 : Symbol(foo4, Decl(noInfer.ts, 23, 68)) ->T : Symbol(T, Decl(noInfer.ts, 24, 22)) ->a : Symbol(a, Decl(noInfer.ts, 24, 40)) ->T : Symbol(T, Decl(noInfer.ts, 24, 22)) ->b : Symbol(b, Decl(noInfer.ts, 24, 45)) ->x : Symbol(x, Decl(noInfer.ts, 24, 50)) +>foo4 : Symbol(foo4, Decl(noInfer.ts, 29, 68)) +>T : Symbol(T, Decl(noInfer.ts, 30, 22)) +>a : Symbol(a, Decl(noInfer.ts, 30, 40)) +>T : Symbol(T, Decl(noInfer.ts, 30, 22)) +>b : Symbol(b, Decl(noInfer.ts, 30, 45)) +>x : Symbol(x, Decl(noInfer.ts, 30, 50)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 24, 22)) +>T : Symbol(T, Decl(noInfer.ts, 30, 22)) declare function foo5(a: T, b: NoInfer<{ x: T }>): void ->foo5 : Symbol(foo5, Decl(noInfer.ts, 24, 73)) ->T : Symbol(T, Decl(noInfer.ts, 25, 22)) ->a : Symbol(a, Decl(noInfer.ts, 25, 40)) ->T : Symbol(T, Decl(noInfer.ts, 25, 22)) ->b : Symbol(b, Decl(noInfer.ts, 25, 45)) +>foo5 : Symbol(foo5, Decl(noInfer.ts, 30, 73)) +>T : Symbol(T, Decl(noInfer.ts, 31, 22)) +>a : Symbol(a, Decl(noInfer.ts, 31, 40)) +>T : Symbol(T, Decl(noInfer.ts, 31, 22)) +>b : Symbol(b, Decl(noInfer.ts, 31, 45)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(noInfer.ts, 25, 58)) ->T : Symbol(T, Decl(noInfer.ts, 25, 22)) +>x : Symbol(x, Decl(noInfer.ts, 31, 58)) +>T : Symbol(T, Decl(noInfer.ts, 31, 22)) foo1('foo', 'foo') // ok ->foo1 : Symbol(foo1, Decl(noInfer.ts, 19, 45)) +>foo1 : Symbol(foo1, Decl(noInfer.ts, 25, 65)) foo1('foo', 'bar') // error ->foo1 : Symbol(foo1, Decl(noInfer.ts, 19, 45)) +>foo1 : Symbol(foo1, Decl(noInfer.ts, 25, 65)) foo2('foo', ['bar']) // error ->foo2 : Symbol(foo2, Decl(noInfer.ts, 21, 66)) +>foo2 : Symbol(foo2, Decl(noInfer.ts, 27, 66)) foo3('foo', ['bar']) // error ->foo3 : Symbol(foo3, Decl(noInfer.ts, 22, 68)) +>foo3 : Symbol(foo3, Decl(noInfer.ts, 28, 68)) foo4('foo', { x: 'bar' }) // error ->foo4 : Symbol(foo4, Decl(noInfer.ts, 23, 68)) ->x : Symbol(x, Decl(noInfer.ts, 31, 13)) +>foo4 : Symbol(foo4, Decl(noInfer.ts, 29, 68)) +>x : Symbol(x, Decl(noInfer.ts, 37, 13)) foo5('foo', { x: 'bar' }) // error ->foo5 : Symbol(foo5, Decl(noInfer.ts, 24, 73)) ->x : Symbol(x, Decl(noInfer.ts, 32, 13)) +>foo5 : Symbol(foo5, Decl(noInfer.ts, 30, 73)) +>x : Symbol(x, Decl(noInfer.ts, 38, 13)) declare class Animal { move(): void } ->Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) ->move : Symbol(Animal.move, Decl(noInfer.ts, 34, 22)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 38, 25)) +>move : Symbol(Animal.move, Decl(noInfer.ts, 40, 22)) declare class Dog extends Animal { woof(): void } ->Dog : Symbol(Dog, Decl(noInfer.ts, 34, 37)) ->Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) ->woof : Symbol(Dog.woof, Decl(noInfer.ts, 35, 34)) +>Dog : Symbol(Dog, Decl(noInfer.ts, 40, 37)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 38, 25)) +>woof : Symbol(Dog.woof, Decl(noInfer.ts, 41, 34)) declare function doSomething(value: T, getDefault: () => NoInfer): void; ->doSomething : Symbol(doSomething, Decl(noInfer.ts, 35, 49)) ->T : Symbol(T, Decl(noInfer.ts, 36, 29)) ->value : Symbol(value, Decl(noInfer.ts, 36, 32)) ->T : Symbol(T, Decl(noInfer.ts, 36, 29)) ->getDefault : Symbol(getDefault, Decl(noInfer.ts, 36, 41)) +>doSomething : Symbol(doSomething, Decl(noInfer.ts, 41, 49)) +>T : Symbol(T, Decl(noInfer.ts, 42, 29)) +>value : Symbol(value, Decl(noInfer.ts, 42, 32)) +>T : Symbol(T, Decl(noInfer.ts, 42, 29)) +>getDefault : Symbol(getDefault, Decl(noInfer.ts, 42, 41)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 36, 29)) +>T : Symbol(T, Decl(noInfer.ts, 42, 29)) doSomething(new Animal(), () => new Animal()); // ok ->doSomething : Symbol(doSomething, Decl(noInfer.ts, 35, 49)) ->Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) ->Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) +>doSomething : Symbol(doSomething, Decl(noInfer.ts, 41, 49)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 38, 25)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 38, 25)) doSomething(new Animal(), () => new Dog()); // ok ->doSomething : Symbol(doSomething, Decl(noInfer.ts, 35, 49)) ->Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) ->Dog : Symbol(Dog, Decl(noInfer.ts, 34, 37)) +>doSomething : Symbol(doSomething, Decl(noInfer.ts, 41, 49)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 38, 25)) +>Dog : Symbol(Dog, Decl(noInfer.ts, 40, 37)) doSomething(new Dog(), () => new Animal()); // error ->doSomething : Symbol(doSomething, Decl(noInfer.ts, 35, 49)) ->Dog : Symbol(Dog, Decl(noInfer.ts, 34, 37)) ->Animal : Symbol(Animal, Decl(noInfer.ts, 32, 25)) +>doSomething : Symbol(doSomething, Decl(noInfer.ts, 41, 49)) +>Dog : Symbol(Dog, Decl(noInfer.ts, 40, 37)) +>Animal : Symbol(Animal, Decl(noInfer.ts, 38, 25)) declare function assertEqual(actual: T, expected: NoInfer): boolean; ->assertEqual : Symbol(assertEqual, Decl(noInfer.ts, 40, 43)) ->T : Symbol(T, Decl(noInfer.ts, 42, 29)) ->actual : Symbol(actual, Decl(noInfer.ts, 42, 32)) ->T : Symbol(T, Decl(noInfer.ts, 42, 29)) ->expected : Symbol(expected, Decl(noInfer.ts, 42, 42)) +>assertEqual : Symbol(assertEqual, Decl(noInfer.ts, 46, 43)) +>T : Symbol(T, Decl(noInfer.ts, 48, 29)) +>actual : Symbol(actual, Decl(noInfer.ts, 48, 32)) +>T : Symbol(T, Decl(noInfer.ts, 48, 29)) +>expected : Symbol(expected, Decl(noInfer.ts, 48, 42)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 42, 29)) +>T : Symbol(T, Decl(noInfer.ts, 48, 29)) assertEqual({ x: 1 }, { x: 3 }); // ok ->assertEqual : Symbol(assertEqual, Decl(noInfer.ts, 40, 43)) ->x : Symbol(x, Decl(noInfer.ts, 44, 13)) ->x : Symbol(x, Decl(noInfer.ts, 44, 23)) +>assertEqual : Symbol(assertEqual, Decl(noInfer.ts, 46, 43)) +>x : Symbol(x, Decl(noInfer.ts, 50, 13)) +>x : Symbol(x, Decl(noInfer.ts, 50, 23)) const g = { x: 3, y: 2 }; ->g : Symbol(g, Decl(noInfer.ts, 45, 5)) ->x : Symbol(x, Decl(noInfer.ts, 45, 11)) ->y : Symbol(y, Decl(noInfer.ts, 45, 17)) +>g : Symbol(g, Decl(noInfer.ts, 51, 5)) +>x : Symbol(x, Decl(noInfer.ts, 51, 11)) +>y : Symbol(y, Decl(noInfer.ts, 51, 17)) assertEqual(g, { x: 3 }); // error ->assertEqual : Symbol(assertEqual, Decl(noInfer.ts, 40, 43)) ->g : Symbol(g, Decl(noInfer.ts, 45, 5)) ->x : Symbol(x, Decl(noInfer.ts, 46, 16)) +>assertEqual : Symbol(assertEqual, Decl(noInfer.ts, 46, 43)) +>g : Symbol(g, Decl(noInfer.ts, 51, 5)) +>x : Symbol(x, Decl(noInfer.ts, 52, 16)) declare function invoke(func: (value: T) => R, value: NoInfer): R; ->invoke : Symbol(invoke, Decl(noInfer.ts, 46, 25)) ->T : Symbol(T, Decl(noInfer.ts, 48, 24)) ->R : Symbol(R, Decl(noInfer.ts, 48, 26)) ->func : Symbol(func, Decl(noInfer.ts, 48, 30)) ->value : Symbol(value, Decl(noInfer.ts, 48, 37)) ->T : Symbol(T, Decl(noInfer.ts, 48, 24)) ->R : Symbol(R, Decl(noInfer.ts, 48, 26)) ->value : Symbol(value, Decl(noInfer.ts, 48, 52)) +>invoke : Symbol(invoke, Decl(noInfer.ts, 52, 25)) +>T : Symbol(T, Decl(noInfer.ts, 54, 24)) +>R : Symbol(R, Decl(noInfer.ts, 54, 26)) +>func : Symbol(func, Decl(noInfer.ts, 54, 30)) +>value : Symbol(value, Decl(noInfer.ts, 54, 37)) +>T : Symbol(T, Decl(noInfer.ts, 54, 24)) +>R : Symbol(R, Decl(noInfer.ts, 54, 26)) +>value : Symbol(value, Decl(noInfer.ts, 54, 52)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 48, 24)) ->R : Symbol(R, Decl(noInfer.ts, 48, 26)) +>T : Symbol(T, Decl(noInfer.ts, 54, 24)) +>R : Symbol(R, Decl(noInfer.ts, 54, 26)) declare function test(value: { x: number; }): number; ->test : Symbol(test, Decl(noInfer.ts, 48, 75)) ->value : Symbol(value, Decl(noInfer.ts, 49, 22)) ->x : Symbol(x, Decl(noInfer.ts, 49, 30)) +>test : Symbol(test, Decl(noInfer.ts, 54, 75)) +>value : Symbol(value, Decl(noInfer.ts, 55, 22)) +>x : Symbol(x, Decl(noInfer.ts, 55, 30)) invoke(test, { x: 1, y: 2 }); // error ->invoke : Symbol(invoke, Decl(noInfer.ts, 46, 25)) ->test : Symbol(test, Decl(noInfer.ts, 48, 75)) ->x : Symbol(x, Decl(noInfer.ts, 51, 14)) ->y : Symbol(y, Decl(noInfer.ts, 51, 20)) +>invoke : Symbol(invoke, Decl(noInfer.ts, 52, 25)) +>test : Symbol(test, Decl(noInfer.ts, 54, 75)) +>x : Symbol(x, Decl(noInfer.ts, 57, 14)) +>y : Symbol(y, Decl(noInfer.ts, 57, 20)) test({ x: 1, y: 2 }); // error ->test : Symbol(test, Decl(noInfer.ts, 48, 75)) ->x : Symbol(x, Decl(noInfer.ts, 52, 6)) ->y : Symbol(y, Decl(noInfer.ts, 52, 12)) +>test : Symbol(test, Decl(noInfer.ts, 54, 75)) +>x : Symbol(x, Decl(noInfer.ts, 58, 6)) +>y : Symbol(y, Decl(noInfer.ts, 58, 12)) type Component = { props: Props; }; ->Component : Symbol(Component, Decl(noInfer.ts, 52, 21)) ->Props : Symbol(Props, Decl(noInfer.ts, 54, 15)) ->props : Symbol(props, Decl(noInfer.ts, 54, 25)) ->Props : Symbol(Props, Decl(noInfer.ts, 54, 15)) +>Component : Symbol(Component, Decl(noInfer.ts, 58, 21)) +>Props : Symbol(Props, Decl(noInfer.ts, 60, 15)) +>props : Symbol(props, Decl(noInfer.ts, 60, 25)) +>Props : Symbol(Props, Decl(noInfer.ts, 60, 15)) declare function doWork(Component: Component, props: NoInfer): void; ->doWork : Symbol(doWork, Decl(noInfer.ts, 54, 42)) ->Props : Symbol(Props, Decl(noInfer.ts, 55, 24)) ->Component : Symbol(Component, Decl(noInfer.ts, 55, 31)) ->Component : Symbol(Component, Decl(noInfer.ts, 52, 21)) ->Props : Symbol(Props, Decl(noInfer.ts, 55, 24)) ->props : Symbol(props, Decl(noInfer.ts, 55, 59)) +>doWork : Symbol(doWork, Decl(noInfer.ts, 60, 42)) +>Props : Symbol(Props, Decl(noInfer.ts, 61, 24)) +>Component : Symbol(Component, Decl(noInfer.ts, 61, 31)) +>Component : Symbol(Component, Decl(noInfer.ts, 58, 21)) +>Props : Symbol(Props, Decl(noInfer.ts, 61, 24)) +>props : Symbol(props, Decl(noInfer.ts, 61, 59)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->Props : Symbol(Props, Decl(noInfer.ts, 55, 24)) +>Props : Symbol(Props, Decl(noInfer.ts, 61, 24)) declare const comp: Component<{ foo: number }>; ->comp : Symbol(comp, Decl(noInfer.ts, 56, 13)) ->Component : Symbol(Component, Decl(noInfer.ts, 52, 21)) ->foo : Symbol(foo, Decl(noInfer.ts, 56, 31)) +>comp : Symbol(comp, Decl(noInfer.ts, 62, 13)) +>Component : Symbol(Component, Decl(noInfer.ts, 58, 21)) +>foo : Symbol(foo, Decl(noInfer.ts, 62, 31)) doWork(comp, { foo: 42 }); // ok ->doWork : Symbol(doWork, Decl(noInfer.ts, 54, 42)) ->comp : Symbol(comp, Decl(noInfer.ts, 56, 13)) ->foo : Symbol(foo, Decl(noInfer.ts, 58, 14)) +>doWork : Symbol(doWork, Decl(noInfer.ts, 60, 42)) +>comp : Symbol(comp, Decl(noInfer.ts, 62, 13)) +>foo : Symbol(foo, Decl(noInfer.ts, 64, 14)) doWork(comp, {}); // error ->doWork : Symbol(doWork, Decl(noInfer.ts, 54, 42)) ->comp : Symbol(comp, Decl(noInfer.ts, 56, 13)) +>doWork : Symbol(doWork, Decl(noInfer.ts, 60, 42)) +>comp : Symbol(comp, Decl(noInfer.ts, 62, 13)) declare function mutate(callback: (a: NoInfer, b: number) => T): T; ->mutate : Symbol(mutate, Decl(noInfer.ts, 59, 17)) ->T : Symbol(T, Decl(noInfer.ts, 61, 24)) ->callback : Symbol(callback, Decl(noInfer.ts, 61, 27)) ->a : Symbol(a, Decl(noInfer.ts, 61, 38)) +>mutate : Symbol(mutate, Decl(noInfer.ts, 65, 17)) +>T : Symbol(T, Decl(noInfer.ts, 67, 24)) +>callback : Symbol(callback, Decl(noInfer.ts, 67, 27)) +>a : Symbol(a, Decl(noInfer.ts, 67, 38)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 61, 24)) ->b : Symbol(b, Decl(noInfer.ts, 61, 52)) ->T : Symbol(T, Decl(noInfer.ts, 61, 24)) ->T : Symbol(T, Decl(noInfer.ts, 61, 24)) +>T : Symbol(T, Decl(noInfer.ts, 67, 24)) +>b : Symbol(b, Decl(noInfer.ts, 67, 52)) +>T : Symbol(T, Decl(noInfer.ts, 67, 24)) +>T : Symbol(T, Decl(noInfer.ts, 67, 24)) const mutate1 = mutate((a, b) => b); ->mutate1 : Symbol(mutate1, Decl(noInfer.ts, 62, 5)) ->mutate : Symbol(mutate, Decl(noInfer.ts, 59, 17)) ->a : Symbol(a, Decl(noInfer.ts, 62, 24)) ->b : Symbol(b, Decl(noInfer.ts, 62, 26)) ->b : Symbol(b, Decl(noInfer.ts, 62, 26)) +>mutate1 : Symbol(mutate1, Decl(noInfer.ts, 68, 5)) +>mutate : Symbol(mutate, Decl(noInfer.ts, 65, 17)) +>a : Symbol(a, Decl(noInfer.ts, 68, 24)) +>b : Symbol(b, Decl(noInfer.ts, 68, 26)) +>b : Symbol(b, Decl(noInfer.ts, 68, 26)) declare class ExampleClass {} ->ExampleClass : Symbol(ExampleClass, Decl(noInfer.ts, 62, 36)) ->T : Symbol(T, Decl(noInfer.ts, 64, 27)) +>ExampleClass : Symbol(ExampleClass, Decl(noInfer.ts, 68, 36)) +>T : Symbol(T, Decl(noInfer.ts, 70, 27)) class OkClass { ->OkClass : Symbol(OkClass, Decl(noInfer.ts, 64, 32)) ->T : Symbol(T, Decl(noInfer.ts, 65, 14)) +>OkClass : Symbol(OkClass, Decl(noInfer.ts, 70, 32)) +>T : Symbol(T, Decl(noInfer.ts, 71, 14)) constructor(private clazz: ExampleClass, private _value: NoInfer) {} ->clazz : Symbol(OkClass.clazz, Decl(noInfer.ts, 66, 16)) ->ExampleClass : Symbol(ExampleClass, Decl(noInfer.ts, 62, 36)) ->T : Symbol(T, Decl(noInfer.ts, 65, 14)) ->_value : Symbol(OkClass._value, Decl(noInfer.ts, 66, 47)) +>clazz : Symbol(OkClass.clazz, Decl(noInfer.ts, 72, 16)) +>ExampleClass : Symbol(ExampleClass, Decl(noInfer.ts, 68, 36)) +>T : Symbol(T, Decl(noInfer.ts, 71, 14)) +>_value : Symbol(OkClass._value, Decl(noInfer.ts, 72, 47)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 65, 14)) +>T : Symbol(T, Decl(noInfer.ts, 71, 14)) get value(): T { ->value : Symbol(OkClass.value, Decl(noInfer.ts, 66, 78)) ->T : Symbol(T, Decl(noInfer.ts, 65, 14)) +>value : Symbol(OkClass.value, Decl(noInfer.ts, 72, 78)) +>T : Symbol(T, Decl(noInfer.ts, 71, 14)) return this._value; // ok ->this._value : Symbol(OkClass._value, Decl(noInfer.ts, 66, 47)) ->this : Symbol(OkClass, Decl(noInfer.ts, 64, 32)) ->_value : Symbol(OkClass._value, Decl(noInfer.ts, 66, 47)) +>this._value : Symbol(OkClass._value, Decl(noInfer.ts, 72, 47)) +>this : Symbol(OkClass, Decl(noInfer.ts, 70, 32)) +>_value : Symbol(OkClass._value, Decl(noInfer.ts, 72, 47)) } } class OkClass2 { ->OkClass2 : Symbol(OkClass2, Decl(noInfer.ts, 71, 1)) ->T : Symbol(T, Decl(noInfer.ts, 72, 15)) +>OkClass2 : Symbol(OkClass2, Decl(noInfer.ts, 77, 1)) +>T : Symbol(T, Decl(noInfer.ts, 78, 15)) constructor(private clazz: ExampleClass, public _value: NoInfer) {} ->clazz : Symbol(OkClass2.clazz, Decl(noInfer.ts, 73, 16)) ->ExampleClass : Symbol(ExampleClass, Decl(noInfer.ts, 62, 36)) ->T : Symbol(T, Decl(noInfer.ts, 72, 15)) ->_value : Symbol(OkClass2._value, Decl(noInfer.ts, 73, 47)) +>clazz : Symbol(OkClass2.clazz, Decl(noInfer.ts, 79, 16)) +>ExampleClass : Symbol(ExampleClass, Decl(noInfer.ts, 68, 36)) +>T : Symbol(T, Decl(noInfer.ts, 78, 15)) +>_value : Symbol(OkClass2._value, Decl(noInfer.ts, 79, 47)) >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(noInfer.ts, 72, 15)) +>T : Symbol(T, Decl(noInfer.ts, 78, 15)) } diff --git a/tests/baselines/reference/noInfer.types b/tests/baselines/reference/noInfer.types index c1427c8878daf..5a2630f08075c 100644 --- a/tests/baselines/reference/noInfer.types +++ b/tests/baselines/reference/noInfer.types @@ -44,6 +44,21 @@ type T21 = NoInfer & string>; type T22 = NoInfer & string[]>; >T22 : NoInfer & string[]> +// NoInfer is erased in index types and mapped types + +type T30 = keyof NoInfer<{ a: string, b: string }>; +>T30 : "a" | "b" +>a : string +>b : string + +type T31 = keyof NoInfer; +>T31 : keyof T + +type T32 = { [K in keyof NoInfer<{ a: string, b: string }>]: K }; +>T32 : { a: "a"; b: "b"; } +>a : string +>b : string + declare function foo1(a: T, b: NoInfer): void >foo1 : (a: T, b: NoInfer) => void >a : T diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts b/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts index 30296f2a7cba3..57e229620de25 100644 --- a/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts +++ b/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts @@ -22,6 +22,12 @@ type T20 = NoInfer>; type T21 = NoInfer & string>; type T22 = NoInfer & string[]>; +// NoInfer is erased in index types and mapped types + +type T30 = keyof NoInfer<{ a: string, b: string }>; +type T31 = keyof NoInfer; +type T32 = { [K in keyof NoInfer<{ a: string, b: string }>]: K }; + declare function foo1(a: T, b: NoInfer): void declare function foo2(a: T, b: NoInfer[]): void declare function foo3(a: T, b: NoInfer): void From 63b6713ed7ed1979fb38c474d36cfc02cbfdeeb8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 Dec 2023 08:40:58 -1000 Subject: [PATCH 6/9] keyof NoInfer ==> NoInfer / globalThis emit when needed --- src/compiler/checker.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3d1ccfeed4f89..d637d122227c7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6713,7 +6713,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (type.flags & TypeFlags.Substitution) { const typeNode = typeToTypeNodeHelper((type as SubstitutionType).baseType, context); - return isNoInferType(type) ? factory.createTypeReferenceNode("NoInfer", [typeNode]) : typeNode; + const noInferSymbol = isNoInferType(type) && getGlobalTypeSymbol("NoInfer" as __String, /*reportErrors*/ false); + return noInferSymbol ? symbolToTypeNode(noInferSymbol, context, SymbolFlags.Type, [typeNode]) : typeNode; } return Debug.fail("Should be unreachable."); @@ -17771,7 +17772,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return shouldDeferIndexType(type, indexFlags) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, indexFlags) : type.flags & TypeFlags.Union ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, indexFlags))) : type.flags & TypeFlags.Intersection ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, indexFlags))) : - type.flags & TypeFlags.Substitution ? getIndexType((type as SubstitutionType).baseType, indexFlags) : + type.flags & TypeFlags.Substitution ? getNoInferType(getIndexType((type as SubstitutionType).baseType, indexFlags)) : getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, indexFlags) : type === wildcardType ? wildcardType : type.flags & TypeFlags.Unknown ? neverType : From 14b90c23ca311981a1b7495437162999a730c634 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 Dec 2023 10:19:42 -1000 Subject: [PATCH 7/9] Simplify keyof NoInfer ==> NoInfer transformation --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d637d122227c7..5a00506da1edf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17760,7 +17760,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function shouldDeferIndexType(type: Type, indexFlags = IndexFlags.None) { - return !!(type.flags & TypeFlags.InstantiableNonPrimitive && !isNoInferType(type) || + return !!(type.flags & TypeFlags.InstantiableNonPrimitive || isGenericTupleType(type) || isGenericMappedType(type) && (!hasDistributiveNameType(type) || getMappedTypeNameTypeKind(type) === MappedTypeNameTypeKind.Remapping) || type.flags & TypeFlags.Union && !(indexFlags & IndexFlags.NoReducibleCheck) && isGenericReducibleType(type) || @@ -17769,10 +17769,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getIndexType(type: Type, indexFlags = defaultIndexFlags): Type { type = getReducedType(type); - return shouldDeferIndexType(type, indexFlags) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, indexFlags) : + return isNoInferType(type) ? getNoInferType(getIndexType((type as SubstitutionType).baseType, indexFlags)) : + shouldDeferIndexType(type, indexFlags) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, indexFlags) : type.flags & TypeFlags.Union ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, indexFlags))) : type.flags & TypeFlags.Intersection ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, indexFlags))) : - type.flags & TypeFlags.Substitution ? getNoInferType(getIndexType((type as SubstitutionType).baseType, indexFlags)) : getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, indexFlags) : type === wildcardType ? wildcardType : type.flags & TypeFlags.Unknown ? neverType : From 2fc975ac4a401e84cbfc715bdbe4c9cefd7dea97 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 Dec 2023 10:19:53 -1000 Subject: [PATCH 8/9] Update tests --- tests/baselines/reference/noInfer.errors.txt | 2 +- tests/baselines/reference/noInfer.js | 2 +- tests/baselines/reference/noInfer.symbols | 2 +- tests/baselines/reference/noInfer.types | 4 ++-- .../types/typeRelationships/typeInference/noInfer.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/noInfer.errors.txt b/tests/baselines/reference/noInfer.errors.txt index acf06ca1f0325..2b016511a09b2 100644 --- a/tests/baselines/reference/noInfer.errors.txt +++ b/tests/baselines/reference/noInfer.errors.txt @@ -34,7 +34,7 @@ noInfer.ts(66,14): error TS2345: Argument of type '{}' is not assignable to para type T21 = NoInfer & string>; type T22 = NoInfer & string[]>; - // NoInfer is erased in index types and mapped types + // keyof NoInfer is transformed into NoInfer type T30 = keyof NoInfer<{ a: string, b: string }>; type T31 = keyof NoInfer; diff --git a/tests/baselines/reference/noInfer.js b/tests/baselines/reference/noInfer.js index a090dbdebcf64..59e27f3755efd 100644 --- a/tests/baselines/reference/noInfer.js +++ b/tests/baselines/reference/noInfer.js @@ -22,7 +22,7 @@ type T20 = NoInfer>; type T21 = NoInfer & string>; type T22 = NoInfer & string[]>; -// NoInfer is erased in index types and mapped types +// keyof NoInfer is transformed into NoInfer type T30 = keyof NoInfer<{ a: string, b: string }>; type T31 = keyof NoInfer; diff --git a/tests/baselines/reference/noInfer.symbols b/tests/baselines/reference/noInfer.symbols index 1fcb74a3249f2..7a36c6fccb9a1 100644 --- a/tests/baselines/reference/noInfer.symbols +++ b/tests/baselines/reference/noInfer.symbols @@ -65,7 +65,7 @@ type T22 = NoInfer & string[]>; >NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) >T : Symbol(T, Decl(noInfer.ts, 19, 9)) -// NoInfer is erased in index types and mapped types +// keyof NoInfer is transformed into NoInfer type T30 = keyof NoInfer<{ a: string, b: string }>; >T30 : Symbol(T30, Decl(noInfer.ts, 19, 45)) diff --git a/tests/baselines/reference/noInfer.types b/tests/baselines/reference/noInfer.types index 5a2630f08075c..0b747c064a450 100644 --- a/tests/baselines/reference/noInfer.types +++ b/tests/baselines/reference/noInfer.types @@ -44,7 +44,7 @@ type T21 = NoInfer & string>; type T22 = NoInfer & string[]>; >T22 : NoInfer & string[]> -// NoInfer is erased in index types and mapped types +// keyof NoInfer is transformed into NoInfer type T30 = keyof NoInfer<{ a: string, b: string }>; >T30 : "a" | "b" @@ -52,7 +52,7 @@ type T30 = keyof NoInfer<{ a: string, b: string }>; >b : string type T31 = keyof NoInfer; ->T31 : keyof T +>T31 : NoInfer type T32 = { [K in keyof NoInfer<{ a: string, b: string }>]: K }; >T32 : { a: "a"; b: "b"; } diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts b/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts index 57e229620de25..49b3dd087a10b 100644 --- a/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts +++ b/tests/cases/conformance/types/typeRelationships/typeInference/noInfer.ts @@ -22,7 +22,7 @@ type T20 = NoInfer>; type T21 = NoInfer & string>; type T22 = NoInfer & string[]>; -// NoInfer is erased in index types and mapped types +// keyof NoInfer is transformed into NoInfer type T30 = keyof NoInfer<{ a: string, b: string }>; type T31 = keyof NoInfer; From 79f851315d6bfddc5f5ef703ec7df71b4adff52f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 9 Jan 2024 14:53:47 -0800 Subject: [PATCH 9/9] Add test for redeclaration of NoInfer --- .../reference/noInferRedeclaration.js | 24 +++++++++++++++++ .../reference/noInferRedeclaration.symbols | 26 +++++++++++++++++++ .../reference/noInferRedeclaration.types | 21 +++++++++++++++ .../typeInference/noInferRedeclaration.ts | 13 ++++++++++ 4 files changed, 84 insertions(+) create mode 100644 tests/baselines/reference/noInferRedeclaration.js create mode 100644 tests/baselines/reference/noInferRedeclaration.symbols create mode 100644 tests/baselines/reference/noInferRedeclaration.types create mode 100644 tests/cases/conformance/types/typeRelationships/typeInference/noInferRedeclaration.ts diff --git a/tests/baselines/reference/noInferRedeclaration.js b/tests/baselines/reference/noInferRedeclaration.js new file mode 100644 index 0000000000000..a9afd9107f829 --- /dev/null +++ b/tests/baselines/reference/noInferRedeclaration.js @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferRedeclaration.ts] //// + +//// [a.ts] +export const f = (x: T, y: NoInfer) => x; + +//// [b.ts] +import { f } from "./a"; + +type NoInfer = T & number; + +export const g = f; + + +//// [a.js] +export const f = (x, y) => x; +//// [b.js] +import { f } from "./a"; +export const g = f; + + +//// [a.d.ts] +export declare const f: (x: T, y: NoInfer) => T; +//// [b.d.ts] +export declare const g: (x: T, y: globalThis.NoInfer) => T; diff --git a/tests/baselines/reference/noInferRedeclaration.symbols b/tests/baselines/reference/noInferRedeclaration.symbols new file mode 100644 index 0000000000000..b7b3bb5529c86 --- /dev/null +++ b/tests/baselines/reference/noInferRedeclaration.symbols @@ -0,0 +1,26 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferRedeclaration.ts] //// + +=== a.ts === +export const f = (x: T, y: NoInfer) => x; +>f : Symbol(f, Decl(a.ts, 0, 12)) +>T : Symbol(T, Decl(a.ts, 0, 18)) +>x : Symbol(x, Decl(a.ts, 0, 21)) +>T : Symbol(T, Decl(a.ts, 0, 18)) +>y : Symbol(y, Decl(a.ts, 0, 26)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(a.ts, 0, 18)) +>x : Symbol(x, Decl(a.ts, 0, 21)) + +=== b.ts === +import { f } from "./a"; +>f : Symbol(f, Decl(b.ts, 0, 8)) + +type NoInfer = T & number; +>NoInfer : Symbol(NoInfer, Decl(b.ts, 0, 24)) +>T : Symbol(T, Decl(b.ts, 2, 13)) +>T : Symbol(T, Decl(b.ts, 2, 13)) + +export const g = f; +>g : Symbol(g, Decl(b.ts, 4, 12)) +>f : Symbol(f, Decl(b.ts, 0, 8)) + diff --git a/tests/baselines/reference/noInferRedeclaration.types b/tests/baselines/reference/noInferRedeclaration.types new file mode 100644 index 0000000000000..0d8f54db5e4ef --- /dev/null +++ b/tests/baselines/reference/noInferRedeclaration.types @@ -0,0 +1,21 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferRedeclaration.ts] //// + +=== a.ts === +export const f = (x: T, y: NoInfer) => x; +>f : (x: T, y: NoInfer) => T +>(x: T, y: NoInfer) => x : (x: T, y: NoInfer) => T +>x : T +>y : NoInfer +>x : T + +=== b.ts === +import { f } from "./a"; +>f : (x: T, y: globalThis.NoInfer) => T + +type NoInfer = T & number; +>NoInfer : NoInfer + +export const g = f; +>g : (x: T, y: globalThis.NoInfer) => T +>f : (x: T, y: globalThis.NoInfer) => T + diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/noInferRedeclaration.ts b/tests/cases/conformance/types/typeRelationships/typeInference/noInferRedeclaration.ts new file mode 100644 index 0000000000000..feab4ca3df0ea --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/typeInference/noInferRedeclaration.ts @@ -0,0 +1,13 @@ +// @strict: true +// @declaration: true +// @target: esnext + +// @filename: a.ts +export const f = (x: T, y: NoInfer) => x; + +// @filename: b.ts +import { f } from "./a"; + +type NoInfer = T & number; + +export const g = f;