diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9a8e9eb1ee868..2e051e9774086 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14153,6 +14153,7 @@ namespace ts { // We ignore 'never' types in unions if (!(flags & TypeFlags.Never)) { includes |= flags & TypeFlags.IncludesMask; + if (flags & TypeFlags.Instantiable) includes |= TypeFlags.IncludesInstantiable; if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; if (!strictNullChecks && flags & TypeFlags.Nullable) { if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9a32a79f37f78..92225facae6c6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5187,8 +5187,6 @@ namespace ts { // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, - /* @internal */ - NotPrimitiveUnion = Any | Unknown | Enum | Void | Never | Object | Intersection | Instantiable, // The following flags are aggregated during union and intersection type construction /* @internal */ IncludesMask = Any | Unknown | Primitive | Never | Object | Union | Intersection | NonPrimitive | TemplateLiteral, @@ -5201,6 +5199,10 @@ namespace ts { IncludesWildcard = IndexedAccess, /* @internal */ IncludesEmptyObject = Conditional, + /* @internal */ + IncludesInstantiable = Substitution, + /* @internal */ + NotPrimitiveUnion = Any | Unknown | Enum | Void | Never | Object | Intersection | IncludesInstantiable, } export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; diff --git a/tests/baselines/reference/primitiveUnionDetection.js b/tests/baselines/reference/primitiveUnionDetection.js new file mode 100644 index 0000000000000..7d12cd85f9201 --- /dev/null +++ b/tests/baselines/reference/primitiveUnionDetection.js @@ -0,0 +1,24 @@ +//// [primitiveUnionDetection.ts] +// Repro from #46624 + +type Kind = "one" | "two" | "three"; + +declare function getInterfaceFromString(options?: { type?: T } & { type?: Kind }): T; + +const result = getInterfaceFromString({ type: 'two' }); + + +//// [primitiveUnionDetection.js] +"use strict"; +// Repro from #46624 +var result = getInterfaceFromString({ type: 'two' }); + + +//// [primitiveUnionDetection.d.ts] +declare type Kind = "one" | "two" | "three"; +declare function getInterfaceFromString(options?: { + type?: T; +} & { + type?: Kind; +}): T; +declare const result: "two"; diff --git a/tests/baselines/reference/primitiveUnionDetection.symbols b/tests/baselines/reference/primitiveUnionDetection.symbols new file mode 100644 index 0000000000000..d5fa7d4447193 --- /dev/null +++ b/tests/baselines/reference/primitiveUnionDetection.symbols @@ -0,0 +1,22 @@ +=== tests/cases/compiler/primitiveUnionDetection.ts === +// Repro from #46624 + +type Kind = "one" | "two" | "three"; +>Kind : Symbol(Kind, Decl(primitiveUnionDetection.ts, 0, 0)) + +declare function getInterfaceFromString(options?: { type?: T } & { type?: Kind }): T; +>getInterfaceFromString : Symbol(getInterfaceFromString, Decl(primitiveUnionDetection.ts, 2, 36)) +>T : Symbol(T, Decl(primitiveUnionDetection.ts, 4, 40)) +>Kind : Symbol(Kind, Decl(primitiveUnionDetection.ts, 0, 0)) +>options : Symbol(options, Decl(primitiveUnionDetection.ts, 4, 56)) +>type : Symbol(type, Decl(primitiveUnionDetection.ts, 4, 67)) +>T : Symbol(T, Decl(primitiveUnionDetection.ts, 4, 40)) +>type : Symbol(type, Decl(primitiveUnionDetection.ts, 4, 82)) +>Kind : Symbol(Kind, Decl(primitiveUnionDetection.ts, 0, 0)) +>T : Symbol(T, Decl(primitiveUnionDetection.ts, 4, 40)) + +const result = getInterfaceFromString({ type: 'two' }); +>result : Symbol(result, Decl(primitiveUnionDetection.ts, 6, 5)) +>getInterfaceFromString : Symbol(getInterfaceFromString, Decl(primitiveUnionDetection.ts, 2, 36)) +>type : Symbol(type, Decl(primitiveUnionDetection.ts, 6, 39)) + diff --git a/tests/baselines/reference/primitiveUnionDetection.types b/tests/baselines/reference/primitiveUnionDetection.types new file mode 100644 index 0000000000000..ac2243d80d4aa --- /dev/null +++ b/tests/baselines/reference/primitiveUnionDetection.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/primitiveUnionDetection.ts === +// Repro from #46624 + +type Kind = "one" | "two" | "three"; +>Kind : Kind + +declare function getInterfaceFromString(options?: { type?: T } & { type?: Kind }): T; +>getInterfaceFromString : (options?: ({ type?: T | undefined; } & { type?: Kind | undefined; }) | undefined) => T +>options : ({ type?: T | undefined; } & { type?: Kind | undefined; }) | undefined +>type : T | undefined +>type : Kind | undefined + +const result = getInterfaceFromString({ type: 'two' }); +>result : "two" +>getInterfaceFromString({ type: 'two' }) : "two" +>getInterfaceFromString : (options?: ({ type?: T | undefined; } & { type?: Kind | undefined; }) | undefined) => T +>{ type: 'two' } : { type: "two"; } +>type : "two" +>'two' : "two" + diff --git a/tests/cases/compiler/primitiveUnionDetection.ts b/tests/cases/compiler/primitiveUnionDetection.ts new file mode 100644 index 0000000000000..4d6cc5c661aea --- /dev/null +++ b/tests/cases/compiler/primitiveUnionDetection.ts @@ -0,0 +1,10 @@ +// @strict: true +// @declaration: true + +// Repro from #46624 + +type Kind = "one" | "two" | "three"; + +declare function getInterfaceFromString(options?: { type?: T } & { type?: Kind }): T; + +const result = getInterfaceFromString({ type: 'two' });