No this type arguments in base constraints (#54536)

This commit is contained in:
Anders Hejlsberg 2023-06-12 19:07:44 -07:00 committed by GitHub
parent e60cf121ae
commit 89cbea8e16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 192 additions and 27 deletions

View File

@ -12502,10 +12502,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (getObjectFlags(type) & ObjectFlags.Reference) {
const target = (type as TypeReference).target;
const typeArguments = getTypeArguments(type as TypeReference);
if (length(target.typeParameters) === length(typeArguments)) {
const ref = createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!]));
return needApparentType ? getApparentType(ref) : ref;
}
return length(target.typeParameters) === length(typeArguments) ? createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])) : type;
}
else if (type.flags & TypeFlags.Intersection) {
const types = sameMap((type as IntersectionType).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType));
@ -12514,10 +12511,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return needApparentType ? getApparentType(type) : type;
}
function getThisArgument(type: Type) {
return getObjectFlags(type) & ObjectFlags.Reference && length(getTypeArguments(type as TypeReference)) > getTypeReferenceArity(type as TypeReference) ? last(getTypeArguments(type as TypeReference)) : type;
}
function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: readonly TypeParameter[], typeArguments: readonly Type[]) {
let mapper: TypeMapper | undefined;
let members: SymbolTable;
@ -13699,7 +13692,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return type.resolvedBaseConstraint;
}
const stack: object[] = [];
return type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), getThisArgument(type));
return type.resolvedBaseConstraint = getImmediateBaseConstraint(type);
function getImmediateBaseConstraint(t: Type): Type {
if (!t.immediateBaseConstraint) {
@ -13805,8 +13798,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// We substitute constraints for variadic elements only when the constraints are array types or
// non-variadic tuple types as we want to avoid further (possibly unbounded) recursion.
const newElements = map(getElementTypes(t), (v, i) => {
const constraint = t.target.elementFlags[i] & ElementFlags.Variadic && getBaseConstraint(v) || v;
return constraint && everyType(constraint, c => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint : v;
const constraint = v.flags & TypeFlags.TypeParameter && t.target.elementFlags[i] & ElementFlags.Variadic && getBaseConstraint(v) || v;
return constraint !== v && everyType(constraint, c => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint : v;
});
return createTupleType(newElements, t.target.elementFlags, t.target.readonly, t.target.labeledElementDeclarations);
}
@ -13814,8 +13807,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
function getApparentTypeOfIntersectionType(type: IntersectionType) {
return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type, /*needApparentType*/ true));
function getApparentTypeOfIntersectionType(type: IntersectionType, thisArgument: Type) {
return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, thisArgument, /*needApparentType*/ true));
}
function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined {
@ -13893,9 +13886,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* type itself.
*/
function getApparentType(type: Type): Type {
const t = !(type.flags & TypeFlags.Instantiable) ? type : getBaseConstraintOfType(type) || unknownType;
return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) :
t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType) :
const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || unknownType : type;
const objectFlags = getObjectFlags(t);
return objectFlags & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) :
objectFlags & ObjectFlags.Reference && t !== type ? getTypeWithThisArgument(t, type) :
t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType, type) :
t.flags & TypeFlags.StringLike ? globalStringType :
t.flags & TypeFlags.NumberLike ? globalNumberType :
t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType() :
@ -21623,9 +21618,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
const c = target as ConditionalType;
// We check for a relationship to a conditional type target only when the conditional type has no
// 'infer' positions and is not distributive or is distributive but doesn't reference the check type
// parameter in either of the result types.
if (!c.root.inferTypeParameters && !isDistributionDependent(c.root)) {
// 'infer' positions, is not distributive or is distributive but doesn't reference the check type
// parameter in either of the result types, and the source isn't an instantiation of the same
// conditional type (as happens when computing variance).
if (!c.root.inferTypeParameters && !isDistributionDependent(c.root) && !(source.flags & TypeFlags.Conditional && (source as ConditionalType).root === c.root)) {
// Check if the conditional is always true or always false but still deferred for distribution purposes.
const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(c.checkType), getPermissiveInstantiation(c.extendsType));
const skipFalse = !skipTrue && isTypeAssignableTo(getRestrictiveInstantiation(c.checkType), getRestrictiveInstantiation(c.extendsType));

View File

@ -1,15 +1,15 @@
immutable.ts(341,22): error TS2430: Interface 'Keyed<K, V>' incorrectly extends interface 'Collection<K, V>'.
The types returned by 'toSeq()' are incompatible between these types.
Type 'Keyed<K, V>' is not assignable to type 'this'.
'this' could be instantiated with an arbitrary type which could be unrelated to 'Keyed<K, V>'.
'Keyed<K, V>' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Keyed<K, V>'.
immutable.ts(359,22): error TS2430: Interface 'Indexed<T>' incorrectly extends interface 'Collection<number, T>'.
The types returned by 'toSeq()' are incompatible between these types.
Type 'Indexed<T>' is not assignable to type 'this'.
'this' could be instantiated with an arbitrary type which could be unrelated to 'Indexed<T>'.
'Indexed<T>' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Indexed<T>'.
immutable.ts(391,22): error TS2430: Interface 'Set<T>' incorrectly extends interface 'Collection<never, T>'.
The types returned by 'toSeq()' are incompatible between these types.
Type 'Set<T>' is not assignable to type 'this'.
'this' could be instantiated with an arbitrary type which could be unrelated to 'Set<T>'.
'Set<T>' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Set<T>'.
==== complex.ts (0 errors) ====
@ -379,7 +379,7 @@ immutable.ts(391,22): error TS2430: Interface 'Set<T>' incorrectly extends inter
!!! error TS2430: Interface 'Keyed<K, V>' incorrectly extends interface 'Collection<K, V>'.
!!! error TS2430: The types returned by 'toSeq()' are incompatible between these types.
!!! error TS2430: Type 'Keyed<K, V>' is not assignable to type 'this'.
!!! error TS2430: 'this' could be instantiated with an arbitrary type which could be unrelated to 'Keyed<K, V>'.
!!! error TS2430: 'Keyed<K, V>' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Keyed<K, V>'.
toJS(): Object;
toJSON(): { [key: string]: V };
toSeq(): Seq.Keyed<K, V>;
@ -402,7 +402,7 @@ immutable.ts(391,22): error TS2430: Interface 'Set<T>' incorrectly extends inter
!!! error TS2430: Interface 'Indexed<T>' incorrectly extends interface 'Collection<number, T>'.
!!! error TS2430: The types returned by 'toSeq()' are incompatible between these types.
!!! error TS2430: Type 'Indexed<T>' is not assignable to type 'this'.
!!! error TS2430: 'this' could be instantiated with an arbitrary type which could be unrelated to 'Indexed<T>'.
!!! error TS2430: 'Indexed<T>' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Indexed<T>'.
toJS(): Array<any>;
toJSON(): Array<T>;
// Reading values
@ -439,7 +439,7 @@ immutable.ts(391,22): error TS2430: Interface 'Set<T>' incorrectly extends inter
!!! error TS2430: Interface 'Set<T>' incorrectly extends interface 'Collection<never, T>'.
!!! error TS2430: The types returned by 'toSeq()' are incompatible between these types.
!!! error TS2430: Type 'Set<T>' is not assignable to type 'this'.
!!! error TS2430: 'this' could be instantiated with an arbitrary type which could be unrelated to 'Set<T>'.
!!! error TS2430: 'Set<T>' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Set<T>'.
toJS(): Array<any>;
toJSON(): Array<T>;
toSeq(): Seq.Set<T>;

View File

@ -0,0 +1,120 @@
//// [tests/cases/compiler/largeTupleTypes.ts] ////
=== largeTupleTypes.ts ===
// Repro from #54491
type UnshiftTuple<T extends [...any[]]> = T extends [T[0], ...infer Tail] ? Tail : never;
>UnshiftTuple : Symbol(UnshiftTuple, Decl(largeTupleTypes.ts, 0, 0))
>T : Symbol(T, Decl(largeTupleTypes.ts, 2, 18))
>T : Symbol(T, Decl(largeTupleTypes.ts, 2, 18))
>T : Symbol(T, Decl(largeTupleTypes.ts, 2, 18))
>Tail : Symbol(Tail, Decl(largeTupleTypes.ts, 2, 67))
>Tail : Symbol(Tail, Decl(largeTupleTypes.ts, 2, 67))
type ExpandSmallerTuples<T extends [...any[]]> = T extends [T[0], ...infer Tail] ? T | ExpandSmallerTuples<Tail> : [];
>ExpandSmallerTuples : Symbol(ExpandSmallerTuples, Decl(largeTupleTypes.ts, 2, 89))
>T : Symbol(T, Decl(largeTupleTypes.ts, 3, 25))
>T : Symbol(T, Decl(largeTupleTypes.ts, 3, 25))
>T : Symbol(T, Decl(largeTupleTypes.ts, 3, 25))
>Tail : Symbol(Tail, Decl(largeTupleTypes.ts, 3, 74))
>T : Symbol(T, Decl(largeTupleTypes.ts, 3, 25))
>ExpandSmallerTuples : Symbol(ExpandSmallerTuples, Decl(largeTupleTypes.ts, 2, 89))
>Tail : Symbol(Tail, Decl(largeTupleTypes.ts, 3, 74))
type Shift<A extends Array<any>> = ((...args: A) => void) extends (...args: [A[0], ...infer R]) => void ? R : never;
>Shift : Symbol(Shift, Decl(largeTupleTypes.ts, 3, 118))
>A : Symbol(A, Decl(largeTupleTypes.ts, 4, 11))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>args : Symbol(args, Decl(largeTupleTypes.ts, 4, 37))
>A : Symbol(A, Decl(largeTupleTypes.ts, 4, 11))
>args : Symbol(args, Decl(largeTupleTypes.ts, 4, 67))
>A : Symbol(A, Decl(largeTupleTypes.ts, 4, 11))
>R : Symbol(R, Decl(largeTupleTypes.ts, 4, 91))
>R : Symbol(R, Decl(largeTupleTypes.ts, 4, 91))
type GrowExpRev<A extends Array<any>, N extends number, P extends Array<Array<any>>> = A['length'] extends N ? A : GrowExpRev<[...A, ...P[0]][N] extends undefined ? [...A, ...P[0]] : A, N, Shift<P>>;
>GrowExpRev : Symbol(GrowExpRev, Decl(largeTupleTypes.ts, 4, 116))
>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>N : Symbol(N, Decl(largeTupleTypes.ts, 5, 37))
>P : Symbol(P, Decl(largeTupleTypes.ts, 5, 55))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16))
>N : Symbol(N, Decl(largeTupleTypes.ts, 5, 37))
>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16))
>GrowExpRev : Symbol(GrowExpRev, Decl(largeTupleTypes.ts, 4, 116))
>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16))
>P : Symbol(P, Decl(largeTupleTypes.ts, 5, 55))
>N : Symbol(N, Decl(largeTupleTypes.ts, 5, 37))
>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16))
>P : Symbol(P, Decl(largeTupleTypes.ts, 5, 55))
>A : Symbol(A, Decl(largeTupleTypes.ts, 5, 16))
>N : Symbol(N, Decl(largeTupleTypes.ts, 5, 37))
>Shift : Symbol(Shift, Decl(largeTupleTypes.ts, 3, 118))
>P : Symbol(P, Decl(largeTupleTypes.ts, 5, 55))
type GrowExp<A extends Array<any>, N extends number, P extends Array<Array<any>>> = [...A, ...A][N] extends undefined ? GrowExp<[...A, ...A], N, [A, ...P]> : GrowExpRev<A, N, P>;
>GrowExp : Symbol(GrowExp, Decl(largeTupleTypes.ts, 5, 199))
>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>N : Symbol(N, Decl(largeTupleTypes.ts, 6, 34))
>P : Symbol(P, Decl(largeTupleTypes.ts, 6, 52))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13))
>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13))
>N : Symbol(N, Decl(largeTupleTypes.ts, 6, 34))
>GrowExp : Symbol(GrowExp, Decl(largeTupleTypes.ts, 5, 199))
>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13))
>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13))
>N : Symbol(N, Decl(largeTupleTypes.ts, 6, 34))
>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13))
>P : Symbol(P, Decl(largeTupleTypes.ts, 6, 52))
>GrowExpRev : Symbol(GrowExpRev, Decl(largeTupleTypes.ts, 4, 116))
>A : Symbol(A, Decl(largeTupleTypes.ts, 6, 13))
>N : Symbol(N, Decl(largeTupleTypes.ts, 6, 34))
>P : Symbol(P, Decl(largeTupleTypes.ts, 6, 52))
type Tuple<T, N extends number> = number extends N ? Array<T> : N extends 0 ? [] : N extends 1 ? [T] : GrowExp<[T], N, [[]]>;
>Tuple : Symbol(Tuple, Decl(largeTupleTypes.ts, 6, 178))
>T : Symbol(T, Decl(largeTupleTypes.ts, 7, 11))
>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13))
>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(largeTupleTypes.ts, 7, 11))
>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13))
>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13))
>T : Symbol(T, Decl(largeTupleTypes.ts, 7, 11))
>GrowExp : Symbol(GrowExp, Decl(largeTupleTypes.ts, 5, 199))
>T : Symbol(T, Decl(largeTupleTypes.ts, 7, 11))
>N : Symbol(N, Decl(largeTupleTypes.ts, 7, 13))
declare class ArrayValidator<T extends unknown[], I = T[number]> {
>ArrayValidator : Symbol(ArrayValidator, Decl(largeTupleTypes.ts, 7, 125))
>T : Symbol(T, Decl(largeTupleTypes.ts, 9, 29))
>I : Symbol(I, Decl(largeTupleTypes.ts, 9, 49))
>T : Symbol(T, Decl(largeTupleTypes.ts, 9, 29))
lengthRange<S extends number, E extends number>(start: S, endBefore: E): ArrayValidator<Exclude<ExpandSmallerTuples<UnshiftTuple<[...Tuple<I, E>]>>, ExpandSmallerTuples<UnshiftTuple<[...Tuple<I, S>]>>>>;
>lengthRange : Symbol(ArrayValidator.lengthRange, Decl(largeTupleTypes.ts, 9, 66))
>S : Symbol(S, Decl(largeTupleTypes.ts, 10, 16))
>E : Symbol(E, Decl(largeTupleTypes.ts, 10, 33))
>start : Symbol(start, Decl(largeTupleTypes.ts, 10, 52))
>S : Symbol(S, Decl(largeTupleTypes.ts, 10, 16))
>endBefore : Symbol(endBefore, Decl(largeTupleTypes.ts, 10, 61))
>E : Symbol(E, Decl(largeTupleTypes.ts, 10, 33))
>ArrayValidator : Symbol(ArrayValidator, Decl(largeTupleTypes.ts, 7, 125))
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
>ExpandSmallerTuples : Symbol(ExpandSmallerTuples, Decl(largeTupleTypes.ts, 2, 89))
>UnshiftTuple : Symbol(UnshiftTuple, Decl(largeTupleTypes.ts, 0, 0))
>Tuple : Symbol(Tuple, Decl(largeTupleTypes.ts, 6, 178))
>I : Symbol(I, Decl(largeTupleTypes.ts, 9, 49))
>E : Symbol(E, Decl(largeTupleTypes.ts, 10, 33))
>ExpandSmallerTuples : Symbol(ExpandSmallerTuples, Decl(largeTupleTypes.ts, 2, 89))
>UnshiftTuple : Symbol(UnshiftTuple, Decl(largeTupleTypes.ts, 0, 0))
>Tuple : Symbol(Tuple, Decl(largeTupleTypes.ts, 6, 178))
>I : Symbol(I, Decl(largeTupleTypes.ts, 9, 49))
>S : Symbol(S, Decl(largeTupleTypes.ts, 10, 16))
}

