mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 12:32:08 -06:00
Reduce intersections of constrained type variables and primitive types (#56515)
This commit is contained in:
parent
f834133fe2
commit
3258d75169
@ -16824,6 +16824,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (!(flags & TypeFlags.Never)) {
|
||||
includes |= flags & TypeFlags.IncludesMask;
|
||||
if (flags & TypeFlags.Instantiable) includes |= TypeFlags.IncludesInstantiable;
|
||||
if (flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable) includes |= TypeFlags.IncludesConstrainedTypeVariable;
|
||||
if (type === wildcardType) includes |= TypeFlags.IncludesWildcard;
|
||||
if (!strictNullChecks && flags & TypeFlags.Nullable) {
|
||||
if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType;
|
||||
@ -16968,6 +16969,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
|
||||
function removeConstrainedTypeVariables(types: Type[]) {
|
||||
const typeVariables: TypeVariable[] = [];
|
||||
// First collect a list of the type variables occurring in constraining intersections.
|
||||
for (const type of types) {
|
||||
if (getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable) {
|
||||
const index = (type as IntersectionType).types[0].flags & TypeFlags.TypeVariable ? 0 : 1;
|
||||
pushIfUnique(typeVariables, (type as IntersectionType).types[index]);
|
||||
}
|
||||
}
|
||||
// For each type variable, check if the constraining intersections for that type variable fully
|
||||
// cover the constraint of the type variable; if so, remove the constraining intersections and
|
||||
// substitute the type variable.
|
||||
for (const typeVariable of typeVariables) {
|
||||
const primitives: Type[] = [];
|
||||
// First collect the primitive types from the constraining intersections.
|
||||
for (const type of types) {
|
||||
if (getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable) {
|
||||
const index = (type as IntersectionType).types[0].flags & TypeFlags.TypeVariable ? 0 : 1;
|
||||
if ((type as IntersectionType).types[index] === typeVariable) {
|
||||
insertType(primitives, (type as IntersectionType).types[1 - index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If every constituent in the type variable's constraint is covered by an intersection of the type
|
||||
// variable and that constituent, remove those intersections and substitute the type variable.
|
||||
const constraint = getBaseConstraintOfType(typeVariable)!;
|
||||
if (everyType(constraint, t => containsType(primitives, t))) {
|
||||
let i = types.length;
|
||||
while (i > 0) {
|
||||
i--;
|
||||
const type = types[i];
|
||||
if (getObjectFlags(type) & ObjectFlags.IsConstrainedTypeVariable) {
|
||||
const index = (type as IntersectionType).types[0].flags & TypeFlags.TypeVariable ? 0 : 1;
|
||||
if ((type as IntersectionType).types[index] === typeVariable && containsType(primitives, (type as IntersectionType).types[1 - index])) {
|
||||
orderedRemoveItemAt(types, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
insertType(types, typeVariable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isNamedUnionType(type: Type) {
|
||||
return !!(type.flags & TypeFlags.Union && (type.aliasSymbol || (type as UnionType).origin));
|
||||
}
|
||||
@ -17042,6 +17086,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) {
|
||||
removeStringLiteralsMatchedByTemplateLiterals(typeSet);
|
||||
}
|
||||
if (includes & TypeFlags.IncludesConstrainedTypeVariable) {
|
||||
removeConstrainedTypeVariables(typeSet);
|
||||
}
|
||||
if (unionReduction === UnionReduction.Subtype) {
|
||||
typeSet = removeSubtypes(typeSet, !!(includes & TypeFlags.Object));
|
||||
if (!typeSet) {
|
||||
@ -17306,9 +17353,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return true;
|
||||
}
|
||||
|
||||
function createIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) {
|
||||
function createIntersectionType(types: Type[], objectFlags: ObjectFlags, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) {
|
||||
const result = createType(TypeFlags.Intersection) as IntersectionType;
|
||||
result.objectFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
|
||||
result.objectFlags = objectFlags | getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
|
||||
result.types = types;
|
||||
result.aliasSymbol = aliasSymbol;
|
||||
result.aliasTypeArguments = aliasTypeArguments;
|
||||
@ -17329,6 +17376,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const typeMembershipMap = new Map<string, Type>();
|
||||
const includes = addTypesToIntersection(typeMembershipMap, 0 as TypeFlags, types);
|
||||
const typeSet: Type[] = arrayFrom(typeMembershipMap.values());
|
||||
let objectFlags = ObjectFlags.None;
|
||||
// An intersection type is considered empty if it contains
|
||||
// the type never, or
|
||||
// more than one unit type or,
|
||||
@ -17380,6 +17428,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (typeSet.length === 1) {
|
||||
return typeSet[0];
|
||||
}
|
||||
if (typeSet.length === 2) {
|
||||
const typeVarIndex = typeSet[0].flags & TypeFlags.TypeVariable ? 0 : 1;
|
||||
const typeVariable = typeSet[typeVarIndex];
|
||||
const primitiveType = typeSet[1 - typeVarIndex];
|
||||
if (typeVariable.flags & TypeFlags.TypeVariable && (primitiveType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) || includes & TypeFlags.IncludesEmptyObject)) {
|
||||
// We have an intersection T & P or P & T, where T is a type variable and P is a primitive type, the object type, or {}.
|
||||
const constraint = getBaseConstraintOfType(typeVariable);
|
||||
// Check that T's constraint is similarly composed of primitive types, the object type, or {}.
|
||||
if (constraint && everyType(constraint, t => !!(t.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) || isEmptyAnonymousObjectType(t))) {
|
||||
// If T's constraint is a subtype of P, simply return T. For example, given `T extends "a" | "b"`,
|
||||
// the intersection `T & string` reduces to just T.
|
||||
if (isTypeStrictSubtypeOf(constraint, primitiveType)) {
|
||||
return typeVariable;
|
||||
}
|
||||
if (!(constraint.flags & TypeFlags.Union && someType(constraint, c => isTypeStrictSubtypeOf(c, primitiveType)))) {
|
||||
// No constituent of T's constraint is a subtype of P. If P is also not a subtype of T's constraint,
|
||||
// then the constraint and P are unrelated, and the intersection reduces to never. For example, given
|
||||
// `T extends "a" | "b"`, the intersection `T & number` reduces to never.
|
||||
if (!isTypeStrictSubtypeOf(primitiveType, constraint)) {
|
||||
return neverType;
|
||||
}
|
||||
}
|
||||
// Some constituent of T's constraint is a subtype of P, or P is a subtype of T's constraint. Thus,
|
||||
// the intersection further constrains the type variable. For example, given `T extends string | number`,
|
||||
// the intersection `T & "a"` is marked as a constrained type variable. Likewise, given `T extends "a" | 1`,
|
||||
// the intersection `T & number` is marked as a constrained type variable.
|
||||
objectFlags = ObjectFlags.IsConstrainedTypeVariable;
|
||||
}
|
||||
}
|
||||
}
|
||||
const id = getTypeListId(typeSet) + getAliasId(aliasSymbol, aliasTypeArguments);
|
||||
let result = intersectionTypes.get(id);
|
||||
if (!result) {
|
||||
@ -17415,7 +17493,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = createIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
|
||||
result = createIntersectionType(typeSet, objectFlags, aliasSymbol, aliasTypeArguments);
|
||||
}
|
||||
intersectionTypes.set(id, result);
|
||||
}
|
||||
|
||||
@ -6153,6 +6153,8 @@ export const enum TypeFlags {
|
||||
/** @internal */
|
||||
IncludesInstantiable = Substitution,
|
||||
/** @internal */
|
||||
IncludesConstrainedTypeVariable = StringMapping,
|
||||
/** @internal */
|
||||
NotPrimitiveUnion = Any | Unknown | Void | Never | Object | Intersection | IncludesInstantiable,
|
||||
}
|
||||
|
||||
@ -6313,6 +6315,8 @@ export const enum ObjectFlags {
|
||||
IsNeverIntersectionComputed = 1 << 24, // IsNeverLike flag has been computed
|
||||
/** @internal */
|
||||
IsNeverIntersection = 1 << 25, // Intersection reduces to never
|
||||
/** @internal */
|
||||
IsConstrainedTypeVariable = 1 << 26, // T & C, where T's constraint and C are primitives, object, or {}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
@ -88,6 +88,7 @@ conditionalTypes1.ts(288,43): error TS2322: Type 'T95<U>' is not assignable to t
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'NonNullable<T>'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type '{}'.
|
||||
!!! related TS2208 conditionalTypes1.ts:10:13: This type parameter might need an `extends {}` constraint.
|
||||
!!! related TS2208 conditionalTypes1.ts:10:13: This type parameter might need an `extends NonNullable<T>` constraint.
|
||||
}
|
||||
|
||||
function f2<T extends string | undefined>(x: T, y: NonNullable<T>) {
|
||||
|
||||
@ -138,12 +138,12 @@ function f5<T>(x: T & {}) {
|
||||
|
||||
function f6<T extends {}>(x: T & {}) {
|
||||
>f6 : <T extends {}>(x: T & {}) => boolean
|
||||
>x : T & {}
|
||||
>x : T
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x instanceof Object && 'a' in x : boolean
|
||||
>x instanceof Object : boolean
|
||||
>x : T & {}
|
||||
>x : T
|
||||
>Object : ObjectConstructor
|
||||
>'a' in x : boolean
|
||||
>'a' : "a"
|
||||
@ -152,15 +152,15 @@ function f6<T extends {}>(x: T & {}) {
|
||||
|
||||
function f7<T extends object>(x: T & {}) {
|
||||
>f7 : <T extends object>(x: T & {}) => boolean
|
||||
>x : T & {}
|
||||
>x : T
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x instanceof Object && 'a' in x : boolean
|
||||
>x instanceof Object : boolean
|
||||
>x : T & {}
|
||||
>x : T
|
||||
>Object : ObjectConstructor
|
||||
>'a' in x : boolean
|
||||
>'a' : "a"
|
||||
>x : T & {}
|
||||
>x : T
|
||||
}
|
||||
|
||||
|
||||
@ -1078,12 +1078,12 @@ function isHTMLTable<T extends object | null>(table: T): boolean {
|
||||
const f = <P extends object>(a: P & {}) => {
|
||||
>f : <P extends object>(a: P & {}) => void
|
||||
><P extends object>(a: P & {}) => { "foo" in a;} : <P extends object>(a: P & {}) => void
|
||||
>a : P & {}
|
||||
>a : P
|
||||
|
||||
"foo" in a;
|
||||
>"foo" in a : boolean
|
||||
>"foo" : "foo"
|
||||
>a : P & {}
|
||||
>a : P
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -1078,12 +1078,12 @@ function isHTMLTable<T extends object | null>(table: T): boolean {
|
||||
const f = <P extends object>(a: P & {}) => {
|
||||
>f : <P extends object>(a: P & {}) => void
|
||||
><P extends object>(a: P & {}) => { "foo" in a;} : <P extends object>(a: P & {}) => void
|
||||
>a : P & {}
|
||||
>a : P
|
||||
|
||||
"foo" in a;
|
||||
>"foo" in a : boolean
|
||||
>"foo" : "foo"
|
||||
>a : P & {}
|
||||
>a : P
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -15,8 +15,10 @@ indexSignatures1.ts(73,5): error TS2374: Duplicate index signature for type '`fo
|
||||
indexSignatures1.ts(81,5): error TS2413: '`a${string}a`' index type '"c"' is not assignable to '`${string}a`' index type '"b"'.
|
||||
indexSignatures1.ts(81,5): error TS2413: '`a${string}a`' index type '"c"' is not assignable to '`a${string}`' index type '"a"'.
|
||||
indexSignatures1.ts(87,6): error TS1337: An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.
|
||||
indexSignatures1.ts(88,5): error TS2374: Duplicate index signature for type 'T'.
|
||||
indexSignatures1.ts(88,6): error TS1337: An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.
|
||||
indexSignatures1.ts(89,6): error TS1268: An index signature parameter type must be 'string', 'number', 'symbol', or a template literal type.
|
||||
indexSignatures1.ts(90,5): error TS2374: Duplicate index signature for type 'T'.
|
||||
indexSignatures1.ts(90,6): error TS1337: An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.
|
||||
indexSignatures1.ts(117,1): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'I1'.
|
||||
No index signature with a parameter of type 'string' was found on type 'I1'.
|
||||
@ -69,7 +71,7 @@ indexSignatures1.ts(289,7): error TS2322: Type 'number' is not assignable to typ
|
||||
indexSignatures1.ts(312,43): error TS2353: Object literal may only specify known properties, and '[sym]' does not exist in type '{ [key: number]: string; }'.
|
||||
|
||||
|
||||
==== indexSignatures1.ts (50 errors) ====
|
||||
==== indexSignatures1.ts (52 errors) ====
|
||||
// Symbol index signature checking
|
||||
|
||||
const sym = Symbol();
|
||||
@ -188,12 +190,16 @@ indexSignatures1.ts(312,43): error TS2353: Object literal may only specify known
|
||||
~~~
|
||||
!!! error TS1337: An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.
|
||||
[key: T | number]: string; // Error
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2374: Duplicate index signature for type 'T'.
|
||||
~~~
|
||||
!!! error TS1337: An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.
|
||||
[key: Error]: string; // Error
|
||||
~~~
|
||||
!!! error TS1268: An index signature parameter type must be 'string', 'number', 'symbol', or a template literal type.
|
||||
[key: T & string]: string; // Error
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2374: Duplicate index signature for type 'T'.
|
||||
~~~
|
||||
!!! error TS1337: An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.
|
||||
}
|
||||
|
||||
@ -261,7 +261,7 @@ type Invalid<T extends string> = {
|
||||
>key : Error
|
||||
|
||||
[key: T & string]: string; // Error
|
||||
>key : T & string
|
||||
>key : T
|
||||
}
|
||||
|
||||
// Intersections in index signatures
|
||||
|
||||
@ -45,7 +45,7 @@ type T1 = (string | number | undefined) & (string | null | undefined); // strin
|
||||
|
||||
function f3<T extends string | number | undefined>(x: T & (number | object | undefined)) {
|
||||
>f3 : <T extends string | number | undefined>(x: T & (number | object | undefined)) => void
|
||||
>x : T & (number | object | undefined)
|
||||
>x : (T & undefined) | (T & number)
|
||||
|
||||
const y: number | undefined = x;
|
||||
>y : number | undefined
|
||||
@ -54,7 +54,7 @@ function f3<T extends string | number | undefined>(x: T & (number | object | und
|
||||
|
||||
function f4<T extends string | number>(x: T & (number | object)) {
|
||||
>f4 : <T extends string | number>(x: T & (number | object)) => void
|
||||
>x : T & (number | object)
|
||||
>x : T & number
|
||||
|
||||
const y: number = x;
|
||||
>y : number
|
||||
|
||||
@ -113,7 +113,7 @@ declare function f5<S, T extends undefined>(a: S | T): S | T;
|
||||
declare function f6<T extends object | undefined>(a: T): T;
|
||||
declare function g1<T extends {}, A extends {
|
||||
z: (T | undefined) & T;
|
||||
}>(a: A): T | (undefined & T);
|
||||
}>(a: A): T;
|
||||
interface DatafulFoo<T> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
@ -58,19 +58,19 @@ function f6<T extends object | undefined>(a: T) {
|
||||
// Repro from #46976
|
||||
|
||||
function g1<T extends {}, A extends { z: (T | undefined) & T }>(a: A) {
|
||||
>g1 : <T extends {}, A extends { z: (T | undefined) & T; }>(a: A) => T | (undefined & T)
|
||||
>z : T | (undefined & T)
|
||||
>g1 : <T extends {}, A extends { z: (T | undefined) & T; }>(a: A) => T
|
||||
>z : T
|
||||
>a : A
|
||||
|
||||
const { z } = a;
|
||||
>z : T | (undefined & T)
|
||||
>z : T
|
||||
>a : A
|
||||
|
||||
return {
|
||||
>{ ...z } : T | (undefined & T)
|
||||
>{ ...z } : T
|
||||
|
||||
...z
|
||||
>z : T | (undefined & T)
|
||||
>z : T
|
||||
|
||||
};
|
||||
}
|
||||
@ -100,9 +100,9 @@ class Foo<T extends string> {
|
||||
this.data.toLocaleLowerCase();
|
||||
>this.data.toLocaleLowerCase() : string
|
||||
>this.data.toLocaleLowerCase : (locales?: string | string[] | undefined) => string
|
||||
>this.data : T | (undefined & T)
|
||||
>this.data : T
|
||||
>this : this & DatafulFoo<T>
|
||||
>data : T | (undefined & T)
|
||||
>data : T
|
||||
>toLocaleLowerCase : (locales?: string | string[] | undefined) => string
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,335 @@
|
||||
//// [tests/cases/compiler/typeVariableConstraintIntersections.ts] ////
|
||||
|
||||
=== typeVariableConstraintIntersections.ts ===
|
||||
type T00<K extends "a" | "b"> = K & "a";
|
||||
>T00 : Symbol(T00, Decl(typeVariableConstraintIntersections.ts, 0, 0))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 0, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 0, 9))
|
||||
|
||||
type T01<K extends "a" | "b"> = K & "c";
|
||||
>T01 : Symbol(T01, Decl(typeVariableConstraintIntersections.ts, 0, 40))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 1, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 1, 9))
|
||||
|
||||
type T02<K extends "a" | "b"> = K & string;
|
||||
>T02 : Symbol(T02, Decl(typeVariableConstraintIntersections.ts, 1, 40))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 2, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 2, 9))
|
||||
|
||||
type T10<K extends string> = K & "a";
|
||||
>T10 : Symbol(T10, Decl(typeVariableConstraintIntersections.ts, 2, 43))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 4, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 4, 9))
|
||||
|
||||
type T11<K extends string> = K & "c";
|
||||
>T11 : Symbol(T11, Decl(typeVariableConstraintIntersections.ts, 4, 37))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 5, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 5, 9))
|
||||
|
||||
type T12<K extends string> = K & string;
|
||||
>T12 : Symbol(T12, Decl(typeVariableConstraintIntersections.ts, 5, 37))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 6, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 6, 9))
|
||||
|
||||
type T20<K extends "a" | "b" | "c"> = K & ("a" | "b" | "c");
|
||||
>T20 : Symbol(T20, Decl(typeVariableConstraintIntersections.ts, 6, 40))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 8, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 8, 9))
|
||||
|
||||
type T21<K extends "a" | "b" | "c"> = ("a" | "b" | "c") & K;
|
||||
>T21 : Symbol(T21, Decl(typeVariableConstraintIntersections.ts, 8, 60))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 9, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 9, 9))
|
||||
|
||||
type T22<K extends "a" | "b" | "c"> = K & ("a" | "b");
|
||||
>T22 : Symbol(T22, Decl(typeVariableConstraintIntersections.ts, 9, 60))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 10, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 10, 9))
|
||||
|
||||
type T23<K extends "a" | "b" | "c"> = ("a" | "b") & K;
|
||||
>T23 : Symbol(T23, Decl(typeVariableConstraintIntersections.ts, 10, 54))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 11, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 11, 9))
|
||||
|
||||
type T30<K extends "a" | "b"> = K & ("a" | "b" | "c");
|
||||
>T30 : Symbol(T30, Decl(typeVariableConstraintIntersections.ts, 11, 54))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 13, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 13, 9))
|
||||
|
||||
type T31<K extends "a" | "b"> = ("a" | "b" | "c") & K;
|
||||
>T31 : Symbol(T31, Decl(typeVariableConstraintIntersections.ts, 13, 54))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 14, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 14, 9))
|
||||
|
||||
type T32<K extends "a" | "b"> = K & ("a" | "b");
|
||||
>T32 : Symbol(T32, Decl(typeVariableConstraintIntersections.ts, 14, 54))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 15, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 15, 9))
|
||||
|
||||
type T33<K extends "a" | "b"> = ("a" | "b") & K;
|
||||
>T33 : Symbol(T33, Decl(typeVariableConstraintIntersections.ts, 15, 48))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 16, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 16, 9))
|
||||
|
||||
type T40<K extends {}> = K & undefined;
|
||||
>T40 : Symbol(T40, Decl(typeVariableConstraintIntersections.ts, 16, 48))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 18, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 18, 9))
|
||||
|
||||
type T41<K extends {}> = K & null;
|
||||
>T41 : Symbol(T41, Decl(typeVariableConstraintIntersections.ts, 18, 39))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 19, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 19, 9))
|
||||
|
||||
type T42<K extends {}> = K & object;
|
||||
>T42 : Symbol(T42, Decl(typeVariableConstraintIntersections.ts, 19, 34))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 20, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 20, 9))
|
||||
|
||||
type T43<K extends {}> = K & {};
|
||||
>T43 : Symbol(T43, Decl(typeVariableConstraintIntersections.ts, 20, 36))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 21, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 21, 9))
|
||||
|
||||
type T50<K extends "a" | 0> = K & "a";
|
||||
>T50 : Symbol(T50, Decl(typeVariableConstraintIntersections.ts, 21, 32))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 23, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 23, 9))
|
||||
|
||||
type T51<K extends "a" | 0> = K & "b";
|
||||
>T51 : Symbol(T51, Decl(typeVariableConstraintIntersections.ts, 23, 38))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 24, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 24, 9))
|
||||
|
||||
type T52<K extends "a" | 0> = K & string;
|
||||
>T52 : Symbol(T52, Decl(typeVariableConstraintIntersections.ts, 24, 38))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 25, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 25, 9))
|
||||
|
||||
type T53<K extends "a" | 0> = K & 0;
|
||||
>T53 : Symbol(T53, Decl(typeVariableConstraintIntersections.ts, 25, 41))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 26, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 26, 9))
|
||||
|
||||
type T54<K extends "a" | 0> = K & 1;
|
||||
>T54 : Symbol(T54, Decl(typeVariableConstraintIntersections.ts, 26, 36))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 27, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 27, 9))
|
||||
|
||||
type T55<K extends "a" | 0> = K & number;
|
||||
>T55 : Symbol(T55, Decl(typeVariableConstraintIntersections.ts, 27, 36))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 28, 9))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 28, 9))
|
||||
|
||||
type T60<T extends "a" | "b", U extends T> = U & "a";
|
||||
>T60 : Symbol(T60, Decl(typeVariableConstraintIntersections.ts, 28, 41))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 30, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 30, 29))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 30, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 30, 29))
|
||||
|
||||
type T61<T extends "a" | "b", U extends T> = U & ("a" | "b");
|
||||
>T61 : Symbol(T61, Decl(typeVariableConstraintIntersections.ts, 30, 53))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 31, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 31, 29))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 31, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 31, 29))
|
||||
|
||||
type T62<T extends "a" | "b", U extends T> = U & ("a" | "b" | "c");
|
||||
>T62 : Symbol(T62, Decl(typeVariableConstraintIntersections.ts, 31, 61))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 32, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 32, 29))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 32, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 32, 29))
|
||||
|
||||
type T63<T extends "a" | "b", U extends T> = U & string;
|
||||
>T63 : Symbol(T63, Decl(typeVariableConstraintIntersections.ts, 32, 67))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 33, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 33, 29))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 33, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 33, 29))
|
||||
|
||||
type T70<T extends "a" | "b", U extends T | "c"> = U & "a";
|
||||
>T70 : Symbol(T70, Decl(typeVariableConstraintIntersections.ts, 33, 56))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 35, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 35, 29))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 35, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 35, 29))
|
||||
|
||||
type T71<T extends "a" | "b", U extends T | "c"> = U & ("a" | "b");
|
||||
>T71 : Symbol(T71, Decl(typeVariableConstraintIntersections.ts, 35, 59))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 36, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 36, 29))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 36, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 36, 29))
|
||||
|
||||
type T72<T extends "a" | "b", U extends T | "c"> = U & ("a" | "b" | "c");
|
||||
>T72 : Symbol(T72, Decl(typeVariableConstraintIntersections.ts, 36, 67))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 37, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 37, 29))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 37, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 37, 29))
|
||||
|
||||
type T73<T extends "a" | "b", U extends T | "c"> = U & string;
|
||||
>T73 : Symbol(T73, Decl(typeVariableConstraintIntersections.ts, 37, 73))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 38, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 38, 29))
|
||||
>T : Symbol(T, Decl(typeVariableConstraintIntersections.ts, 38, 9))
|
||||
>U : Symbol(U, Decl(typeVariableConstraintIntersections.ts, 38, 29))
|
||||
|
||||
declare function isA(x: any): x is "a";
|
||||
>isA : Symbol(isA, Decl(typeVariableConstraintIntersections.ts, 38, 62))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 40, 21))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 40, 21))
|
||||
|
||||
declare function isB(x: any): x is "b";
|
||||
>isB : Symbol(isB, Decl(typeVariableConstraintIntersections.ts, 40, 39))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 41, 21))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 41, 21))
|
||||
|
||||
declare function isC(x: any): x is "c";
|
||||
>isC : Symbol(isC, Decl(typeVariableConstraintIntersections.ts, 41, 39))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 42, 21))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 42, 21))
|
||||
|
||||
function foo<K extends "a" | "b">(x: K) {
|
||||
>foo : Symbol(foo, Decl(typeVariableConstraintIntersections.ts, 42, 39))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 44, 13))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 44, 13))
|
||||
|
||||
if (isA(x)) {
|
||||
>isA : Symbol(isA, Decl(typeVariableConstraintIntersections.ts, 38, 62))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
|
||||
x; // K & "a"
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
}
|
||||
if (isB(x)) {
|
||||
>isB : Symbol(isB, Decl(typeVariableConstraintIntersections.ts, 40, 39))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
|
||||
x; // K & "b"
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
}
|
||||
if (isC(x)) {
|
||||
>isC : Symbol(isC, Decl(typeVariableConstraintIntersections.ts, 41, 39))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
|
||||
x; // never
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
}
|
||||
if (isA(x) || isB(x)) {
|
||||
>isA : Symbol(isA, Decl(typeVariableConstraintIntersections.ts, 38, 62))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
>isB : Symbol(isB, Decl(typeVariableConstraintIntersections.ts, 40, 39))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
|
||||
x; // K
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
}
|
||||
if (!(isA(x) || isB(x))) {
|
||||
>isA : Symbol(isA, Decl(typeVariableConstraintIntersections.ts, 38, 62))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
>isB : Symbol(isB, Decl(typeVariableConstraintIntersections.ts, 40, 39))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
|
||||
return;
|
||||
}
|
||||
x; // K
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 44, 34))
|
||||
}
|
||||
|
||||
// Example from #30581
|
||||
|
||||
type OptionOne = {
|
||||
>OptionOne : Symbol(OptionOne, Decl(typeVariableConstraintIntersections.ts, 61, 1))
|
||||
|
||||
kind: "one";
|
||||
>kind : Symbol(kind, Decl(typeVariableConstraintIntersections.ts, 65, 18))
|
||||
|
||||
s: string;
|
||||
>s : Symbol(s, Decl(typeVariableConstraintIntersections.ts, 66, 14))
|
||||
|
||||
};
|
||||
|
||||
type OptionTwo = {
|
||||
>OptionTwo : Symbol(OptionTwo, Decl(typeVariableConstraintIntersections.ts, 68, 2))
|
||||
|
||||
kind: "two";
|
||||
>kind : Symbol(kind, Decl(typeVariableConstraintIntersections.ts, 70, 18))
|
||||
|
||||
x: number;
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 71, 14))
|
||||
|
||||
y: number;
|
||||
>y : Symbol(y, Decl(typeVariableConstraintIntersections.ts, 72, 12))
|
||||
|
||||
};
|
||||
|
||||
type Options = OptionOne | OptionTwo;
|
||||
>Options : Symbol(Options, Decl(typeVariableConstraintIntersections.ts, 74, 2))
|
||||
>OptionOne : Symbol(OptionOne, Decl(typeVariableConstraintIntersections.ts, 61, 1))
|
||||
>OptionTwo : Symbol(OptionTwo, Decl(typeVariableConstraintIntersections.ts, 68, 2))
|
||||
|
||||
type OptionHandlers = {
|
||||
>OptionHandlers : Symbol(OptionHandlers, Decl(typeVariableConstraintIntersections.ts, 76, 37))
|
||||
|
||||
[K in Options['kind']]: (option: Options & { kind: K }) => string;
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 79, 3))
|
||||
>Options : Symbol(Options, Decl(typeVariableConstraintIntersections.ts, 74, 2))
|
||||
>option : Symbol(option, Decl(typeVariableConstraintIntersections.ts, 79, 27))
|
||||
>Options : Symbol(Options, Decl(typeVariableConstraintIntersections.ts, 74, 2))
|
||||
>kind : Symbol(kind, Decl(typeVariableConstraintIntersections.ts, 79, 46))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 79, 3))
|
||||
}
|
||||
|
||||
const optionHandlers: OptionHandlers = {
|
||||
>optionHandlers : Symbol(optionHandlers, Decl(typeVariableConstraintIntersections.ts, 82, 5))
|
||||
>OptionHandlers : Symbol(OptionHandlers, Decl(typeVariableConstraintIntersections.ts, 76, 37))
|
||||
|
||||
"one": option => option.s,
|
||||
>"one" : Symbol("one", Decl(typeVariableConstraintIntersections.ts, 82, 40))
|
||||
>option : Symbol(option, Decl(typeVariableConstraintIntersections.ts, 83, 8))
|
||||
>option.s : Symbol(s, Decl(typeVariableConstraintIntersections.ts, 66, 14))
|
||||
>option : Symbol(option, Decl(typeVariableConstraintIntersections.ts, 83, 8))
|
||||
>s : Symbol(s, Decl(typeVariableConstraintIntersections.ts, 66, 14))
|
||||
|
||||
"two": option => option.x + "," + option.y,
|
||||
>"two" : Symbol("two", Decl(typeVariableConstraintIntersections.ts, 83, 28))
|
||||
>option : Symbol(option, Decl(typeVariableConstraintIntersections.ts, 84, 8))
|
||||
>option.x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 71, 14))
|
||||
>option : Symbol(option, Decl(typeVariableConstraintIntersections.ts, 84, 8))
|
||||
>x : Symbol(x, Decl(typeVariableConstraintIntersections.ts, 71, 14))
|
||||
>option.y : Symbol(y, Decl(typeVariableConstraintIntersections.ts, 72, 12))
|
||||
>option : Symbol(option, Decl(typeVariableConstraintIntersections.ts, 84, 8))
|
||||
>y : Symbol(y, Decl(typeVariableConstraintIntersections.ts, 72, 12))
|
||||
|
||||
};
|
||||
|
||||
function handleOption<K extends Options['kind']>(option: Options & { kind: K }): string {
|
||||
>handleOption : Symbol(handleOption, Decl(typeVariableConstraintIntersections.ts, 85, 2))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 87, 22))
|
||||
>Options : Symbol(Options, Decl(typeVariableConstraintIntersections.ts, 74, 2))
|
||||
>option : Symbol(option, Decl(typeVariableConstraintIntersections.ts, 87, 49))
|
||||
>Options : Symbol(Options, Decl(typeVariableConstraintIntersections.ts, 74, 2))
|
||||
>kind : Symbol(kind, Decl(typeVariableConstraintIntersections.ts, 87, 68))
|
||||
>K : Symbol(K, Decl(typeVariableConstraintIntersections.ts, 87, 22))
|
||||
|
||||
const kind = option.kind;
|
||||
>kind : Symbol(kind, Decl(typeVariableConstraintIntersections.ts, 88, 7))
|
||||
>option.kind : Symbol(kind, Decl(typeVariableConstraintIntersections.ts, 65, 18), Decl(typeVariableConstraintIntersections.ts, 87, 68), Decl(typeVariableConstraintIntersections.ts, 70, 18), Decl(typeVariableConstraintIntersections.ts, 87, 68))
|
||||
>option : Symbol(option, Decl(typeVariableConstraintIntersections.ts, 87, 49))
|
||||
>kind : Symbol(kind, Decl(typeVariableConstraintIntersections.ts, 65, 18), Decl(typeVariableConstraintIntersections.ts, 87, 68), Decl(typeVariableConstraintIntersections.ts, 70, 18), Decl(typeVariableConstraintIntersections.ts, 87, 68))
|
||||
|
||||
const handler = optionHandlers[kind];
|
||||
>handler : Symbol(handler, Decl(typeVariableConstraintIntersections.ts, 89, 7))
|
||||
>optionHandlers : Symbol(optionHandlers, Decl(typeVariableConstraintIntersections.ts, 82, 5))
|
||||
>kind : Symbol(kind, Decl(typeVariableConstraintIntersections.ts, 88, 7))
|
||||
|
||||
return handler(option);
|
||||
>handler : Symbol(handler, Decl(typeVariableConstraintIntersections.ts, 89, 7))
|
||||
>option : Symbol(option, Decl(typeVariableConstraintIntersections.ts, 87, 49))
|
||||
|
||||
};
|
||||
|
||||
@ -0,0 +1,258 @@
|
||||
//// [tests/cases/compiler/typeVariableConstraintIntersections.ts] ////
|
||||
|
||||
=== typeVariableConstraintIntersections.ts ===
|
||||
type T00<K extends "a" | "b"> = K & "a";
|
||||
>T00 : T00<K>
|
||||
|
||||
type T01<K extends "a" | "b"> = K & "c";
|
||||
>T01 : never
|
||||
|
||||
type T02<K extends "a" | "b"> = K & string;
|
||||
>T02 : K
|
||||
|
||||
type T10<K extends string> = K & "a";
|
||||
>T10 : T10<K>
|
||||
|
||||
type T11<K extends string> = K & "c";
|
||||
>T11 : T11<K>
|
||||
|
||||
type T12<K extends string> = K & string;
|
||||
>T12 : K
|
||||
|
||||
type T20<K extends "a" | "b" | "c"> = K & ("a" | "b" | "c");
|
||||
>T20 : K
|
||||
|
||||
type T21<K extends "a" | "b" | "c"> = ("a" | "b" | "c") & K;
|
||||
>T21 : K
|
||||
|
||||
type T22<K extends "a" | "b" | "c"> = K & ("a" | "b");
|
||||
>T22 : T22<K>
|
||||
|
||||
type T23<K extends "a" | "b" | "c"> = ("a" | "b") & K;
|
||||
>T23 : T23<K>
|
||||
|
||||
type T30<K extends "a" | "b"> = K & ("a" | "b" | "c");
|
||||
>T30 : K
|
||||
|
||||
type T31<K extends "a" | "b"> = ("a" | "b" | "c") & K;
|
||||
>T31 : K
|
||||
|
||||
type T32<K extends "a" | "b"> = K & ("a" | "b");
|
||||
>T32 : K
|
||||
|
||||
type T33<K extends "a" | "b"> = ("a" | "b") & K;
|
||||
>T33 : K
|
||||
|
||||
type T40<K extends {}> = K & undefined;
|
||||
>T40 : never
|
||||
|
||||
type T41<K extends {}> = K & null;
|
||||
>T41 : never
|
||||
|
||||
type T42<K extends {}> = K & object;
|
||||
>T42 : T42<K>
|
||||
|
||||
type T43<K extends {}> = K & {};
|
||||
>T43 : K
|
||||
|
||||
type T50<K extends "a" | 0> = K & "a";
|
||||
>T50 : T50<K>
|
||||
|
||||
type T51<K extends "a" | 0> = K & "b";
|
||||
>T51 : never
|
||||
|
||||
type T52<K extends "a" | 0> = K & string;
|
||||
>T52 : T52<K>
|
||||
|
||||
type T53<K extends "a" | 0> = K & 0;
|
||||
>T53 : T53<K>
|
||||
|
||||
type T54<K extends "a" | 0> = K & 1;
|
||||
>T54 : never
|
||||
|
||||
type T55<K extends "a" | 0> = K & number;
|
||||
>T55 : T55<K>
|
||||
|
||||
type T60<T extends "a" | "b", U extends T> = U & "a";
|
||||
>T60 : T60<T, U>
|
||||
|
||||
type T61<T extends "a" | "b", U extends T> = U & ("a" | "b");
|
||||
>T61 : U
|
||||
|
||||
type T62<T extends "a" | "b", U extends T> = U & ("a" | "b" | "c");
|
||||
>T62 : U
|
||||
|
||||
type T63<T extends "a" | "b", U extends T> = U & string;
|
||||
>T63 : U
|
||||
|
||||
type T70<T extends "a" | "b", U extends T | "c"> = U & "a";
|
||||
>T70 : T70<T, U>
|
||||
|
||||
type T71<T extends "a" | "b", U extends T | "c"> = U & ("a" | "b");
|
||||
>T71 : T71<T, U>
|
||||
|
||||
type T72<T extends "a" | "b", U extends T | "c"> = U & ("a" | "b" | "c");
|
||||
>T72 : U
|
||||
|
||||
type T73<T extends "a" | "b", U extends T | "c"> = U & string;
|
||||
>T73 : U
|
||||
|
||||
declare function isA(x: any): x is "a";
|
||||
>isA : (x: any) => x is "a"
|
||||
>x : any
|
||||
|
||||
declare function isB(x: any): x is "b";
|
||||
>isB : (x: any) => x is "b"
|
||||
>x : any
|
||||
|
||||
declare function isC(x: any): x is "c";
|
||||
>isC : (x: any) => x is "c"
|
||||
>x : any
|
||||
|
||||
function foo<K extends "a" | "b">(x: K) {
|
||||
>foo : <K extends "a" | "b">(x: K) => void
|
||||
>x : K
|
||||
|
||||
if (isA(x)) {
|
||||
>isA(x) : boolean
|
||||
>isA : (x: any) => x is "a"
|
||||
>x : "a" | "b"
|
||||
|
||||
x; // K & "a"
|
||||
>x : K & "a"
|
||||
}
|
||||
if (isB(x)) {
|
||||
>isB(x) : boolean
|
||||
>isB : (x: any) => x is "b"
|
||||
>x : "a" | "b"
|
||||
|
||||
x; // K & "b"
|
||||
>x : K & "b"
|
||||
}
|
||||
if (isC(x)) {
|
||||
>isC(x) : boolean
|
||||
>isC : (x: any) => x is "c"
|
||||
>x : "a" | "b"
|
||||
|
||||
x; // never
|
||||
>x : never
|
||||
}
|
||||
if (isA(x) || isB(x)) {
|
||||
>isA(x) || isB(x) : boolean
|
||||
>isA(x) : boolean
|
||||
>isA : (x: any) => x is "a"
|
||||
>x : "a" | "b"
|
||||
>isB(x) : boolean
|
||||
>isB : (x: any) => x is "b"
|
||||
>x : "b"
|
||||
|
||||
x; // K
|
||||
>x : K
|
||||
}
|
||||
if (!(isA(x) || isB(x))) {
|
||||
>!(isA(x) || isB(x)) : boolean
|
||||
>(isA(x) || isB(x)) : boolean
|
||||
>isA(x) || isB(x) : boolean
|
||||
>isA(x) : boolean
|
||||
>isA : (x: any) => x is "a"
|
||||
>x : "a" | "b"
|
||||
>isB(x) : boolean
|
||||
>isB : (x: any) => x is "b"
|
||||
>x : "b"
|
||||
|
||||
return;
|
||||
}
|
||||
x; // K
|
||||
>x : K
|
||||
}
|
||||
|
||||
// Example from #30581
|
||||
|
||||
type OptionOne = {
|
||||
>OptionOne : { kind: "one"; s: string; }
|
||||
|
||||
kind: "one";
|
||||
>kind : "one"
|
||||
|
||||
s: string;
|
||||
>s : string
|
||||
|
||||
};
|
||||
|
||||
type OptionTwo = {
|
||||
>OptionTwo : { kind: "two"; x: number; y: number; }
|
||||
|
||||
kind: "two";
|
||||
>kind : "two"
|
||||
|
||||
x: number;
|
||||
>x : number
|
||||
|
||||
y: number;
|
||||
>y : number
|
||||
|
||||
};
|
||||
|
||||
type Options = OptionOne | OptionTwo;
|
||||
>Options : OptionOne | OptionTwo
|
||||
|
||||
type OptionHandlers = {
|
||||
>OptionHandlers : { one: (option: OptionOne & { kind: "one"; }) => string; two: (option: OptionTwo & { kind: "two"; }) => string; }
|
||||
|
||||
[K in Options['kind']]: (option: Options & { kind: K }) => string;
|
||||
>option : Options & { kind: K; }
|
||||
>kind : K
|
||||
}
|
||||
|
||||
const optionHandlers: OptionHandlers = {
|
||||
>optionHandlers : OptionHandlers
|
||||
>{ "one": option => option.s, "two": option => option.x + "," + option.y,} : { one: (option: OptionOne & { kind: "one"; }) => string; two: (option: OptionTwo & { kind: "two"; }) => string; }
|
||||
|
||||
"one": option => option.s,
|
||||
>"one" : (option: OptionOne & { kind: "one"; }) => string
|
||||
>option => option.s : (option: OptionOne & { kind: "one"; }) => string
|
||||
>option : OptionOne & { kind: "one"; }
|
||||
>option.s : string
|
||||
>option : OptionOne & { kind: "one"; }
|
||||
>s : string
|
||||
|
||||
"two": option => option.x + "," + option.y,
|
||||
>"two" : (option: OptionTwo & { kind: "two"; }) => string
|
||||
>option => option.x + "," + option.y : (option: OptionTwo & { kind: "two"; }) => string
|
||||
>option : OptionTwo & { kind: "two"; }
|
||||
>option.x + "," + option.y : string
|
||||
>option.x + "," : string
|
||||
>option.x : number
|
||||
>option : OptionTwo & { kind: "two"; }
|
||||
>x : number
|
||||
>"," : ","
|
||||
>option.y : number
|
||||
>option : OptionTwo & { kind: "two"; }
|
||||
>y : number
|
||||
|
||||
};
|
||||
|
||||
function handleOption<K extends Options['kind']>(option: Options & { kind: K }): string {
|
||||
>handleOption : <K extends "one" | "two">(option: Options & { kind: K; }) => string
|
||||
>option : Options & { kind: K; }
|
||||
>kind : K
|
||||
|
||||
const kind = option.kind;
|
||||
>kind : K
|
||||
>option.kind : K
|
||||
>option : Options & { kind: K; }
|
||||
>kind : K
|
||||
|
||||
const handler = optionHandlers[kind];
|
||||
>handler : OptionHandlers[K]
|
||||
>optionHandlers[kind] : OptionHandlers[K]
|
||||
>optionHandlers : OptionHandlers
|
||||
>kind : K
|
||||
|
||||
return handler(option);
|
||||
>handler(option) : string
|
||||
>handler : OptionHandlers[K]
|
||||
>option : Options & { kind: K; }
|
||||
|
||||
};
|
||||
|
||||
@ -3,9 +3,11 @@ unknownControlFlow.ts(283,5): error TS2536: Type 'keyof (T & {})' cannot be used
|
||||
unknownControlFlow.ts(290,11): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.
|
||||
unknownControlFlow.ts(291,5): error TS2345: Argument of type 'null' is not assignable to parameter of type 'never'.
|
||||
unknownControlFlow.ts(293,5): error TS2345: Argument of type 'null' is not assignable to parameter of type 'never'.
|
||||
unknownControlFlow.ts(323,9): error TS2367: This comparison appears to be unintentional because the types 'T' and 'number' have no overlap.
|
||||
unknownControlFlow.ts(341,9): error TS2367: This comparison appears to be unintentional because the types 'T' and 'number' have no overlap.
|
||||
|
||||
|
||||
==== unknownControlFlow.ts (5 errors) ====
|
||||
==== unknownControlFlow.ts (7 errors) ====
|
||||
type T01 = {} & string; // {} & string
|
||||
type T02 = {} & 'a'; // 'a'
|
||||
type T03 = {} & object; // object
|
||||
@ -339,6 +341,8 @@ unknownControlFlow.ts(293,5): error TS2345: Argument of type 'null' is not assig
|
||||
|
||||
function fx2<T extends {}>(value: T & ({} | null)) {
|
||||
if (value === 42) {
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2367: This comparison appears to be unintentional because the types 'T' and 'number' have no overlap.
|
||||
value; // T & {}
|
||||
}
|
||||
else {
|
||||
@ -357,6 +361,8 @@ unknownControlFlow.ts(293,5): error TS2345: Argument of type 'null' is not assig
|
||||
|
||||
function fx4<T extends {} | null>(value: T & ({} | null)) {
|
||||
if (value === 42) {
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2367: This comparison appears to be unintentional because the types 'T' and 'number' have no overlap.
|
||||
value; // T & {}
|
||||
}
|
||||
else {
|
||||
|
||||
@ -819,47 +819,29 @@ function fx1<T extends unknown>(value: T & ({} | null)) {
|
||||
|
||||
function fx2<T extends {}>(value: T & ({} | null)) {
|
||||
>fx2 : <T extends {}>(value: T & ({} | null)) => void
|
||||
>value : T & ({} | null)
|
||||
>value : T
|
||||
|
||||
if (value === 42) {
|
||||
>value === 42 : boolean
|
||||
>value : T & ({} | null)
|
||||
>value : T
|
||||
>42 : 42
|
||||
|
||||
value; // T & {}
|
||||
>value : T & ({} | null)
|
||||
>value : never
|
||||
}
|
||||
else {
|
||||
value; // T & ({} | null)
|
||||
>value : T & ({} | null)
|
||||
>value : T
|
||||
}
|
||||
}
|
||||
|
||||
function fx3<T extends {} | undefined>(value: T & ({} | null)) {
|
||||
>fx3 : <T extends {} | undefined>(value: T & ({} | null)) => void
|
||||
>value : T & ({} | null)
|
||||
>value : T & {}
|
||||
|
||||
if (value === 42) {
|
||||
>value === 42 : boolean
|
||||
>value : T & ({} | null)
|
||||
>42 : 42
|
||||
|
||||
value; // T & {}
|
||||
>value : T & ({} | null)
|
||||
}
|
||||
else {
|
||||
value; // T & ({} | null)
|
||||
>value : T & ({} | null)
|
||||
}
|
||||
}
|
||||
|
||||
function fx4<T extends {} | null>(value: T & ({} | null)) {
|
||||
>fx4 : <T extends {} | null>(value: T & ({} | null)) => void
|
||||
>value : T & ({} | null)
|
||||
|
||||
if (value === 42) {
|
||||
>value === 42 : boolean
|
||||
>value : T & ({} | null)
|
||||
>value : T & {}
|
||||
>42 : 42
|
||||
|
||||
value; // T & {}
|
||||
@ -867,7 +849,25 @@ function fx4<T extends {} | null>(value: T & ({} | null)) {
|
||||
}
|
||||
else {
|
||||
value; // T & ({} | null)
|
||||
>value : T & ({} | null)
|
||||
>value : T & {}
|
||||
}
|
||||
}
|
||||
|
||||
function fx4<T extends {} | null>(value: T & ({} | null)) {
|
||||
>fx4 : <T extends {} | null>(value: T & ({} | null)) => void
|
||||
>value : T
|
||||
|
||||
if (value === 42) {
|
||||
>value === 42 : boolean
|
||||
>value : T
|
||||
>42 : 42
|
||||
|
||||
value; // T & {}
|
||||
>value : never
|
||||
}
|
||||
else {
|
||||
value; // T & ({} | null)
|
||||
>value : T
|
||||
}
|
||||
}
|
||||
|
||||
@ -1036,12 +1036,12 @@ type AB = "A" | "B";
|
||||
|
||||
function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
|
||||
>x : <T_AB extends AB>(x: T_AB & undefined, y: any) => void
|
||||
>x : T_AB & undefined
|
||||
>x : never
|
||||
>y : any
|
||||
|
||||
let r2: never = y as T_AB & undefined;
|
||||
>r2 : never
|
||||
>y as T_AB & undefined : T_AB & undefined
|
||||
>y as T_AB & undefined : never
|
||||
>y : any
|
||||
}
|
||||
|
||||
|
||||
95
tests/cases/compiler/typeVariableConstraintIntersections.ts
Normal file
95
tests/cases/compiler/typeVariableConstraintIntersections.ts
Normal file
@ -0,0 +1,95 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
type T00<K extends "a" | "b"> = K & "a";
|
||||
type T01<K extends "a" | "b"> = K & "c";
|
||||
type T02<K extends "a" | "b"> = K & string;
|
||||
|
||||
type T10<K extends string> = K & "a";
|
||||
type T11<K extends string> = K & "c";
|
||||
type T12<K extends string> = K & string;
|
||||
|
||||
type T20<K extends "a" | "b" | "c"> = K & ("a" | "b" | "c");
|
||||
type T21<K extends "a" | "b" | "c"> = ("a" | "b" | "c") & K;
|
||||
type T22<K extends "a" | "b" | "c"> = K & ("a" | "b");
|
||||
type T23<K extends "a" | "b" | "c"> = ("a" | "b") & K;
|
||||
|
||||
type T30<K extends "a" | "b"> = K & ("a" | "b" | "c");
|
||||
type T31<K extends "a" | "b"> = ("a" | "b" | "c") & K;
|
||||
type T32<K extends "a" | "b"> = K & ("a" | "b");
|
||||
type T33<K extends "a" | "b"> = ("a" | "b") & K;
|
||||
|
||||
type T40<K extends {}> = K & undefined;
|
||||
type T41<K extends {}> = K & null;
|
||||
type T42<K extends {}> = K & object;
|
||||
type T43<K extends {}> = K & {};
|
||||
|
||||
type T50<K extends "a" | 0> = K & "a";
|
||||
type T51<K extends "a" | 0> = K & "b";
|
||||
type T52<K extends "a" | 0> = K & string;
|
||||
type T53<K extends "a" | 0> = K & 0;
|
||||
type T54<K extends "a" | 0> = K & 1;
|
||||
type T55<K extends "a" | 0> = K & number;
|
||||
|
||||
type T60<T extends "a" | "b", U extends T> = U & "a";
|
||||
type T61<T extends "a" | "b", U extends T> = U & ("a" | "b");
|
||||
type T62<T extends "a" | "b", U extends T> = U & ("a" | "b" | "c");
|
||||
type T63<T extends "a" | "b", U extends T> = U & string;
|
||||
|
||||
type T70<T extends "a" | "b", U extends T | "c"> = U & "a";
|
||||
type T71<T extends "a" | "b", U extends T | "c"> = U & ("a" | "b");
|
||||
type T72<T extends "a" | "b", U extends T | "c"> = U & ("a" | "b" | "c");
|
||||
type T73<T extends "a" | "b", U extends T | "c"> = U & string;
|
||||
|
||||
declare function isA(x: any): x is "a";
|
||||
declare function isB(x: any): x is "b";
|
||||
declare function isC(x: any): x is "c";
|
||||
|
||||
function foo<K extends "a" | "b">(x: K) {
|
||||
if (isA(x)) {
|
||||
x; // K & "a"
|
||||
}
|
||||
if (isB(x)) {
|
||||
x; // K & "b"
|
||||
}
|
||||
if (isC(x)) {
|
||||
x; // never
|
||||
}
|
||||
if (isA(x) || isB(x)) {
|
||||
x; // K
|
||||
}
|
||||
if (!(isA(x) || isB(x))) {
|
||||
return;
|
||||
}
|
||||
x; // K
|
||||
}
|
||||
|
||||
// Example from #30581
|
||||
|
||||
type OptionOne = {
|
||||
kind: "one";
|
||||
s: string;
|
||||
};
|
||||
|
||||
type OptionTwo = {
|
||||
kind: "two";
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
type Options = OptionOne | OptionTwo;
|
||||
|
||||
type OptionHandlers = {
|
||||
[K in Options['kind']]: (option: Options & { kind: K }) => string;
|
||||
}
|
||||
|
||||
const optionHandlers: OptionHandlers = {
|
||||
"one": option => option.s,
|
||||
"two": option => option.x + "," + option.y,
|
||||
};
|
||||
|
||||
function handleOption<K extends Options['kind']>(option: Options & { kind: K }): string {
|
||||
const kind = option.kind;
|
||||
const handler = optionHandlers[kind];
|
||||
return handler(option);
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user