Properly check whether union type contains only primitive types (#46645)

* Properly check whether union type contains only primitive types

* Add regression test

* Remove 'export' modifier from test
This commit is contained in:
Anders Hejlsberg 2021-11-02 12:46:26 -07:00 committed by GitHub
parent 7f8bf0b9c4
commit 56f81075f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 2 deletions

View file

@ -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;

View file

@ -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;

View file

@ -0,0 +1,24 @@
//// [primitiveUnionDetection.ts]
// Repro from #46624
type Kind = "one" | "two" | "three";
declare function getInterfaceFromString<T extends Kind>(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<T extends Kind>(options?: {
type?: T;
} & {
type?: Kind;
}): T;
declare const result: "two";

View file

@ -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<T extends Kind>(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))

View file

@ -0,0 +1,20 @@
=== tests/cases/compiler/primitiveUnionDetection.ts ===
// Repro from #46624
type Kind = "one" | "two" | "three";
>Kind : Kind
declare function getInterfaceFromString<T extends Kind>(options?: { type?: T } & { type?: Kind }): T;
>getInterfaceFromString : <T extends Kind>(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 : <T extends Kind>(options?: ({ type?: T | undefined; } & { type?: Kind | undefined; }) | undefined) => T
>{ type: 'two' } : { type: "two"; }
>type : "two"
>'two' : "two"

View file

@ -0,0 +1,10 @@
// @strict: true
// @declaration: true
// Repro from #46624
type Kind = "one" | "two" | "three";
declare function getInterfaceFromString<T extends Kind>(options?: { type?: T } & { type?: Kind }): T;
const result = getInterfaceFromString({ type: 'two' });