View File

@ -0,0 +1,34 @@
//// [tests/cases/compiler/largeTupleTypes.ts] ////
=== largeTupleTypes.ts ===
// Repro from #54491
type UnshiftTuple<T extends [...any[]]> = T extends [T[0], ...infer Tail] ? Tail : never;
>UnshiftTuple : UnshiftTuple<T>
type ExpandSmallerTuples<T extends [...any[]]> = T extends [T[0], ...infer Tail] ? T | ExpandSmallerTuples<Tail> : [];
>ExpandSmallerTuples : ExpandSmallerTuples<T>
type Shift<A extends Array<any>> = ((...args: A) => void) extends (...args: [A[0], ...infer R]) => void ? R : never;
>Shift : Shift<A>
>args : A
>args : [A[0], ...R]
type GrowExpRev<A extends Array<any>, N extends number, P extends Array<Array<any>>> = A['length'] extends N ? A : GrowExpRev<[...A, ...P[0]][N] extends undefined ? [...A, ...P[0]] : A, N, Shift<P>>;
>GrowExpRev : GrowExpRev<A, N, P>
type GrowExp<A extends Array<any>, N extends number, P extends Array<Array<any>>> = [...A, ...A][N] extends undefined ? GrowExp<[...A, ...A], N, [A, ...P]> : GrowExpRev<A, N, P>;
>GrowExp : GrowExp<A, N, P>
type Tuple<T, N extends number> = number extends N ? Array<T> : N extends 0 ? [] : N extends 1 ? [T] : GrowExp<[T], N, [[]]>;
>Tuple : Tuple<T, N>
declare class ArrayValidator<T extends unknown[], I = T[number]> {
>ArrayValidator : ArrayValidator<T, I>
lengthRange<S extends number, E extends number>(start: S, endBefore: E): ArrayValidator<Exclude<ExpandSmallerTuples<UnshiftTuple<[...Tuple<I, E>]>>, ExpandSmallerTuples<UnshiftTuple<[...Tuple<I, S>]>>>>;
>lengthRange : <S extends number, E extends number>(start: S, endBefore: E) => ArrayValidator<Exclude<ExpandSmallerTuples<UnshiftTuple<[...Tuple<I, E>]>>, ExpandSmallerTuples<UnshiftTuple<[...Tuple<I, S>]>>>>
>start : S
>endBefore : E
}

