Constraints for generic tuple types (#53672)
This commit is contained in:
Родитель
94564cf073
Коммит
44f4e276b7
|
@ -10409,7 +10409,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
// If the parent is a tuple type, the rest element has a tuple type of the
|
||||
// remaining tuple element types. Otherwise, the rest element has an array type with same
|
||||
// element type as the parent type.
|
||||
const baseConstraint = getBaseConstraintOrType(parentType);
|
||||
const baseConstraint = mapType(parentType, t => t.flags & TypeFlags.InstantiableNonPrimitive ? getBaseConstraintOrType(t) : t);
|
||||
type = everyType(baseConstraint, isTupleType) ?
|
||||
mapType(baseConstraint, t => sliceTupleType(t as TupleTypeReference, index)) :
|
||||
createArrayType(elementType);
|
||||
|
@ -12556,6 +12556,10 @@ 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;
|
||||
|
@ -12685,7 +12689,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
return [sig.parameters];
|
||||
|
||||
function expandSignatureParametersWithTupleMembers(restType: TupleTypeReference, restIndex: number) {
|
||||
const elementTypes = getTypeArguments(restType);
|
||||
const elementTypes = getElementTypes(restType);
|
||||
const associatedNames = getUniqAssociatedNamesFromTupleType(restType);
|
||||
const restParams = map(elementTypes, (t, i) => {
|
||||
// Lookup the label from the individual tuple passed in before falling back to the signature `rest` parameter name
|
||||
|
@ -13583,7 +13587,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType) ||
|
||||
type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType)) ||
|
||||
type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType) ||
|
||||
isGenericTupleType(type) && findIndex(getTypeArguments(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t)) >= 0));
|
||||
isGenericTupleType(type) && findIndex(getElementTypes(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t)) >= 0));
|
||||
}
|
||||
|
||||
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
|
||||
|
@ -13708,7 +13712,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
}
|
||||
|
||||
function getBaseConstraintOfType(type: Type): Type | undefined {
|
||||
if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) {
|
||||
if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || isGenericTupleType(type)) {
|
||||
const constraint = getResolvedBaseConstraint(type as InstantiableType | UnionOrIntersectionType);
|
||||
return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined;
|
||||
}
|
||||
|
@ -13737,7 +13741,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
return type.resolvedBaseConstraint;
|
||||
}
|
||||
const stack: object[] = [];
|
||||
return type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), type);
|
||||
return type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), getThisArgument(type));
|
||||
|
||||
function getImmediateBaseConstraint(t: Type): Type {
|
||||
if (!t.immediateBaseConstraint) {
|
||||
|
@ -13839,6 +13843,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
if (t.flags & TypeFlags.Substitution) {
|
||||
return getBaseConstraint(getSubstitutionIntersection(t as SubstitutionType));
|
||||
}
|
||||
if (isGenericTupleType(t)) {
|
||||
// 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;
|
||||
});
|
||||
return createTupleType(newElements, t.target.elementFlags, t.target.readonly, t.target.labeledElementDeclarations);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
@ -16147,7 +16160,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]);
|
||||
}
|
||||
else if (isTupleType(type)) {
|
||||
const elements = getTypeArguments(type);
|
||||
const elements = getElementTypes(type);
|
||||
if (elements.length + expandedTypes.length >= 10_000) {
|
||||
error(currentNode, isPartOfTypeNode(currentNode!)
|
||||
? Diagnostics.Type_produces_a_tuple_type_that_is_too_large_to_represent
|
||||
|
@ -16229,6 +16242,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
return type.elementFlags.length - findLastIndex(type.elementFlags, f => !(f & flags)) - 1;
|
||||
}
|
||||
|
||||
function getElementTypes(type: TupleTypeReference): readonly Type[] {
|
||||
const typeArguments = getTypeArguments(type);
|
||||
const arity = getTypeReferenceArity(type);
|
||||
return typeArguments.length === arity ? typeArguments : typeArguments.slice(0, arity);
|
||||
}
|
||||
|
||||
function getTypeFromOptionalTypeNode(node: OptionalTypeNode): Type {
|
||||
return addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true);
|
||||
}
|
||||
|
@ -17779,7 +17798,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
}
|
||||
|
||||
function isDeferredType(type: Type, checkTuples: boolean) {
|
||||
return isGenericType(type) || checkTuples && isTupleType(type) && some(getTypeArguments(type), isGenericType);
|
||||
return isGenericType(type) || checkTuples && isTupleType(type) && some(getElementTypes(type), isGenericType);
|
||||
}
|
||||
|
||||
function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type {
|
||||
|
@ -18920,7 +18939,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
// M<[A, B?, ...T, ...C[]] into [...M<[A]>, ...M<[B?]>, ...M<T>, ...M<C[]>] and then rely on tuple type
|
||||
// normalization to resolve the non-generic parts of the resulting tuple.
|
||||
const elementFlags = tupleType.target.elementFlags;
|
||||
const elementTypes = map(getTypeArguments(tupleType), (t, i) => {
|
||||
const elementTypes = map(getElementTypes(tupleType), (t, i) => {
|
||||
const singleton = elementFlags[i] & ElementFlags.Variadic ? t :
|
||||
elementFlags[i] & ElementFlags.Rest ? createArrayType(t) :
|
||||
createTupleType([t], [elementFlags[i]]);
|
||||
|
@ -18939,7 +18958,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
|
||||
function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) {
|
||||
const elementFlags = tupleType.target.elementFlags;
|
||||
const elementTypes = map(getTypeArguments(tupleType), (_, i) =>
|
||||
const elementTypes = map(getElementTypes(tupleType), (_, i) =>
|
||||
instantiateMappedTypeTemplate(mappedType, getStringLiteralType("" + i), !!(elementFlags[i] & ElementFlags.Optional), mapper));
|
||||
const modifiers = getMappedTypeModifiers(mappedType);
|
||||
const newTupleModifiers = modifiers & MappedTypeModifiers.IncludeOptional ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) :
|
||||
|
@ -20244,7 +20263,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
}
|
||||
|
||||
function getNormalizedTupleType(type: TupleTypeReference, writing: boolean): Type {
|
||||
const elements = getTypeArguments(type);
|
||||
const elements = getElementTypes(type);
|
||||
const normalizedElements = sameMap(elements, t => t.flags & TypeFlags.Simplifiable ? getSimplifiedType(t, writing) : t);
|
||||
return elements !== normalizedElements ? createNormalizedTupleType(type.target, normalizedElements) : type;
|
||||
}
|
||||
|
@ -21802,6 +21821,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
else if (isGenericTupleType(source) && isTupleType(target) && !isGenericTupleType(target)) {
|
||||
const constraint = getBaseConstraintOrType(source);
|
||||
if (constraint !== source) {
|
||||
return isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors);
|
||||
}
|
||||
}
|
||||
// A fresh empty object type is never a subtype of a non-empty object type. This ensures fresh({}) <: { [x: string]: xxx }
|
||||
// but not vice-versa. Without this rule, those types would be mutual subtypes.
|
||||
else if ((relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) {
|
||||
|
@ -24083,7 +24108,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
function isPartiallyInferableType(type: Type): boolean {
|
||||
return !(getObjectFlags(type) & ObjectFlags.NonInferrableType) ||
|
||||
isObjectLiteralType(type) && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop))) ||
|
||||
isTupleType(type) && some(getTypeArguments(type), isPartiallyInferableType);
|
||||
isTupleType(type) && some(getElementTypes(type), isPartiallyInferableType);
|
||||
}
|
||||
|
||||
function createReverseMappedType(source: Type, target: MappedType, constraint: IndexType) {
|
||||
|
@ -24098,7 +24123,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
return createArrayType(inferReverseMappedType(getTypeArguments(source)[0], target, constraint), isReadonlyArrayType(source));
|
||||
}
|
||||
if (isTupleType(source)) {
|
||||
const elementTypes = map(getTypeArguments(source), t => inferReverseMappedType(t, target, constraint));
|
||||
const elementTypes = map(getElementTypes(source), t => inferReverseMappedType(t, target, constraint));
|
||||
const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ?
|
||||
sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) :
|
||||
source.target.elementFlags;
|
||||
|
@ -32491,7 +32516,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
function getMutableArrayOrTupleType(type: Type) {
|
||||
return type.flags & TypeFlags.Union ? mapType(type, getMutableArrayOrTupleType) :
|
||||
type.flags & TypeFlags.Any || isMutableArrayOrTuple(getBaseConstraintOfType(type) || type) ? type :
|
||||
isTupleType(type) ? createTupleType(getTypeArguments(type), type.target.elementFlags, /*readonly*/ false, type.target.labeledElementDeclarations) :
|
||||
isTupleType(type) ? createTupleType(getElementTypes(type), type.target.elementFlags, /*readonly*/ false, type.target.labeledElementDeclarations) :
|
||||
createTupleType([type], [ElementFlags.Variadic]);
|
||||
}
|
||||
|
||||
|
@ -32825,7 +32850,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
// We can call checkExpressionCached because spread expressions never have a contextual type.
|
||||
const spreadType = arg.kind === SyntaxKind.SpreadElement && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) : checkExpressionCached((arg as SpreadElement).expression));
|
||||
if (spreadType && isTupleType(spreadType)) {
|
||||
forEach(getTypeArguments(spreadType), (t, i) => {
|
||||
forEach(getElementTypes(spreadType), (t, i) => {
|
||||
const flags = spreadType.target.elementFlags[i];
|
||||
const syntheticArg = createSyntheticExpression(arg, flags & ElementFlags.Rest ? createArrayType(t) : t,
|
||||
!!(flags & ElementFlags.Variable), spreadType.target.labeledElementDeclarations?.[i]);
|
||||
|
@ -37436,7 +37461,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
|
||||
function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) {
|
||||
const patternElements = pattern.elements;
|
||||
const elementTypes = getTypeArguments(type).slice();
|
||||
const elementTypes = getElementTypes(type).slice();
|
||||
const elementFlags = type.target.elementFlags.slice();
|
||||
for (let i = getTypeReferenceArity(type); i < patternElements.length; i++) {
|
||||
const e = patternElements[i];
|
||||
|
|
|
@ -35,13 +35,20 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(191,5): error TS2322: Typ
|
|||
'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'readonly string[]'.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(203,5): error TS2322: Type 'string' is not assignable to type 'keyof [1, 2, ...T]'.
|
||||
Type '"2"' is not assignable to type '"0" | "1" | keyof T[]'.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(357,26): error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Type '[boolean, false]' is not assignable to type '[...number[], boolean]'.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(213,5): error TS2322: Type '[...T, ...T]' is not assignable to type '[unknown, unknown]'.
|
||||
Type '[] | [unknown] | [unknown, unknown]' is not assignable to type '[unknown, unknown]'.
|
||||
Type '[]' is not assignable to type '[unknown, unknown]'.
|
||||
Source has 0 element(s) but target requires 2.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(217,5): error TS2322: Type '[...T, ...T]' is not assignable to type '[unknown, unknown]'.
|
||||
Type 'unknown[]' is not assignable to type '[unknown, unknown]'.
|
||||
Target requires 2 element(s) but source may have fewer.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(371,26): error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(411,7): error TS2322: Type '[boolean, false]' is not assignable to type '[...number[], boolean]'.
|
||||
Type at position 0 in source is not compatible with type at position 0 in target.
|
||||
Type 'boolean' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/tuple/variadicTuples1.ts (20 errors) ====
|
||||
==== tests/cases/conformance/types/tuple/variadicTuples1.ts (22 errors) ====
|
||||
// Variadics in tuple types
|
||||
|
||||
type TV0<T extends unknown[]> = [string, ...T];
|
||||
|
@ -303,6 +310,29 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Typ
|
|||
!!! error TS2322: Type '"2"' is not assignable to type '"0" | "1" | keyof T[]'.
|
||||
}
|
||||
|
||||
// Constraints of variadic tuple types
|
||||
|
||||
function ft16<T extends [unknown]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
function ft17<T extends [] | [unknown]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
x = y;
|
||||
~
|
||||
!!! error TS2322: Type '[...T, ...T]' is not assignable to type '[unknown, unknown]'.
|
||||
!!! error TS2322: Type '[] | [unknown] | [unknown, unknown]' is not assignable to type '[unknown, unknown]'.
|
||||
!!! error TS2322: Type '[]' is not assignable to type '[unknown, unknown]'.
|
||||
!!! error TS2322: Source has 0 element(s) but target requires 2.
|
||||
}
|
||||
|
||||
function ft18<T extends unknown[]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
x = y;
|
||||
~
|
||||
!!! error TS2322: Type '[...T, ...T]' is not assignable to type '[unknown, unknown]'.
|
||||
!!! error TS2322: Type 'unknown[]' is not assignable to type '[unknown, unknown]'.
|
||||
!!! error TS2322: Target requires 2 element(s) but source may have fewer.
|
||||
}
|
||||
|
||||
// Inference between variadic tuple types
|
||||
|
||||
type First<T extends readonly unknown[]> =
|
||||
|
@ -505,4 +535,9 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Typ
|
|||
type U1 = [string, ...Numbers, boolean];
|
||||
type U2 = [...[string, ...Numbers], boolean];
|
||||
type U3 = [...[string, number], boolean];
|
||||
|
||||
// Repro from #53563
|
||||
|
||||
type ToStringLength1<T extends any[]> = `${T['length']}`;
|
||||
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
|
||||
|
|
@ -204,6 +204,20 @@ function f15<T extends string[], U extends T>(k0: keyof T, k1: keyof [...T], k2:
|
|||
k3 = '2'; // Error
|
||||
}
|
||||
|
||||
// Constraints of variadic tuple types
|
||||
|
||||
function ft16<T extends [unknown]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
function ft17<T extends [] | [unknown]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
function ft18<T extends unknown[]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
// Inference between variadic tuple types
|
||||
|
||||
type First<T extends readonly unknown[]> =
|
||||
|
@ -400,6 +414,11 @@ const data: Unbounded = [false, false]; // Error
|
|||
type U1 = [string, ...Numbers, boolean];
|
||||
type U2 = [...[string, ...Numbers], boolean];
|
||||
type U3 = [...[string, number], boolean];
|
||||
|
||||
// Repro from #53563
|
||||
|
||||
type ToStringLength1<T extends any[]> = `${T['length']}`;
|
||||
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
|
||||
|
||||
|
||||
//// [variadicTuples1.js]
|
||||
|
@ -541,6 +560,16 @@ function f15(k0, k1, k2, k3) {
|
|||
k3 = '1';
|
||||
k3 = '2'; // Error
|
||||
}
|
||||
// Constraints of variadic tuple types
|
||||
function ft16(x, y) {
|
||||
x = y;
|
||||
}
|
||||
function ft17(x, y) {
|
||||
x = y;
|
||||
}
|
||||
function ft18(x, y) {
|
||||
x = y;
|
||||
}
|
||||
// Inference to [...T, ...U] with implied arity for T
|
||||
function curry(f) {
|
||||
var a = [];
|
||||
|
@ -677,6 +706,9 @@ declare function f12<T extends readonly unknown[]>(t: T, m: [...T], r: readonly
|
|||
declare function f13<T extends string[], U extends T>(t0: T, t1: [...T], t2: [...U]): void;
|
||||
declare function f14<T extends readonly string[], U extends T>(t0: T, t1: [...T], t2: [...U]): void;
|
||||
declare function f15<T extends string[], U extends T>(k0: keyof T, k1: keyof [...T], k2: keyof [...U], k3: keyof [1, 2, ...T]): void;
|
||||
declare function ft16<T extends [unknown]>(x: [unknown, unknown], y: [...T, ...T]): void;
|
||||
declare function ft17<T extends [] | [unknown]>(x: [unknown, unknown], y: [...T, ...T]): void;
|
||||
declare function ft18<T extends unknown[]>(x: [unknown, unknown], y: [...T, ...T]): void;
|
||||
type First<T extends readonly unknown[]> = T extends readonly [unknown, ...unknown[]] ? T[0] : T[0] | undefined;
|
||||
type DropFirst<T extends readonly unknown[]> = T extends readonly [unknown?, ...infer U] ? U : [...T];
|
||||
type Last<T extends readonly unknown[]> = T extends readonly [...unknown[], infer U] ? U : T extends readonly [unknown, ...unknown[]] ? T[number] : T[number] | undefined;
|
||||
|
@ -794,3 +826,5 @@ declare const data: Unbounded;
|
|||
type U1 = [string, ...Numbers, boolean];
|
||||
type U2 = [...[string, ...Numbers], boolean];
|
||||
type U3 = [...[string, number], boolean];
|
||||
type ToStringLength1<T extends any[]> = `${T['length']}`;
|
||||
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -770,6 +770,41 @@ function f15<T extends string[], U extends T>(k0: keyof T, k1: keyof [...T], k2:
|
|||
>'2' : "2"
|
||||
}
|
||||
|
||||
// Constraints of variadic tuple types
|
||||
|
||||
function ft16<T extends [unknown]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
>ft16 : <T extends [unknown]>(x: [unknown, unknown], y: [...T, ...T]) => void
|
||||
>x : [unknown, unknown]
|
||||
>y : [...T, ...T]
|
||||
|
||||
x = y;
|
||||
>x = y : [...T, ...T]
|
||||
>x : [unknown, unknown]
|
||||
>y : [...T, ...T]
|
||||
}
|
||||
|
||||
function ft17<T extends [] | [unknown]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
>ft17 : <T extends [] | [unknown]>(x: [unknown, unknown], y: [...T, ...T]) => void
|
||||
>x : [unknown, unknown]
|
||||
>y : [...T, ...T]
|
||||
|
||||
x = y;
|
||||
>x = y : [...T, ...T]
|
||||
>x : [unknown, unknown]
|
||||
>y : [...T, ...T]
|
||||
}
|
||||
|
||||
function ft18<T extends unknown[]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
>ft18 : <T extends unknown[]>(x: [unknown, unknown], y: [...T, ...T]) => void
|
||||
>x : [unknown, unknown]
|
||||
>y : [...T, ...T]
|
||||
|
||||
x = y;
|
||||
>x = y : [...T, ...T]
|
||||
>x : [unknown, unknown]
|
||||
>y : [...T, ...T]
|
||||
}
|
||||
|
||||
// Inference between variadic tuple types
|
||||
|
||||
type First<T extends readonly unknown[]> =
|
||||
|
@ -1410,3 +1445,11 @@ type U2 = [...[string, ...Numbers], boolean];
|
|||
type U3 = [...[string, number], boolean];
|
||||
>U3 : [string, number, boolean]
|
||||
|
||||
// Repro from #53563
|
||||
|
||||
type ToStringLength1<T extends any[]> = `${T['length']}`;
|
||||
>ToStringLength1 : `${T["length"]}`
|
||||
|
||||
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
|
||||
>ToStringLength2 : `${[...T]["length"]}`
|
||||
|
||||
|
|
|
@ -36,12 +36,12 @@ tests/cases/conformance/types/tuple/variadicTuples2.ts(71,5): error TS2322: Type
|
|||
tests/cases/conformance/types/tuple/variadicTuples2.ts(72,5): error TS2322: Type '[number, ...number[]]' is not assignable to type '[number, ...T]'.
|
||||
Target requires 2 element(s) but source may have fewer.
|
||||
tests/cases/conformance/types/tuple/variadicTuples2.ts(73,5): error TS2322: Type '[number, ...T]' is not assignable to type '[number, number]'.
|
||||
Variadic element at position 1 in source does not match element at position 1 in target.
|
||||
Type '[number, ...unknown[]]' is not assignable to type '[number, number]'.
|
||||
Target requires 2 element(s) but source may have fewer.
|
||||
tests/cases/conformance/types/tuple/variadicTuples2.ts(74,5): error TS2322: Type '[number, ...T]' is not assignable to type '[number, ...number[]]'.
|
||||
Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
Type 'T' is not assignable to type 'number[]'.
|
||||
Type 'unknown[]' is not assignable to type 'number[]'.
|
||||
Type 'unknown' is not assignable to type 'number'.
|
||||
Type '[number, ...unknown[]]' is not assignable to type '[number, ...number[]]'.
|
||||
Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
Type 'unknown' is not assignable to type 'number'.
|
||||
tests/cases/conformance/types/tuple/variadicTuples2.ts(79,5): error TS2322: Type '[number, string, ...any[]]' is not assignable to type '[number, ...number[]]'.
|
||||
Type at positions 1 through 2 in source is not compatible with type at position 1 in target.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
|
@ -195,14 +195,14 @@ tests/cases/conformance/types/tuple/variadicTuples2.ts(134,25): error TS2345: Ar
|
|||
y = x; // Error
|
||||
~
|
||||
!!! error TS2322: Type '[number, ...T]' is not assignable to type '[number, number]'.
|
||||
!!! error TS2322: Variadic element at position 1 in source does not match element at position 1 in target.
|
||||
!!! error TS2322: Type '[number, ...unknown[]]' is not assignable to type '[number, number]'.
|
||||
!!! error TS2322: Target requires 2 element(s) but source may have fewer.
|
||||
z = x; // Error
|
||||
~
|
||||
!!! error TS2322: Type '[number, ...T]' is not assignable to type '[number, ...number[]]'.
|
||||
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'number[]'.
|
||||
!!! error TS2322: Type 'unknown[]' is not assignable to type 'number[]'.
|
||||
!!! error TS2322: Type 'unknown' is not assignable to type 'number'.
|
||||
!!! error TS2322: Type '[number, ...unknown[]]' is not assignable to type '[number, ...number[]]'.
|
||||
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
|
||||
!!! error TS2322: Type 'unknown' is not assignable to type 'number'.
|
||||
}
|
||||
|
||||
// repro #50216
|
||||
|
|
|
@ -206,6 +206,20 @@ function f15<T extends string[], U extends T>(k0: keyof T, k1: keyof [...T], k2:
|
|||
k3 = '2'; // Error
|
||||
}
|
||||
|
||||
// Constraints of variadic tuple types
|
||||
|
||||
function ft16<T extends [unknown]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
function ft17<T extends [] | [unknown]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
function ft18<T extends unknown[]>(x: [unknown, unknown], y: [...T, ...T]) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
// Inference between variadic tuple types
|
||||
|
||||
type First<T extends readonly unknown[]> =
|
||||
|
@ -402,3 +416,8 @@ const data: Unbounded = [false, false]; // Error
|
|||
type U1 = [string, ...Numbers, boolean];
|
||||
type U2 = [...[string, ...Numbers], boolean];
|
||||
type U3 = [...[string, number], boolean];
|
||||
|
||||
// Repro from #53563
|
||||
|
||||
type ToStringLength1<T extends any[]> = `${T['length']}`;
|
||||
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
|
||||
|
|
Загрузка…
Ссылка в новой задаче