From 29f7f597dfc39a20100a7780a0404c847bd07a9a Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 7 Oct 2026 15:43:22 -0700 Subject: [PATCH] Add instantiated symbol mapper into context mapper when reprinting nodes we instantiate --- tsc/internal/checker/nodebuilderimpl.go | 6 +++ tsc/internal/checker/pseudotypenodebuilder.go | 2 +- ...UninstantiatedConditionalTypeParameters.js | 30 +++++++++++++ ...tantiatedConditionalTypeParameters.symbols | 44 +++++++++++++++++++ ...nstantiatedConditionalTypeParameters.types | 40 +++++++++++++++++ ...InternalTypesProduceUniqueTypeParams.types | 2 +- .../compiler/es2018ObjectAssign.types | 4 +- .../conformance/parserRealSource14.types | 8 ++-- .../conformance/parserRealSource8.types | 4 +- .../usePromiseFinally(target=es2015).types | 4 +- ...ationEmitUnresolvedGenericAnnotations.d.ts | 43 ++++++++++++++++++ ...UninstantiatedConditionalTypeParameters.ts | 21 +++++++++ ...arationEmitUnresolvedGenericAnnotations.ts | 31 +++++++++++++ 13 files changed, 227 insertions(+), 12 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.js create mode 100644 tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.types create mode 100644 tsc/testdata/baselines/reference/transpile/declarationEmitUnresolvedGenericAnnotations.d.ts create mode 100644 tsc/testdata/tests/cases/compiler/declarationEmitUninstantiatedConditionalTypeParameters.ts create mode 100644 tsc/testdata/tests/cases/transpile/declarationEmitUnresolvedGenericAnnotations.ts diff --git a/tsc/internal/checker/nodebuilderimpl.go b/tsc/internal/checker/nodebuilderimpl.go index 4592b3c656c43..5eaba88ffe3c9 100644 --- a/tsc/internal/checker/nodebuilderimpl.go +++ b/tsc/internal/checker/nodebuilderimpl.go @@ -2300,6 +2300,11 @@ func (b *NodeBuilderImpl) serializeTypeForDeclaration(declaration *ast.Declarati var reportedInferenceFallback bool // !!! expandable hover support if !b.isActivelyExpanding() && tryReuse && b.ctx.enclosingDeclaration != nil && declaration != nil && (ast.IsAccessor(declaration) || (ast.HasInferredType(declaration) && !ast.NodeIsSynthesized(declaration) && (t.ObjectFlags()&ObjectFlagsRequiresWidening) == 0)) { + oldMapper := b.ctx.mapper + // The annotation belongs to the original declaration, not the instantiated symbol. + if symbol != nil && symbol.CheckFlags&ast.CheckFlagsInstantiated != 0 { + b.ctx.mapper = b.ch.combineTypeMappers(b.ch.valueSymbolLinks.Get(symbol).mapper, oldMapper) + } var remove func() if symbol != nil { remove = b.addSymbolTypeToContext(symbol, t) @@ -2350,6 +2355,7 @@ func (b *NodeBuilderImpl) serializeTypeForDeclaration(declaration *ast.Declarati if remove != nil { remove() } + b.ctx.mapper = oldMapper } if result == nil { if reportedInferenceFallback { diff --git a/tsc/internal/checker/pseudotypenodebuilder.go b/tsc/internal/checker/pseudotypenodebuilder.go index 9daf4b686fc43..11ccce46ae7bf 100644 --- a/tsc/internal/checker/pseudotypenodebuilder.go +++ b/tsc/internal/checker/pseudotypenodebuilder.go @@ -30,7 +30,7 @@ func (b *NodeBuilderImpl) pseudoTypeToNodeWithCheckerFallback(t *pseudochecker.P return result } else if t.Kind == pseudochecker.PseudoTypeKindDirect { existing := t.AsPseudoTypeDirect().TypeNode - if !b.canReuseExistingJSTypeNode(existing, checkerType) { + if b.getTypeFromTypeNode(existing, true /*noMappedTypes*/) == nil || !b.canReuseExistingJSTypeNode(existing, checkerType) { if !b.ctx.suppressReportInferenceFallback { b.ctx.tracker.ReportInferenceFallback(existing) } diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.js b/tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.js new file mode 100644 index 0000000000000..1e8d04f9fe465 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.js @@ -0,0 +1,30 @@ +//// [tests/cases/compiler/declarationEmitUninstantiatedConditionalTypeParameters.ts] //// + +//// [contracts.js] +exports.schema = { parse: v => v }; + +//// [router.ts] +import { State } from "./contracts"; +interface Builder { + query(resolver: () => T): { output: TOutputOut extends "unset" ? T : TOutputOut }; +} + +declare const builder: Builder<"unset">; + +export const query = builder.query((): State | null => null); +export const anyQuery = builder.query((): any => null); +export const typedQuery = builder.query((): string | null => null); + + + + +//// [router.d.ts] +export declare const query: { + output: any; +}; +export declare const anyQuery: { + output: any; +}; +export declare const typedQuery: { + output: string | null; +}; diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.symbols b/tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.symbols new file mode 100644 index 0000000000000..90f2a0401f213 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.symbols @@ -0,0 +1,44 @@ +//// [tests/cases/compiler/declarationEmitUninstantiatedConditionalTypeParameters.ts] //// + +=== router.ts === +import { State } from "./contracts"; +>State : Symbol(State, Decl(router.ts, 0, 8)) + +interface Builder { +>Builder : Symbol(Builder, Decl(router.ts, 0, 36)) +>TOutputOut : Symbol(TOutputOut, Decl(router.ts, 1, 18)) + + query(resolver: () => T): { output: TOutputOut extends "unset" ? T : TOutputOut }; +>query : Symbol(Builder.query, Decl(router.ts, 1, 31)) +>T : Symbol(T, Decl(router.ts, 2, 10)) +>resolver : Symbol(resolver, Decl(router.ts, 2, 13)) +>T : Symbol(T, Decl(router.ts, 2, 10)) +>output : Symbol(output, Decl(router.ts, 2, 34)) +>TOutputOut : Symbol(TOutputOut, Decl(router.ts, 1, 18)) +>T : Symbol(T, Decl(router.ts, 2, 10)) +>TOutputOut : Symbol(TOutputOut, Decl(router.ts, 1, 18)) +} + +declare const builder: Builder<"unset">; +>builder : Symbol(builder, Decl(router.ts, 5, 13)) +>Builder : Symbol(Builder, Decl(router.ts, 0, 36)) + +export const query = builder.query((): State | null => null); +>query : Symbol(query, Decl(router.ts, 7, 12)) +>builder.query : Symbol(Builder.query, Decl(router.ts, 1, 31)) +>builder : Symbol(builder, Decl(router.ts, 5, 13)) +>query : Symbol(Builder.query, Decl(router.ts, 1, 31)) +>State : Symbol(State, Decl(router.ts, 0, 8)) + +export const anyQuery = builder.query((): any => null); +>anyQuery : Symbol(anyQuery, Decl(router.ts, 8, 12)) +>builder.query : Symbol(Builder.query, Decl(router.ts, 1, 31)) +>builder : Symbol(builder, Decl(router.ts, 5, 13)) +>query : Symbol(Builder.query, Decl(router.ts, 1, 31)) + +export const typedQuery = builder.query((): string | null => null); +>typedQuery : Symbol(typedQuery, Decl(router.ts, 9, 12)) +>builder.query : Symbol(Builder.query, Decl(router.ts, 1, 31)) +>builder : Symbol(builder, Decl(router.ts, 5, 13)) +>query : Symbol(Builder.query, Decl(router.ts, 1, 31)) + diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.types b/tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.types new file mode 100644 index 0000000000000..2e8bdfb58259f --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitUninstantiatedConditionalTypeParameters.types @@ -0,0 +1,40 @@ +//// [tests/cases/compiler/declarationEmitUninstantiatedConditionalTypeParameters.ts] //// + +=== router.ts === +import { State } from "./contracts"; +>State : any + +interface Builder { + query(resolver: () => T): { output: TOutputOut extends "unset" ? T : TOutputOut }; +>query : (resolver: () => T) => { output: TOutputOut extends "unset" ? T : TOutputOut; } +>resolver : () => T +>output : TOutputOut extends "unset" ? T : TOutputOut +} + +declare const builder: Builder<"unset">; +>builder : Builder<"unset"> + +export const query = builder.query((): State | null => null); +>query : { output: any; } +>builder.query((): State | null => null) : { output: any; } +>builder.query : (resolver: () => T) => { output: T; } +>builder : Builder<"unset"> +>query : (resolver: () => T) => { output: T; } +>(): State | null => null : () => State | null + +export const anyQuery = builder.query((): any => null); +>anyQuery : { output: any; } +>builder.query((): any => null) : { output: any; } +>builder.query : (resolver: () => T) => { output: T; } +>builder : Builder<"unset"> +>query : (resolver: () => T) => { output: T; } +>(): any => null : () => any + +export const typedQuery = builder.query((): string | null => null); +>typedQuery : { output: string | null; } +>builder.query((): string | null => null) : { output: string | null; } +>builder.query : (resolver: () => T) => { output: T; } +>builder : Builder<"unset"> +>query : (resolver: () => T) => { output: T; } +>(): string | null => null : () => string | null + diff --git a/tsc/testdata/baselines/reference/compiler/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types b/tsc/testdata/baselines/reference/compiler/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types index 85714338f2607..364743dcb7bec 100644 --- a/tsc/testdata/baselines/reference/compiler/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types +++ b/tsc/testdata/baselines/reference/compiler/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types @@ -50,7 +50,7 @@ export const updateIfChanged = (t: T) => { >key : K reduce>(u[key as keyof U] as Value, (v: Value) => { ->reduce>(u[key as keyof U] as Value, (v: Value) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }) : (>>(key: K) => (>>>>(key: K_2) => (>>>>>>>>(key: K_3) => (>>>>>>>>>>>>>>>>(key: K_4) => (>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>(key: K_5) => (>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>(key: K_6) => (>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>(key: K_7) => (>(key: K_8) => any & { map: (updater: (u: any) => any) => T; set: (newU: any) => T; }) & { map: (updater: (u: any) => any) => T; set: (newU: any) => T; }) & { map: (updater: (u: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>>>>>>) => Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>) => Value>>>>>>>>>>>>>) => T; set: (newU: Value>>>>>>) => T; }) & { map: (updater: (u: Value>>) => Value>>>>>) => T; set: (newU: Value>>) => T; }) & { map: (updater: (u: Value) => Value>) => T; set: (newU: Value) => T; } +>reduce>(u[key as keyof U] as Value, (v: Value) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }) : (>>(key: K) => (>>>>(key: K_2) => (>>>>>>>>(key: K_3) => (>>>>>>>>>>>>>>>>(key: K_4) => (>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>(key: K_5) => (>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>(key: K_6) => (>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>(key: K_7) => (>(key: K_8) => any & { map: (updater: (u: any) => any) => T; set: (newU: any) => T; }) & { map: (updater: (u: any) => any) => T; set: (newU: any) => T; }) & { map: (updater: (u: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => any) => T; set: (newU: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>>>>>>) => Value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>) => Value>>>>>>>>>>>>>) => T; set: (newU: Value>>>>>>) => T; }) & { map: (updater: (u: Value>>) => Value>>>>>) => T; set: (newU: Value>>) => T; }) & { map: (updater: (u: Value) => Value>) => T; set: (newU: Value) => T; } >reduce : (u: U, update: (u: U) => T) => (>(key: K) => (>>(key: K_1) => any & { map: (updater: (u: Value) => Value>) => T; set: (newU: Value) => T; }) & { map: (updater: (u: Value) => Value>) => T; set: (newU: Value) => T; }) & { map: (updater: (u: U) => U) => T; set: (newU: U) => T; } >u[key as keyof U] as Value : Value >u[key as keyof U] : U[keyof U] diff --git a/tsc/testdata/baselines/reference/compiler/es2018ObjectAssign.types b/tsc/testdata/baselines/reference/compiler/es2018ObjectAssign.types index 35054c220842d..63e7b4543653e 100644 --- a/tsc/testdata/baselines/reference/compiler/es2018ObjectAssign.types +++ b/tsc/testdata/baselines/reference/compiler/es2018ObjectAssign.types @@ -17,7 +17,7 @@ declare const p: Promise; p.finally(); >p.finally() : Promise ->p.finally : (onfinally?: (() => void) | undefined | null) => Promise +>p.finally : (onfinally?: (() => void) | null | undefined) => Promise >p : Promise ->finally : (onfinally?: (() => void) | undefined | null) => Promise +>finally : (onfinally?: (() => void) | null | undefined) => Promise diff --git a/tsc/testdata/baselines/reference/conformance/parserRealSource14.types b/tsc/testdata/baselines/reference/conformance/parserRealSource14.types index 5127066179986..98eac2b018a1d 100644 --- a/tsc/testdata/baselines/reference/conformance/parserRealSource14.types +++ b/tsc/testdata/baselines/reference/conformance/parserRealSource14.types @@ -172,11 +172,11 @@ namespace TypeScript { this.asts.pop(); >this.asts.pop() : TypeScript.AST ->this.asts.pop : () => TypeScript.AST | undefined +>this.asts.pop : () => TypeScript.AST >this.asts : TypeScript.AST[] >this : this >asts : TypeScript.AST[] ->pop : () => TypeScript.AST | undefined +>pop : () => TypeScript.AST } return head; >head : TypeScript.AST @@ -201,11 +201,11 @@ namespace TypeScript { this.asts.pop(); >this.asts.pop() : TypeScript.AST ->this.asts.pop : () => TypeScript.AST | undefined +>this.asts.pop : () => TypeScript.AST >this.asts : TypeScript.AST[] >this : this >asts : TypeScript.AST[] ->pop : () => TypeScript.AST | undefined +>pop : () => TypeScript.AST } this.top = this.asts.length; >this.top = this.asts.length : number diff --git a/tsc/testdata/baselines/reference/conformance/parserRealSource8.types b/tsc/testdata/baselines/reference/conformance/parserRealSource8.types index 14c3a744d9876..4e33cd08576fb 100644 --- a/tsc/testdata/baselines/reference/conformance/parserRealSource8.types +++ b/tsc/testdata/baselines/reference/conformance/parserRealSource8.types @@ -2178,11 +2178,11 @@ namespace TypeScript { context.modDeclChain.pop(); >context.modDeclChain.pop() : any ->context.modDeclChain.pop : () => ModuleDeclaration | undefined +>context.modDeclChain.pop : () => any >context.modDeclChain : ModuleDeclaration[] >context : AssignScopeContext >modDeclChain : ModuleDeclaration[] ->pop : () => ModuleDeclaration | undefined +>pop : () => any if (context.modDeclChain.length >= 1) { >context.modDeclChain.length >= 1 : boolean diff --git a/tsc/testdata/baselines/reference/conformance/usePromiseFinally(target=es2015).types b/tsc/testdata/baselines/reference/conformance/usePromiseFinally(target=es2015).types index 421207e8fafa9..63f07e7fbda88 100644 --- a/tsc/testdata/baselines/reference/conformance/usePromiseFinally(target=es2015).types +++ b/tsc/testdata/baselines/reference/conformance/usePromiseFinally(target=es2015).types @@ -4,7 +4,7 @@ let promise1 = new Promise(function(resolve, reject) {}) >promise1 : Promise >new Promise(function(resolve, reject) {}) .finally(function() {}) : Promise ->new Promise(function(resolve, reject) {}) .finally : (onfinally?: (() => void) | undefined | null) => Promise +>new Promise(function(resolve, reject) {}) .finally : (onfinally?: (() => void) | null | undefined) => Promise >new Promise(function(resolve, reject) {}) : Promise >Promise : PromiseConstructor >function(resolve, reject) {} : (resolve: (value: unknown) => void, reject: (reason?: any) => void) => void @@ -12,6 +12,6 @@ let promise1 = new Promise(function(resolve, reject) {}) >reject : (reason?: any) => void .finally(function() {}); ->finally : (onfinally?: (() => void) | undefined | null) => Promise +>finally : (onfinally?: (() => void) | null | undefined) => Promise >function() {} : () => void diff --git a/tsc/testdata/baselines/reference/transpile/declarationEmitUnresolvedGenericAnnotations.d.ts b/tsc/testdata/baselines/reference/transpile/declarationEmitUnresolvedGenericAnnotations.d.ts new file mode 100644 index 0000000000000..69ab3ca51b7d4 --- /dev/null +++ b/tsc/testdata/baselines/reference/transpile/declarationEmitUnresolvedGenericAnnotations.d.ts @@ -0,0 +1,43 @@ +//// [declarationEmitUnresolvedGenericAnnotations.ts] //// +import type { Box, Schema } from "./external"; + +export const identity = (value: Box): Box => value; +export const nullable = (value: Box | null): Box | null => value; +export const conditional = (value: T): T extends string ? Box : T => null!; +export const mapped = (value: T): { [K in keyof T]: Box } => null!; + +export const methods = { + identity(value: Box): Box { + return value; + }, + conditional(value: T): T extends string ? Box : T { + return null!; + } +}; + +export class Container { + value: Box; + + constructor(value: Box) { + this.value = value; + } + + map(value: Box): Box { + return value; + } +} +//// [declarationEmitUnresolvedGenericAnnotations.d.ts] //// +import type { Box, Schema } from "./external"; +export declare const identity: (value: Box) => Box; +export declare const nullable: (value: Box | null) => Box | null; +export declare const conditional: (value: T) => T extends string ? Box : T; +export declare const mapped: (value: T) => { [K in keyof T]: Box; }; +export declare const methods: { + identity(value: Box): Box; + conditional(value: T): T extends string ? Box : T; +}; +export declare class Container { + value: Box; + constructor(value: Box); + map(value: Box): Box; +} diff --git a/tsc/testdata/tests/cases/compiler/declarationEmitUninstantiatedConditionalTypeParameters.ts b/tsc/testdata/tests/cases/compiler/declarationEmitUninstantiatedConditionalTypeParameters.ts new file mode 100644 index 0000000000000..0b9e769bcf112 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/declarationEmitUninstantiatedConditionalTypeParameters.ts @@ -0,0 +1,21 @@ +// @declaration: true +// @emitDeclarationOnly: true +// @strictNullChecks: true +// @noImplicitAny: false +// @module: commonjs +// @noImplicitReferences: true + +// @filename: contracts.js +exports.schema = { parse: v => v }; + +// @filename: router.ts +import { State } from "./contracts"; +interface Builder { + query(resolver: () => T): { output: TOutputOut extends "unset" ? T : TOutputOut }; +} + +declare const builder: Builder<"unset">; + +export const query = builder.query((): State | null => null); +export const anyQuery = builder.query((): any => null); +export const typedQuery = builder.query((): string | null => null); diff --git a/tsc/testdata/tests/cases/transpile/declarationEmitUnresolvedGenericAnnotations.ts b/tsc/testdata/tests/cases/transpile/declarationEmitUnresolvedGenericAnnotations.ts new file mode 100644 index 0000000000000..a6e46306d2431 --- /dev/null +++ b/tsc/testdata/tests/cases/transpile/declarationEmitUnresolvedGenericAnnotations.ts @@ -0,0 +1,31 @@ +// @strict: true +// @declaration: true +// @emitDeclarationOnly: true + +import type { Box, Schema } from "./external"; + +export const identity = (value: Box): Box => value; +export const nullable = (value: Box | null): Box | null => value; +export const conditional = (value: T): T extends string ? Box : T => null!; +export const mapped = (value: T): { [K in keyof T]: Box } => null!; + +export const methods = { + identity(value: Box): Box { + return value; + }, + conditional(value: T): T extends string ? Box : T { + return null!; + } +}; + +export class Container { + value: Box; + + constructor(value: Box) { + this.value = value; + } + + map(value: Box): Box { + return value; + } +}