View File

@ -1,7 +1,7 @@
test.ts(4,5): error TS2322: Type 'PassportStatic' is not assignable to type 'Passport'.
The types returned by 'use()' are incompatible between these types.
Type 'PassportStatic' is not assignable to type 'this'.
'this' could be instantiated with an arbitrary type which could be unrelated to 'PassportStatic'.
'PassportStatic' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Passport'.
==== passport.d.ts (0 errors) ====
@ -29,4 +29,4 @@ test.ts(4,5): error TS2322: Type 'PassportStatic' is not assignable to type 'Pas
!!! error TS2322: Type 'PassportStatic' is not assignable to type 'Passport'.
!!! error TS2322: The types returned by 'use()' are incompatible between these types.
!!! error TS2322: Type 'PassportStatic' is not assignable to type 'this'.
!!! error TS2322: 'this' could be instantiated with an arbitrary type which could be unrelated to 'PassportStatic'.
!!! error TS2322: 'PassportStatic' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Passport'.

View File

@ -0,0 +1,15 @@
// @strict: true
// @noEmit: true
// Repro from #54491
type UnshiftTuple<T extends [...any[]]> = T extends [T[0], ...infer Tail] ? Tail : never;
type ExpandSmallerTuples<T extends [...any[]]> = T extends [T[0], ...infer Tail] ? T | ExpandSmallerTuples<Tail> : [];
type Shift<A extends Array<any>> = ((...args: A) => void) extends (...args: [A[0], ...infer R]) => void ? R : never;
type GrowExpRev<A extends Array<any>, N extends number, P extends Array<Array<any>>> = A['length'] extends N ? A : GrowExpRev<[...A, ...P[0]][N] extends undefined ? [...A, ...P[0]] : A, N, Shift<P>>;
type GrowExp<A extends Array<any>, N extends number, P extends Array<Array<any>>> = [...A, ...A][N] extends undefined ? GrowExp<[...A, ...A], N, [A, ...P]> : GrowExpRev<A, N, P>;
type Tuple<T, N extends number> = number extends N ? Array<T> : N extends 0 ? [] : N extends 1 ? [T] : GrowExp<[T], N, [[]]>;
declare class ArrayValidator<T extends unknown[], I = T[number]> {
lengthRange<S extends number, E extends number>(start: S, endBefore: E): ArrayValidator<Exclude<ExpandSmallerTuples<UnshiftTuple<[...Tuple<I, E>]>>, ExpandSmallerTuples<UnshiftTuple<[...Tuple<I, S>]>>>>;
}