mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 01:49:41 -05:00
Defer conditional types with parenthesized multi-element tuple types in extends clause (#56271)
Co-authored-by: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
b436976bd3
commit
41ec497211
@@ -967,6 +967,7 @@ import {
|
||||
skipParentheses,
|
||||
skipTrivia,
|
||||
skipTypeChecking,
|
||||
skipTypeParentheses,
|
||||
some,
|
||||
SourceFile,
|
||||
SpreadAssignment,
|
||||
@@ -18490,7 +18491,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return constraint && (isGenericObjectType(constraint) || isGenericIndexType(constraint)) ? cloneTypeParameter(p) : p;
|
||||
}
|
||||
|
||||
function isSimpleTupleType(node: TypeNode) {
|
||||
function isSimpleTupleType(node: TypeNode): boolean {
|
||||
return isTupleTypeNode(node) && length(node.elements) > 0 &&
|
||||
!some(node.elements, e => isOptionalTypeNode(e) || isRestTypeNode(e) || isNamedTupleMember(e) && !!(e.questionToken || e.dotDotDotToken));
|
||||
}
|
||||
@@ -18521,11 +18522,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (checkType === wildcardType || extendsType === wildcardType) {
|
||||
return wildcardType;
|
||||
}
|
||||
const checkTypeNode = skipTypeParentheses(root.node.checkType);
|
||||
const extendsTypeNode = skipTypeParentheses(root.node.extendsType);
|
||||
// When the check and extends types are simple tuple types of the same arity, we defer resolution of the
|
||||
// conditional type when any tuple elements are generic. This is such that non-distributable conditional
|
||||
// types can be written `[X] extends [Y] ? ...` and be deferred similarly to `X extends Y ? ...`.
|
||||
const checkTuples = isSimpleTupleType(root.node.checkType) && isSimpleTupleType(root.node.extendsType) &&
|
||||
length((root.node.checkType as TupleTypeNode).elements) === length((root.node.extendsType as TupleTypeNode).elements);
|
||||
const checkTuples = isSimpleTupleType(checkTypeNode) && isSimpleTupleType(extendsTypeNode) &&
|
||||
length((checkTypeNode as TupleTypeNode).elements) === length((extendsTypeNode as TupleTypeNode).elements);
|
||||
const checkTypeDeferred = isDeferredType(checkType, checkTuples);
|
||||
let combinedMapper: TypeMapper | undefined;
|
||||
if (root.inferTypeParameters) {
|
||||
|
||||
117
tests/baselines/reference/deferredConditionalTypes2.symbols
Normal file
117
tests/baselines/reference/deferredConditionalTypes2.symbols
Normal file
@@ -0,0 +1,117 @@
|
||||
//// [tests/cases/compiler/deferredConditionalTypes2.ts] ////
|
||||
|
||||
=== deferredConditionalTypes2.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/56270
|
||||
|
||||
type PositiveInfinity = 1e999;
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
|
||||
type NegativeInfinity = -1e999;
|
||||
>NegativeInfinity : Symbol(NegativeInfinity, Decl(deferredConditionalTypes2.ts, 2, 30))
|
||||
|
||||
export type IsEqual<A, B> = (<G>() => G extends A ? 1 : 2) extends <
|
||||
>IsEqual : Symbol(IsEqual, Decl(deferredConditionalTypes2.ts, 3, 31))
|
||||
>A : Symbol(A, Decl(deferredConditionalTypes2.ts, 5, 20))
|
||||
>B : Symbol(B, Decl(deferredConditionalTypes2.ts, 5, 22))
|
||||
>G : Symbol(G, Decl(deferredConditionalTypes2.ts, 5, 30))
|
||||
>G : Symbol(G, Decl(deferredConditionalTypes2.ts, 5, 30))
|
||||
>A : Symbol(A, Decl(deferredConditionalTypes2.ts, 5, 20))
|
||||
|
||||
G,
|
||||
>G : Symbol(G, Decl(deferredConditionalTypes2.ts, 5, 68))
|
||||
|
||||
>() => G extends B ? 1 : 2
|
||||
>G : Symbol(G, Decl(deferredConditionalTypes2.ts, 5, 68))
|
||||
>B : Symbol(B, Decl(deferredConditionalTypes2.ts, 5, 22))
|
||||
|
||||
? true
|
||||
: false;
|
||||
|
||||
export type Add<A extends number, B extends number> = [
|
||||
>Add : Symbol(Add, Decl(deferredConditionalTypes2.ts, 9, 10))
|
||||
>A : Symbol(A, Decl(deferredConditionalTypes2.ts, 11, 16))
|
||||
>B : Symbol(B, Decl(deferredConditionalTypes2.ts, 11, 33))
|
||||
|
||||
IsEqual<A, PositiveInfinity>,
|
||||
>IsEqual : Symbol(IsEqual, Decl(deferredConditionalTypes2.ts, 3, 31))
|
||||
>A : Symbol(A, Decl(deferredConditionalTypes2.ts, 11, 16))
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
|
||||
IsEqual<A, NegativeInfinity>,
|
||||
>IsEqual : Symbol(IsEqual, Decl(deferredConditionalTypes2.ts, 3, 31))
|
||||
>A : Symbol(A, Decl(deferredConditionalTypes2.ts, 11, 16))
|
||||
>NegativeInfinity : Symbol(NegativeInfinity, Decl(deferredConditionalTypes2.ts, 2, 30))
|
||||
|
||||
IsEqual<B, PositiveInfinity>,
|
||||
>IsEqual : Symbol(IsEqual, Decl(deferredConditionalTypes2.ts, 3, 31))
|
||||
>B : Symbol(B, Decl(deferredConditionalTypes2.ts, 11, 33))
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
|
||||
IsEqual<B, NegativeInfinity>,
|
||||
>IsEqual : Symbol(IsEqual, Decl(deferredConditionalTypes2.ts, 3, 31))
|
||||
>B : Symbol(B, Decl(deferredConditionalTypes2.ts, 11, 33))
|
||||
>NegativeInfinity : Symbol(NegativeInfinity, Decl(deferredConditionalTypes2.ts, 2, 30))
|
||||
|
||||
] extends infer R extends [boolean, boolean, boolean, boolean]
|
||||
>R : Symbol(R, Decl(deferredConditionalTypes2.ts, 16, 15))
|
||||
|
||||
? [true, false] extends ([R[0], R[3]])
|
||||
>R : Symbol(R, Decl(deferredConditionalTypes2.ts, 16, 15))
|
||||
>R : Symbol(R, Decl(deferredConditionalTypes2.ts, 16, 15))
|
||||
|
||||
? PositiveInfinity
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
|
||||
: "failed"
|
||||
: never;
|
||||
|
||||
export type AddWithoutParentheses<A extends number, B extends number> = [
|
||||
>AddWithoutParentheses : Symbol(AddWithoutParentheses, Decl(deferredConditionalTypes2.ts, 20, 10))
|
||||
>A : Symbol(A, Decl(deferredConditionalTypes2.ts, 22, 34))
|
||||
>B : Symbol(B, Decl(deferredConditionalTypes2.ts, 22, 51))
|
||||
|
||||
IsEqual<A, PositiveInfinity>,
|
||||
>IsEqual : Symbol(IsEqual, Decl(deferredConditionalTypes2.ts, 3, 31))
|
||||
>A : Symbol(A, Decl(deferredConditionalTypes2.ts, 22, 34))
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
|
||||
IsEqual<A, NegativeInfinity>,
|
||||
>IsEqual : Symbol(IsEqual, Decl(deferredConditionalTypes2.ts, 3, 31))
|
||||
>A : Symbol(A, Decl(deferredConditionalTypes2.ts, 22, 34))
|
||||
>NegativeInfinity : Symbol(NegativeInfinity, Decl(deferredConditionalTypes2.ts, 2, 30))
|
||||
|
||||
IsEqual<B, PositiveInfinity>,
|
||||
>IsEqual : Symbol(IsEqual, Decl(deferredConditionalTypes2.ts, 3, 31))
|
||||
>B : Symbol(B, Decl(deferredConditionalTypes2.ts, 22, 51))
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
|
||||
IsEqual<B, NegativeInfinity>,
|
||||
>IsEqual : Symbol(IsEqual, Decl(deferredConditionalTypes2.ts, 3, 31))
|
||||
>B : Symbol(B, Decl(deferredConditionalTypes2.ts, 22, 51))
|
||||
>NegativeInfinity : Symbol(NegativeInfinity, Decl(deferredConditionalTypes2.ts, 2, 30))
|
||||
|
||||
] extends infer R extends [boolean, boolean, boolean, boolean]
|
||||
>R : Symbol(R, Decl(deferredConditionalTypes2.ts, 27, 15))
|
||||
|
||||
? [true, false] extends [R[0], R[3]]
|
||||
>R : Symbol(R, Decl(deferredConditionalTypes2.ts, 27, 15))
|
||||
>R : Symbol(R, Decl(deferredConditionalTypes2.ts, 27, 15))
|
||||
|
||||
? PositiveInfinity
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
|
||||
: "failed"
|
||||
: never;
|
||||
|
||||
type AddTest0 = Add<PositiveInfinity, PositiveInfinity>;
|
||||
>AddTest0 : Symbol(AddTest0, Decl(deferredConditionalTypes2.ts, 31, 10))
|
||||
>Add : Symbol(Add, Decl(deferredConditionalTypes2.ts, 9, 10))
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
|
||||
type AddTest1 = AddWithoutParentheses<PositiveInfinity, PositiveInfinity>;
|
||||
>AddTest1 : Symbol(AddTest1, Decl(deferredConditionalTypes2.ts, 33, 56))
|
||||
>AddWithoutParentheses : Symbol(AddWithoutParentheses, Decl(deferredConditionalTypes2.ts, 20, 10))
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
>PositiveInfinity : Symbol(PositiveInfinity, Decl(deferredConditionalTypes2.ts, 0, 0))
|
||||
|
||||
62
tests/baselines/reference/deferredConditionalTypes2.types
Normal file
62
tests/baselines/reference/deferredConditionalTypes2.types
Normal file
@@ -0,0 +1,62 @@
|
||||
//// [tests/cases/compiler/deferredConditionalTypes2.ts] ////
|
||||
|
||||
=== deferredConditionalTypes2.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/56270
|
||||
|
||||
type PositiveInfinity = 1e999;
|
||||
>PositiveInfinity : Infinity
|
||||
|
||||
type NegativeInfinity = -1e999;
|
||||
>NegativeInfinity : -Infinity
|
||||
>-1e999 : -Infinity
|
||||
>1e999 : Infinity
|
||||
|
||||
export type IsEqual<A, B> = (<G>() => G extends A ? 1 : 2) extends <
|
||||
>IsEqual : IsEqual<A, B>
|
||||
|
||||
G,
|
||||
>() => G extends B ? 1 : 2
|
||||
? true
|
||||
>true : true
|
||||
|
||||
: false;
|
||||
>false : false
|
||||
|
||||
export type Add<A extends number, B extends number> = [
|
||||
>Add : [true, false] extends [IsEqual<A, Infinity>, IsEqual<B, -Infinity>] ? Infinity : "failed"
|
||||
|
||||
IsEqual<A, PositiveInfinity>,
|
||||
IsEqual<A, NegativeInfinity>,
|
||||
IsEqual<B, PositiveInfinity>,
|
||||
IsEqual<B, NegativeInfinity>,
|
||||
] extends infer R extends [boolean, boolean, boolean, boolean]
|
||||
? [true, false] extends ([R[0], R[3]])
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
? PositiveInfinity
|
||||
: "failed"
|
||||
: never;
|
||||
|
||||
export type AddWithoutParentheses<A extends number, B extends number> = [
|
||||
>AddWithoutParentheses : [true, false] extends [IsEqual<A, Infinity>, IsEqual<B, -Infinity>] ? Infinity : "failed"
|
||||
|
||||
IsEqual<A, PositiveInfinity>,
|
||||
IsEqual<A, NegativeInfinity>,
|
||||
IsEqual<B, PositiveInfinity>,
|
||||
IsEqual<B, NegativeInfinity>,
|
||||
] extends infer R extends [boolean, boolean, boolean, boolean]
|
||||
? [true, false] extends [R[0], R[3]]
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
? PositiveInfinity
|
||||
: "failed"
|
||||
: never;
|
||||
|
||||
type AddTest0 = Add<PositiveInfinity, PositiveInfinity>;
|
||||
>AddTest0 : Infinity
|
||||
|
||||
type AddTest1 = AddWithoutParentheses<PositiveInfinity, PositiveInfinity>;
|
||||
>AddTest1 : Infinity
|
||||
|
||||
38
tests/cases/compiler/deferredConditionalTypes2.ts
Normal file
38
tests/cases/compiler/deferredConditionalTypes2.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/56270
|
||||
|
||||
type PositiveInfinity = 1e999;
|
||||
type NegativeInfinity = -1e999;
|
||||
|
||||
export type IsEqual<A, B> = (<G>() => G extends A ? 1 : 2) extends <
|
||||
G,
|
||||
>() => G extends B ? 1 : 2
|
||||
? true
|
||||
: false;
|
||||
|
||||
export type Add<A extends number, B extends number> = [
|
||||
IsEqual<A, PositiveInfinity>,
|
||||
IsEqual<A, NegativeInfinity>,
|
||||
IsEqual<B, PositiveInfinity>,
|
||||
IsEqual<B, NegativeInfinity>,
|
||||
] extends infer R extends [boolean, boolean, boolean, boolean]
|
||||
? [true, false] extends ([R[0], R[3]])
|
||||
? PositiveInfinity
|
||||
: "failed"
|
||||
: never;
|
||||
|
||||
export type AddWithoutParentheses<A extends number, B extends number> = [
|
||||
IsEqual<A, PositiveInfinity>,
|
||||
IsEqual<A, NegativeInfinity>,
|
||||
IsEqual<B, PositiveInfinity>,
|
||||
IsEqual<B, NegativeInfinity>,
|
||||
] extends infer R extends [boolean, boolean, boolean, boolean]
|
||||
? [true, false] extends [R[0], R[3]]
|
||||
? PositiveInfinity
|
||||
: "failed"
|
||||
: never;
|
||||
|
||||
type AddTest0 = Add<PositiveInfinity, PositiveInfinity>;
|
||||
type AddTest1 = AddWithoutParentheses<PositiveInfinity, PositiveInfinity>;
|
||||
Reference in New Issue
Block a user