mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 21:36:50 -05:00
Improve support for numeric string types (#48837)
* Improve support for numeric string types * Update test * Add tests
This commit is contained in:
@@ -833,6 +833,7 @@ namespace ts {
|
||||
const keyofConstraintType = keyofStringsOnly ? stringType : stringNumberSymbolType;
|
||||
const numberOrBigIntType = getUnionType([numberType, bigintType]);
|
||||
const templateConstraintType = getUnionType([stringType, numberType, booleanType, bigintType, nullType, undefinedType]) as UnionType;
|
||||
const numericStringType = getTemplateLiteralType(["", ""], [numberType]); // The `${number}` type
|
||||
|
||||
const restrictiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t);
|
||||
const permissiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? wildcardType : t);
|
||||
@@ -12273,7 +12274,7 @@ namespace ts {
|
||||
const typeVariable = getHomomorphicTypeVariable(type);
|
||||
if (typeVariable && !type.declaration.nameType) {
|
||||
const constraint = getConstraintOfTypeParameter(typeVariable);
|
||||
if (constraint && (isArrayType(constraint) || isTupleType(constraint))) {
|
||||
if (constraint && isArrayOrTupleType(constraint)) {
|
||||
return instantiateType(type, prependTypeMapping(typeVariable, constraint, type.mapper));
|
||||
}
|
||||
}
|
||||
@@ -12654,10 +12655,10 @@ namespace ts {
|
||||
|
||||
function isApplicableIndexType(source: Type, target: Type): boolean {
|
||||
// A 'string' index signature applies to types assignable to 'string' or 'number', and a 'number' index
|
||||
// signature applies to types assignable to 'number' and numeric string literal types.
|
||||
// signature applies to types assignable to 'number', `${number}` and numeric string literal types.
|
||||
return isTypeAssignableTo(source, target) ||
|
||||
target === stringType && isTypeAssignableTo(source, numberType) ||
|
||||
target === numberType && !!(source.flags & TypeFlags.StringLiteral) && isNumericLiteralName((source as StringLiteralType).value);
|
||||
target === numberType && (source === numericStringType || !!(source.flags & TypeFlags.StringLiteral) && isNumericLiteralName((source as StringLiteralType).value));
|
||||
}
|
||||
|
||||
function getIndexInfosOfStructuredType(type: Type): readonly IndexInfo[] {
|
||||
@@ -13778,6 +13779,20 @@ namespace ts {
|
||||
constraints = append(constraints, constraint);
|
||||
}
|
||||
}
|
||||
// Given a homomorphic mapped type { [K in keyof T]: XXX }, where T is constrained to an array or tuple type, in the
|
||||
// template type XXX, K has an added constraint of number | `${number}`.
|
||||
else if (type.flags & TypeFlags.TypeParameter && parent.kind === SyntaxKind.MappedType && node === (parent as MappedTypeNode).type) {
|
||||
const mappedType = getTypeFromTypeNode(parent as TypeNode) as MappedType;
|
||||
if (getTypeParameterFromMappedType(mappedType) === getActualTypeVariable(type)) {
|
||||
const typeParameter = getHomomorphicTypeVariable(mappedType);
|
||||
if (typeParameter) {
|
||||
const constraint = getConstraintOfTypeParameter(typeParameter);
|
||||
if (constraint && everyType(constraint, isArrayOrTupleType)) {
|
||||
constraints = append(constraints, getUnionType([numberType, numericStringType]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
return constraints ? getSubstitutionType(type, getIntersectionType(append(constraints, type))) : type;
|
||||
@@ -14817,7 +14832,7 @@ namespace ts {
|
||||
i--;
|
||||
const t = types[i];
|
||||
const remove =
|
||||
t.flags & TypeFlags.String && includes & TypeFlags.StringLiteral ||
|
||||
t.flags & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ||
|
||||
t.flags & TypeFlags.Number && includes & TypeFlags.NumberLiteral ||
|
||||
t.flags & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral ||
|
||||
t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol;
|
||||
@@ -14978,7 +14993,7 @@ namespace ts {
|
||||
if (!strictNullChecks && includes & TypeFlags.Nullable) {
|
||||
return includes & TypeFlags.Undefined ? undefinedType : nullType;
|
||||
}
|
||||
if (includes & TypeFlags.String && includes & TypeFlags.StringLiteral ||
|
||||
if (includes & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ||
|
||||
includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral ||
|
||||
includes & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral ||
|
||||
includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol) {
|
||||
@@ -16996,7 +17011,7 @@ namespace ts {
|
||||
if (!type.declaration.nameType) {
|
||||
let constraint;
|
||||
if (isArrayType(t) || t.flags & TypeFlags.Any && findResolutionCycleStartIndex(typeVariable, TypeSystemPropertyName.ImmediateBaseConstraint) < 0 &&
|
||||
(constraint = getConstraintOfTypeParameter(typeVariable)) && everyType(constraint, or(isArrayType, isTupleType))) {
|
||||
(constraint = getConstraintOfTypeParameter(typeVariable)) && everyType(constraint, isArrayOrTupleType)) {
|
||||
return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper));
|
||||
}
|
||||
if (isGenericTupleType(t)) {
|
||||
@@ -18565,7 +18580,7 @@ namespace ts {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return isTupleType(target) || isArrayType(target);
|
||||
return isArrayOrTupleType(target);
|
||||
}
|
||||
if (isReadonlyArrayType(source) && isMutableArrayOrTuple(target)) {
|
||||
if (reportErrors) {
|
||||
@@ -18700,7 +18715,7 @@ namespace ts {
|
||||
// recursive intersections that are structurally similar but not exactly identical. See #37854.
|
||||
if (result && !inPropertyCheck && (
|
||||
target.flags & TypeFlags.Intersection && (isPerformingExcessPropertyChecks || isPerformingCommonPropertyChecks) ||
|
||||
isNonGenericObjectType(target) && !isArrayType(target) && !isTupleType(target) && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && !some((source as IntersectionType).types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)))) {
|
||||
isNonGenericObjectType(target) && !isArrayOrTupleType(target) && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && !some((source as IntersectionType).types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)))) {
|
||||
inPropertyCheck = true;
|
||||
result &= recursiveTypeRelatedTo(source, target, reportErrors, IntersectionState.PropertyCheck, recursionFlags);
|
||||
inPropertyCheck = false;
|
||||
@@ -19708,7 +19723,7 @@ namespace ts {
|
||||
return varianceResult;
|
||||
}
|
||||
}
|
||||
else if (isReadonlyArrayType(target) ? isArrayType(source) || isTupleType(source) : isArrayType(target) && isTupleType(source) && !source.target.readonly) {
|
||||
else if (isReadonlyArrayType(target) ? isArrayOrTupleType(source) : isArrayType(target) && isTupleType(source) && !source.target.readonly) {
|
||||
if (relation !== identityRelation) {
|
||||
return isRelatedTo(getIndexTypeOfType(source, numberType) || anyType, getIndexTypeOfType(target, numberType) || anyType, RecursionFlags.Both, reportErrors);
|
||||
}
|
||||
@@ -20093,7 +20108,7 @@ namespace ts {
|
||||
}
|
||||
let result = Ternary.True;
|
||||
if (isTupleType(target)) {
|
||||
if (isArrayType(source) || isTupleType(source)) {
|
||||
if (isArrayOrTupleType(source)) {
|
||||
if (!target.target.readonly && (isReadonlyArrayType(source) || isTupleType(source) && source.target.readonly)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
@@ -21098,6 +21113,10 @@ namespace ts {
|
||||
return !!(getObjectFlags(type) & ObjectFlags.Reference) && (type as TypeReference).target === globalReadonlyArrayType;
|
||||
}
|
||||
|
||||
function isArrayOrTupleType(type: Type): type is TypeReference {
|
||||
return isArrayType(type) || isTupleType(type);
|
||||
}
|
||||
|
||||
function isMutableArrayOrTuple(type: Type): boolean {
|
||||
return isArrayType(type) && !isReadonlyArrayType(type) || isTupleType(type) && !type.target.readonly;
|
||||
}
|
||||
@@ -21598,7 +21617,7 @@ namespace ts {
|
||||
else if (type.flags & TypeFlags.Intersection) {
|
||||
result = getIntersectionType(sameMap((type as IntersectionType).types, getWidenedType));
|
||||
}
|
||||
else if (isArrayType(type) || isTupleType(type)) {
|
||||
else if (isArrayOrTupleType(type)) {
|
||||
result = createTypeReference(type.target, sameMap(getTypeArguments(type), getWidenedType));
|
||||
}
|
||||
if (result && context === undefined) {
|
||||
@@ -21635,7 +21654,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isArrayType(type) || isTupleType(type)) {
|
||||
if (isArrayOrTupleType(type)) {
|
||||
for (const t of getTypeArguments(type)) {
|
||||
if (reportWideningErrorsInType(t)) {
|
||||
errorReported = true;
|
||||
@@ -22714,7 +22733,7 @@ namespace ts {
|
||||
}
|
||||
// Infer from the members of source and target only if the two types are possibly related
|
||||
if (!typesDefinitelyUnrelated(source, target)) {
|
||||
if (isArrayType(source) || isTupleType(source)) {
|
||||
if (isArrayOrTupleType(source)) {
|
||||
if (isTupleType(target)) {
|
||||
const sourceArity = getTypeReferenceArity(source);
|
||||
const targetArity = getTypeReferenceArity(target);
|
||||
|
||||
80
tests/baselines/reference/numericStringLiteralTypes.js
Normal file
80
tests/baselines/reference/numericStringLiteralTypes.js
Normal file
@@ -0,0 +1,80 @@
|
||||
//// [numericStringLiteralTypes.ts]
|
||||
type T0 = string & `${string}`; // string
|
||||
type T1 = string & `${number}`; // `${number}
|
||||
type T2 = string & `${bigint}`; // `${bigint}
|
||||
type T3<T extends string> = string & `${T}`; // `${T}
|
||||
type T4<T extends string> = string & `${Capitalize<`${T}`>}`; // `${Capitalize<T>}`
|
||||
|
||||
function f1(a: boolean[], x: `${number}`) {
|
||||
let s = a[x]; // boolean
|
||||
}
|
||||
|
||||
function f2(a: boolean[], x: number | `${number}`) {
|
||||
let s = a[x]; // boolean
|
||||
}
|
||||
|
||||
type T10 = boolean[][`${number}`]; // boolean
|
||||
type T11 = boolean[][number | `${number}`]; // boolean
|
||||
|
||||
type T20<T extends number | `${number}`> = T;
|
||||
type T21<T extends unknown[]> = { [K in keyof T]: T20<K> };
|
||||
|
||||
type Container<T> = {
|
||||
value: T
|
||||
}
|
||||
|
||||
type UnwrapContainers<T extends Container<unknown>[]> = { [K in keyof T]: T[K]['value'] };
|
||||
|
||||
declare function createContainer<T extends unknown>(value: T): Container<T>;
|
||||
|
||||
declare function f<T extends Container<unknown>[]>(containers: [...T], callback: (...values: UnwrapContainers<T>) => void): void;
|
||||
|
||||
const container1 = createContainer('hi')
|
||||
const container2 = createContainer(2)
|
||||
|
||||
f([container1, container2], (value1, value2) => {
|
||||
value1; // string
|
||||
value2; // number
|
||||
});
|
||||
|
||||
|
||||
//// [numericStringLiteralTypes.js]
|
||||
"use strict";
|
||||
function f1(a, x) {
|
||||
var s = a[x]; // boolean
|
||||
}
|
||||
function f2(a, x) {
|
||||
var s = a[x]; // boolean
|
||||
}
|
||||
var container1 = createContainer('hi');
|
||||
var container2 = createContainer(2);
|
||||
f([container1, container2], function (value1, value2) {
|
||||
value1; // string
|
||||
value2; // number
|
||||
});
|
||||
|
||||
|
||||
//// [numericStringLiteralTypes.d.ts]
|
||||
declare type T0 = string & `${string}`;
|
||||
declare type T1 = string & `${number}`;
|
||||
declare type T2 = string & `${bigint}`;
|
||||
declare type T3<T extends string> = string & `${T}`;
|
||||
declare type T4<T extends string> = string & `${Capitalize<`${T}`>}`;
|
||||
declare function f1(a: boolean[], x: `${number}`): void;
|
||||
declare function f2(a: boolean[], x: number | `${number}`): void;
|
||||
declare type T10 = boolean[][`${number}`];
|
||||
declare type T11 = boolean[][number | `${number}`];
|
||||
declare type T20<T extends number | `${number}`> = T;
|
||||
declare type T21<T extends unknown[]> = {
|
||||
[K in keyof T]: T20<K>;
|
||||
};
|
||||
declare type Container<T> = {
|
||||
value: T;
|
||||
};
|
||||
declare type UnwrapContainers<T extends Container<unknown>[]> = {
|
||||
[K in keyof T]: T[K]['value'];
|
||||
};
|
||||
declare function createContainer<T extends unknown>(value: T): Container<T>;
|
||||
declare function f<T extends Container<unknown>[]>(containers: [...T], callback: (...values: UnwrapContainers<T>) => void): void;
|
||||
declare const container1: Container<string>;
|
||||
declare const container2: Container<number>;
|
||||
122
tests/baselines/reference/numericStringLiteralTypes.symbols
Normal file
122
tests/baselines/reference/numericStringLiteralTypes.symbols
Normal file
@@ -0,0 +1,122 @@
|
||||
=== tests/cases/conformance/types/literal/numericStringLiteralTypes.ts ===
|
||||
type T0 = string & `${string}`; // string
|
||||
>T0 : Symbol(T0, Decl(numericStringLiteralTypes.ts, 0, 0))
|
||||
|
||||
type T1 = string & `${number}`; // `${number}
|
||||
>T1 : Symbol(T1, Decl(numericStringLiteralTypes.ts, 0, 31))
|
||||
|
||||
type T2 = string & `${bigint}`; // `${bigint}
|
||||
>T2 : Symbol(T2, Decl(numericStringLiteralTypes.ts, 1, 31))
|
||||
|
||||
type T3<T extends string> = string & `${T}`; // `${T}
|
||||
>T3 : Symbol(T3, Decl(numericStringLiteralTypes.ts, 2, 31))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 3, 8))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 3, 8))
|
||||
|
||||
type T4<T extends string> = string & `${Capitalize<`${T}`>}`; // `${Capitalize<T>}`
|
||||
>T4 : Symbol(T4, Decl(numericStringLiteralTypes.ts, 3, 44))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 4, 8))
|
||||
>Capitalize : Symbol(Capitalize, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 4, 8))
|
||||
|
||||
function f1(a: boolean[], x: `${number}`) {
|
||||
>f1 : Symbol(f1, Decl(numericStringLiteralTypes.ts, 4, 61))
|
||||
>a : Symbol(a, Decl(numericStringLiteralTypes.ts, 6, 12))
|
||||
>x : Symbol(x, Decl(numericStringLiteralTypes.ts, 6, 25))
|
||||
|
||||
let s = a[x]; // boolean
|
||||
>s : Symbol(s, Decl(numericStringLiteralTypes.ts, 7, 7))
|
||||
>a : Symbol(a, Decl(numericStringLiteralTypes.ts, 6, 12))
|
||||
>x : Symbol(x, Decl(numericStringLiteralTypes.ts, 6, 25))
|
||||
}
|
||||
|
||||
function f2(a: boolean[], x: number | `${number}`) {
|
||||
>f2 : Symbol(f2, Decl(numericStringLiteralTypes.ts, 8, 1))
|
||||
>a : Symbol(a, Decl(numericStringLiteralTypes.ts, 10, 12))
|
||||
>x : Symbol(x, Decl(numericStringLiteralTypes.ts, 10, 25))
|
||||
|
||||
let s = a[x]; // boolean
|
||||
>s : Symbol(s, Decl(numericStringLiteralTypes.ts, 11, 7))
|
||||
>a : Symbol(a, Decl(numericStringLiteralTypes.ts, 10, 12))
|
||||
>x : Symbol(x, Decl(numericStringLiteralTypes.ts, 10, 25))
|
||||
}
|
||||
|
||||
type T10 = boolean[][`${number}`]; // boolean
|
||||
>T10 : Symbol(T10, Decl(numericStringLiteralTypes.ts, 12, 1))
|
||||
|
||||
type T11 = boolean[][number | `${number}`]; // boolean
|
||||
>T11 : Symbol(T11, Decl(numericStringLiteralTypes.ts, 14, 34))
|
||||
|
||||
type T20<T extends number | `${number}`> = T;
|
||||
>T20 : Symbol(T20, Decl(numericStringLiteralTypes.ts, 15, 43))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 17, 9))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 17, 9))
|
||||
|
||||
type T21<T extends unknown[]> = { [K in keyof T]: T20<K> };
|
||||
>T21 : Symbol(T21, Decl(numericStringLiteralTypes.ts, 17, 45))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 18, 9))
|
||||
>K : Symbol(K, Decl(numericStringLiteralTypes.ts, 18, 35))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 18, 9))
|
||||
>T20 : Symbol(T20, Decl(numericStringLiteralTypes.ts, 15, 43))
|
||||
>K : Symbol(K, Decl(numericStringLiteralTypes.ts, 18, 35))
|
||||
|
||||
type Container<T> = {
|
||||
>Container : Symbol(Container, Decl(numericStringLiteralTypes.ts, 18, 59))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 20, 15))
|
||||
|
||||
value: T
|
||||
>value : Symbol(value, Decl(numericStringLiteralTypes.ts, 20, 21))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 20, 15))
|
||||
}
|
||||
|
||||
type UnwrapContainers<T extends Container<unknown>[]> = { [K in keyof T]: T[K]['value'] };
|
||||
>UnwrapContainers : Symbol(UnwrapContainers, Decl(numericStringLiteralTypes.ts, 22, 1))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 24, 22))
|
||||
>Container : Symbol(Container, Decl(numericStringLiteralTypes.ts, 18, 59))
|
||||
>K : Symbol(K, Decl(numericStringLiteralTypes.ts, 24, 59))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 24, 22))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 24, 22))
|
||||
>K : Symbol(K, Decl(numericStringLiteralTypes.ts, 24, 59))
|
||||
|
||||
declare function createContainer<T extends unknown>(value: T): Container<T>;
|
||||
>createContainer : Symbol(createContainer, Decl(numericStringLiteralTypes.ts, 24, 90))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 26, 33))
|
||||
>value : Symbol(value, Decl(numericStringLiteralTypes.ts, 26, 52))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 26, 33))
|
||||
>Container : Symbol(Container, Decl(numericStringLiteralTypes.ts, 18, 59))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 26, 33))
|
||||
|
||||
declare function f<T extends Container<unknown>[]>(containers: [...T], callback: (...values: UnwrapContainers<T>) => void): void;
|
||||
>f : Symbol(f, Decl(numericStringLiteralTypes.ts, 26, 76))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 28, 19))
|
||||
>Container : Symbol(Container, Decl(numericStringLiteralTypes.ts, 18, 59))
|
||||
>containers : Symbol(containers, Decl(numericStringLiteralTypes.ts, 28, 51))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 28, 19))
|
||||
>callback : Symbol(callback, Decl(numericStringLiteralTypes.ts, 28, 70))
|
||||
>values : Symbol(values, Decl(numericStringLiteralTypes.ts, 28, 82))
|
||||
>UnwrapContainers : Symbol(UnwrapContainers, Decl(numericStringLiteralTypes.ts, 22, 1))
|
||||
>T : Symbol(T, Decl(numericStringLiteralTypes.ts, 28, 19))
|
||||
|
||||
const container1 = createContainer('hi')
|
||||
>container1 : Symbol(container1, Decl(numericStringLiteralTypes.ts, 30, 5))
|
||||
>createContainer : Symbol(createContainer, Decl(numericStringLiteralTypes.ts, 24, 90))
|
||||
|
||||
const container2 = createContainer(2)
|
||||
>container2 : Symbol(container2, Decl(numericStringLiteralTypes.ts, 31, 5))
|
||||
>createContainer : Symbol(createContainer, Decl(numericStringLiteralTypes.ts, 24, 90))
|
||||
|
||||
f([container1, container2], (value1, value2) => {
|
||||
>f : Symbol(f, Decl(numericStringLiteralTypes.ts, 26, 76))
|
||||
>container1 : Symbol(container1, Decl(numericStringLiteralTypes.ts, 30, 5))
|
||||
>container2 : Symbol(container2, Decl(numericStringLiteralTypes.ts, 31, 5))
|
||||
>value1 : Symbol(value1, Decl(numericStringLiteralTypes.ts, 33, 29))
|
||||
>value2 : Symbol(value2, Decl(numericStringLiteralTypes.ts, 33, 36))
|
||||
|
||||
value1; // string
|
||||
>value1 : Symbol(value1, Decl(numericStringLiteralTypes.ts, 33, 29))
|
||||
|
||||
value2; // number
|
||||
>value2 : Symbol(value2, Decl(numericStringLiteralTypes.ts, 33, 36))
|
||||
|
||||
});
|
||||
|
||||
102
tests/baselines/reference/numericStringLiteralTypes.types
Normal file
102
tests/baselines/reference/numericStringLiteralTypes.types
Normal file
@@ -0,0 +1,102 @@
|
||||
=== tests/cases/conformance/types/literal/numericStringLiteralTypes.ts ===
|
||||
type T0 = string & `${string}`; // string
|
||||
>T0 : string
|
||||
|
||||
type T1 = string & `${number}`; // `${number}
|
||||
>T1 : `${number}`
|
||||
|
||||
type T2 = string & `${bigint}`; // `${bigint}
|
||||
>T2 : `${bigint}`
|
||||
|
||||
type T3<T extends string> = string & `${T}`; // `${T}
|
||||
>T3 : `${T}`
|
||||
|
||||
type T4<T extends string> = string & `${Capitalize<`${T}`>}`; // `${Capitalize<T>}`
|
||||
>T4 : `${Capitalize<`${T}`>}`
|
||||
|
||||
function f1(a: boolean[], x: `${number}`) {
|
||||
>f1 : (a: boolean[], x: `${number}`) => void
|
||||
>a : boolean[]
|
||||
>x : `${number}`
|
||||
|
||||
let s = a[x]; // boolean
|
||||
>s : boolean
|
||||
>a[x] : boolean
|
||||
>a : boolean[]
|
||||
>x : `${number}`
|
||||
}
|
||||
|
||||
function f2(a: boolean[], x: number | `${number}`) {
|
||||
>f2 : (a: boolean[], x: number | `${number}`) => void
|
||||
>a : boolean[]
|
||||
>x : number | `${number}`
|
||||
|
||||
let s = a[x]; // boolean
|
||||
>s : boolean
|
||||
>a[x] : boolean
|
||||
>a : boolean[]
|
||||
>x : number | `${number}`
|
||||
}
|
||||
|
||||
type T10 = boolean[][`${number}`]; // boolean
|
||||
>T10 : boolean
|
||||
|
||||
type T11 = boolean[][number | `${number}`]; // boolean
|
||||
>T11 : boolean
|
||||
|
||||
type T20<T extends number | `${number}`> = T;
|
||||
>T20 : T
|
||||
|
||||
type T21<T extends unknown[]> = { [K in keyof T]: T20<K> };
|
||||
>T21 : T21<T>
|
||||
|
||||
type Container<T> = {
|
||||
>Container : Container<T>
|
||||
|
||||
value: T
|
||||
>value : T
|
||||
}
|
||||
|
||||
type UnwrapContainers<T extends Container<unknown>[]> = { [K in keyof T]: T[K]['value'] };
|
||||
>UnwrapContainers : UnwrapContainers<T>
|
||||
|
||||
declare function createContainer<T extends unknown>(value: T): Container<T>;
|
||||
>createContainer : <T extends unknown>(value: T) => Container<T>
|
||||
>value : T
|
||||
|
||||
declare function f<T extends Container<unknown>[]>(containers: [...T], callback: (...values: UnwrapContainers<T>) => void): void;
|
||||
>f : <T extends Container<unknown>[]>(containers: [...T], callback: (...values: UnwrapContainers<T>) => void) => void
|
||||
>containers : [...T]
|
||||
>callback : (...values: UnwrapContainers<T>) => void
|
||||
>values : UnwrapContainers<T>
|
||||
|
||||
const container1 = createContainer('hi')
|
||||
>container1 : Container<string>
|
||||
>createContainer('hi') : Container<string>
|
||||
>createContainer : <T extends unknown>(value: T) => Container<T>
|
||||
>'hi' : "hi"
|
||||
|
||||
const container2 = createContainer(2)
|
||||
>container2 : Container<number>
|
||||
>createContainer(2) : Container<number>
|
||||
>createContainer : <T extends unknown>(value: T) => Container<T>
|
||||
>2 : 2
|
||||
|
||||
f([container1, container2], (value1, value2) => {
|
||||
>f([container1, container2], (value1, value2) => { value1; // string value2; // number}) : void
|
||||
>f : <T extends Container<unknown>[]>(containers: [...T], callback: (...values: UnwrapContainers<T>) => void) => void
|
||||
>[container1, container2] : [Container<string>, Container<number>]
|
||||
>container1 : Container<string>
|
||||
>container2 : Container<number>
|
||||
>(value1, value2) => { value1; // string value2; // number} : (value1: string, value2: number) => void
|
||||
>value1 : string
|
||||
>value2 : number
|
||||
|
||||
value1; // string
|
||||
>value1 : string
|
||||
|
||||
value2; // number
|
||||
>value2 : number
|
||||
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ tests/cases/conformance/types/literal/templateLiteralTypes1.ts(165,15): error TS
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(197,16): error TS2590: Expression produces a union type that is too complex to represent.
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(201,16): error TS2590: Expression produces a union type that is too complex to represent.
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(205,16): error TS2590: Expression produces a union type that is too complex to represent.
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(251,7): error TS2590: Expression produces a union type that is too complex to represent.
|
||||
tests/cases/conformance/types/literal/templateLiteralTypes1.ts(252,7): error TS2590: Expression produces a union type that is too complex to represent.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/literal/templateLiteralTypes1.ts (7 errors) ====
|
||||
@@ -242,6 +242,7 @@ tests/cases/conformance/types/literal/templateLiteralTypes1.ts(251,7): error TS2
|
||||
// Repro from #40970
|
||||
|
||||
type PathKeys<T> =
|
||||
unknown extends T ? never :
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> :
|
||||
never;
|
||||
|
||||
@@ -217,6 +217,7 @@ type BB = AA<-2, -2>;
|
||||
// Repro from #40970
|
||||
|
||||
type PathKeys<T> =
|
||||
unknown extends T ? never :
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> :
|
||||
never;
|
||||
|
||||
@@ -878,11 +878,14 @@ type PathKeys<T> =
|
||||
>PathKeys : Symbol(PathKeys, Decl(templateLiteralTypes1.ts, 213, 21))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
|
||||
unknown extends T ? never :
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>SubKeys : Symbol(SubKeys, Decl(templateLiteralTypes1.ts, 220, 10))
|
||||
>SubKeys : Symbol(SubKeys, Decl(templateLiteralTypes1.ts, 221, 10))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
@@ -891,7 +894,7 @@ type PathKeys<T> =
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>SubKeys : Symbol(SubKeys, Decl(templateLiteralTypes1.ts, 220, 10))
|
||||
>SubKeys : Symbol(SubKeys, Decl(templateLiteralTypes1.ts, 221, 10))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
@@ -899,63 +902,63 @@ type PathKeys<T> =
|
||||
never;
|
||||
|
||||
type SubKeys<T, K extends string> = K extends keyof T ? `${K}.${PathKeys<T[K]>}` : never;
|
||||
>SubKeys : Symbol(SubKeys, Decl(templateLiteralTypes1.ts, 220, 10))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 222, 13))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 222, 15))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 222, 15))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 222, 13))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 222, 15))
|
||||
>SubKeys : Symbol(SubKeys, Decl(templateLiteralTypes1.ts, 221, 10))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 223, 13))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 223, 15))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 223, 15))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 223, 13))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 223, 15))
|
||||
>PathKeys : Symbol(PathKeys, Decl(templateLiteralTypes1.ts, 213, 21))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 222, 13))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 222, 15))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 223, 13))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 223, 15))
|
||||
|
||||
declare function getProp2<T, P extends PathKeys<T>>(obj: T, path: P): PropType<T, P>;
|
||||
>getProp2 : Symbol(getProp2, Decl(templateLiteralTypes1.ts, 222, 89))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 224, 26))
|
||||
>P : Symbol(P, Decl(templateLiteralTypes1.ts, 224, 28))
|
||||
>getProp2 : Symbol(getProp2, Decl(templateLiteralTypes1.ts, 223, 89))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 225, 26))
|
||||
>P : Symbol(P, Decl(templateLiteralTypes1.ts, 225, 28))
|
||||
>PathKeys : Symbol(PathKeys, Decl(templateLiteralTypes1.ts, 213, 21))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 224, 26))
|
||||
>obj : Symbol(obj, Decl(templateLiteralTypes1.ts, 224, 52))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 224, 26))
|
||||
>path : Symbol(path, Decl(templateLiteralTypes1.ts, 224, 59))
|
||||
>P : Symbol(P, Decl(templateLiteralTypes1.ts, 224, 28))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 225, 26))
|
||||
>obj : Symbol(obj, Decl(templateLiteralTypes1.ts, 225, 52))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 225, 26))
|
||||
>path : Symbol(path, Decl(templateLiteralTypes1.ts, 225, 59))
|
||||
>P : Symbol(P, Decl(templateLiteralTypes1.ts, 225, 28))
|
||||
>PropType : Symbol(PropType, Decl(templateLiteralTypes1.ts, 138, 69))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 224, 26))
|
||||
>P : Symbol(P, Decl(templateLiteralTypes1.ts, 224, 28))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 225, 26))
|
||||
>P : Symbol(P, Decl(templateLiteralTypes1.ts, 225, 28))
|
||||
|
||||
const obj2 = {
|
||||
>obj2 : Symbol(obj2, Decl(templateLiteralTypes1.ts, 226, 5))
|
||||
>obj2 : Symbol(obj2, Decl(templateLiteralTypes1.ts, 227, 5))
|
||||
|
||||
name: 'John',
|
||||
>name : Symbol(name, Decl(templateLiteralTypes1.ts, 226, 14))
|
||||
>name : Symbol(name, Decl(templateLiteralTypes1.ts, 227, 14))
|
||||
|
||||
age: 42,
|
||||
>age : Symbol(age, Decl(templateLiteralTypes1.ts, 227, 17))
|
||||
>age : Symbol(age, Decl(templateLiteralTypes1.ts, 228, 17))
|
||||
|
||||
cars: [
|
||||
>cars : Symbol(cars, Decl(templateLiteralTypes1.ts, 228, 12))
|
||||
>cars : Symbol(cars, Decl(templateLiteralTypes1.ts, 229, 12))
|
||||
|
||||
{ make: 'Ford', age: 10 },
|
||||
>make : Symbol(make, Decl(templateLiteralTypes1.ts, 230, 9))
|
||||
>age : Symbol(age, Decl(templateLiteralTypes1.ts, 230, 23))
|
||||
>make : Symbol(make, Decl(templateLiteralTypes1.ts, 231, 9))
|
||||
>age : Symbol(age, Decl(templateLiteralTypes1.ts, 231, 23))
|
||||
|
||||
{ make: 'Trabant', age: 35 }
|
||||
>make : Symbol(make, Decl(templateLiteralTypes1.ts, 231, 9))
|
||||
>age : Symbol(age, Decl(templateLiteralTypes1.ts, 231, 26))
|
||||
>make : Symbol(make, Decl(templateLiteralTypes1.ts, 232, 9))
|
||||
>age : Symbol(age, Decl(templateLiteralTypes1.ts, 232, 26))
|
||||
|
||||
]
|
||||
} as const;
|
||||
>const : Symbol(const)
|
||||
|
||||
let make = getProp2(obj2, 'cars.1.make'); // 'Trabant'
|
||||
>make : Symbol(make, Decl(templateLiteralTypes1.ts, 235, 3))
|
||||
>getProp2 : Symbol(getProp2, Decl(templateLiteralTypes1.ts, 222, 89))
|
||||
>obj2 : Symbol(obj2, Decl(templateLiteralTypes1.ts, 226, 5))
|
||||
>make : Symbol(make, Decl(templateLiteralTypes1.ts, 236, 3))
|
||||
>getProp2 : Symbol(getProp2, Decl(templateLiteralTypes1.ts, 223, 89))
|
||||
>obj2 : Symbol(obj2, Decl(templateLiteralTypes1.ts, 227, 5))
|
||||
|
||||
// Repro from #46480
|
||||
|
||||
export type Spacing =
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
|
||||
| `0`
|
||||
| `${number}px`
|
||||
@@ -963,28 +966,28 @@ export type Spacing =
|
||||
| `s${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20}`;
|
||||
|
||||
const spacing: Spacing = "s12"
|
||||
>spacing : Symbol(spacing, Decl(templateLiteralTypes1.ts, 245, 5))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>spacing : Symbol(spacing, Decl(templateLiteralTypes1.ts, 246, 5))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
|
||||
export type SpacingShorthand =
|
||||
>SpacingShorthand : Symbol(SpacingShorthand, Decl(templateLiteralTypes1.ts, 245, 30))
|
||||
>SpacingShorthand : Symbol(SpacingShorthand, Decl(templateLiteralTypes1.ts, 246, 30))
|
||||
|
||||
| `${Spacing} ${Spacing}`
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
|
||||
| `${Spacing} ${Spacing} ${Spacing}`
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
|
||||
| `${Spacing} ${Spacing} ${Spacing} ${Spacing}`;
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 235, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
>Spacing : Symbol(Spacing, Decl(templateLiteralTypes1.ts, 236, 41))
|
||||
|
||||
const test1: SpacingShorthand = "0 0 0";
|
||||
>test1 : Symbol(test1, Decl(templateLiteralTypes1.ts, 252, 5))
|
||||
>SpacingShorthand : Symbol(SpacingShorthand, Decl(templateLiteralTypes1.ts, 245, 30))
|
||||
>test1 : Symbol(test1, Decl(templateLiteralTypes1.ts, 253, 5))
|
||||
>SpacingShorthand : Symbol(SpacingShorthand, Decl(templateLiteralTypes1.ts, 246, 30))
|
||||
|
||||
|
||||
@@ -541,6 +541,7 @@ type BB = AA<-2, -2>;
|
||||
type PathKeys<T> =
|
||||
>PathKeys : PathKeys<T>
|
||||
|
||||
unknown extends T ? never :
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> :
|
||||
never;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// @strict: true
|
||||
// @declaration: true
|
||||
|
||||
type T0 = string & `${string}`; // string
|
||||
type T1 = string & `${number}`; // `${number}
|
||||
type T2 = string & `${bigint}`; // `${bigint}
|
||||
type T3<T extends string> = string & `${T}`; // `${T}
|
||||
type T4<T extends string> = string & `${Capitalize<`${T}`>}`; // `${Capitalize<T>}`
|
||||
|
||||
function f1(a: boolean[], x: `${number}`) {
|
||||
let s = a[x]; // boolean
|
||||
}
|
||||
|
||||
function f2(a: boolean[], x: number | `${number}`) {
|
||||
let s = a[x]; // boolean
|
||||
}
|
||||
|
||||
type T10 = boolean[][`${number}`]; // boolean
|
||||
type T11 = boolean[][number | `${number}`]; // boolean
|
||||
|
||||
type T20<T extends number | `${number}`> = T;
|
||||
type T21<T extends unknown[]> = { [K in keyof T]: T20<K> };
|
||||
|
||||
type Container<T> = {
|
||||
value: T
|
||||
}
|
||||
|
||||
type UnwrapContainers<T extends Container<unknown>[]> = { [K in keyof T]: T[K]['value'] };
|
||||
|
||||
declare function createContainer<T extends unknown>(value: T): Container<T>;
|
||||
|
||||
declare function f<T extends Container<unknown>[]>(containers: [...T], callback: (...values: UnwrapContainers<T>) => void): void;
|
||||
|
||||
const container1 = createContainer('hi')
|
||||
const container2 = createContainer(2)
|
||||
|
||||
f([container1, container2], (value1, value2) => {
|
||||
value1; // string
|
||||
value2; // number
|
||||
});
|
||||
@@ -219,6 +219,7 @@ type BB = AA<-2, -2>;
|
||||
// Repro from #40970
|
||||
|
||||
type PathKeys<T> =
|
||||
unknown extends T ? never :
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> :
|
||||
never;
|
||||
|
||||
Reference in New Issue
Block a user