Allow nongeneric string mapping types to exist (#47050)

* Allow nongeneric string mapping types to exist

* Accept baseline

* Recusive membership testing function

* Fix lint

* Add @DanielRosenwasser's comment
This commit is contained in:
Wesley Wigham 2022-06-16 17:02:31 -07:00 committed by GitHub
parent 86d5040031
commit 5c4caafc2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1731 additions and 57 deletions

View File

@ -12182,7 +12182,7 @@ namespace ts {
}
if (t.flags & TypeFlags.StringMapping) {
const constraint = getBaseConstraint((t as StringMappingType).type);
return constraint ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType;
return constraint && constraint !== (t as StringMappingType).type ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType;
}
if (t.flags & TypeFlags.IndexedAccess) {
if (isMappedTypeGenericIndexedAccess(t)) {
@ -15381,8 +15381,11 @@ namespace ts {
function getStringMappingType(symbol: Symbol, type: Type): Type {
return type.flags & (TypeFlags.Union | TypeFlags.Never) ? mapType(type, t => getStringMappingType(symbol, t)) :
isGenericIndexType(type) ? getStringMappingTypeForGenericType(symbol, type) :
// Mapping<Mapping<T>> === Mapping<T>
type.flags & TypeFlags.StringMapping && symbol === type.symbol ? type :
isGenericIndexType(type) || isPatternLiteralPlaceholderType(type) ? getStringMappingTypeForGenericType(symbol, isPatternLiteralPlaceholderType(type) && !(type.flags & TypeFlags.StringMapping) ? getTemplateLiteralType(["", ""], [type]) : type) :
type.flags & TypeFlags.StringLiteral ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) :
type.flags & TypeFlags.TemplateLiteral ? getTemplateLiteralType(...applyTemplateStringMapping(symbol, (type as TemplateLiteralType).texts, (type as TemplateLiteralType).types)) :
type;
}
@ -15396,6 +15399,16 @@ namespace ts {
return str;
}
function applyTemplateStringMapping(symbol: Symbol, texts: readonly string[], types: readonly Type[]): [texts: readonly string[], types: readonly Type[]] {
switch (intrinsicTypeKinds.get(symbol.escapedName as string)) {
case IntrinsicTypeKind.Uppercase: return [texts.map(t => t.toUpperCase()), types.map(t => getStringMappingType(symbol, t))];
case IntrinsicTypeKind.Lowercase: return [texts.map(t => t.toLowerCase()), types.map(t => getStringMappingType(symbol, t))];
case IntrinsicTypeKind.Capitalize: return [texts[0] === "" ? texts : [texts[0].charAt(0).toUpperCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types];
case IntrinsicTypeKind.Uncapitalize: return [texts[0] === "" ? texts : [texts[0].charAt(0).toLowerCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types];
}
return [texts, types];
}
function getStringMappingTypeForGenericType(symbol: Symbol, type: Type): Type {
const id = `${getSymbolId(symbol)},${getTypeId(type)}`;
let result = stringMappingTypes.get(id);
@ -15651,8 +15664,8 @@ namespace ts {
accessNode;
}
function isPatternLiteralPlaceholderType(type: Type) {
return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt));
function isPatternLiteralPlaceholderType(type: Type): boolean {
return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || !!(type.flags & TypeFlags.StringMapping && isPatternLiteralPlaceholderType((type as StringMappingType).type));
}
function isPatternLiteralType(type: Type) {
@ -19613,6 +19626,13 @@ namespace ts {
return Ternary.True;
}
}
else if (target.flags & TypeFlags.StringMapping) {
if (!(source.flags & TypeFlags.StringMapping)) {
if (isMemberOfStringMapping(source, target)) {
return Ternary.True;
}
}
}
if (sourceFlags & TypeFlags.TypeVariable) {
// IndexedAccess comparisons are handled above in the `targetFlags & TypeFlage.IndexedAccess` branch
@ -19657,7 +19677,10 @@ namespace ts {
}
}
else if (sourceFlags & TypeFlags.StringMapping) {
if (targetFlags & TypeFlags.StringMapping && (source as StringMappingType).symbol === (target as StringMappingType).symbol) {
if (targetFlags & TypeFlags.StringMapping) {
if ((source as StringMappingType).symbol !== (target as StringMappingType).symbol) {
return Ternary.False;
}
if (result = isRelatedTo((source as StringMappingType).type, (target as StringMappingType).type, RecursionFlags.Both, reportErrors)) {
resetErrorInfo(saveErrorInfo);
return result;
@ -20611,7 +20634,7 @@ namespace ts {
}
}
return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral);
return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral) || !!(type.flags & TypeFlags.StringMapping);
}
function getExactOptionalUnassignableProperties(source: Type, target: Type) {
@ -22171,6 +22194,32 @@ namespace ts {
&& (!roundTripOnly || s === pseudoBigIntToString({ negative, base10Value: parsePseudoBigInt(scanner.getTokenValue()) }));
}
function isMemberOfStringMapping(source: Type, target: Type): boolean {
if (target.flags & (TypeFlags.String | TypeFlags.AnyOrUnknown)) {
return true;
}
if (target.flags & TypeFlags.TemplateLiteral) {
return isTypeAssignableTo(source, target);
}
if (target.flags & TypeFlags.StringMapping) {
// We need to see whether applying the same mappings of the target
// onto the source would produce an identical type *and* that
// it's compatible with the inner-most non-string-mapped type.
//
// The intuition here is that if same mappings don't affect the source at all,
// and the source is compatible with the unmapped target, then they must
// still reside in the same domain.
const mappingStack = [];
while (target.flags & TypeFlags.StringMapping) {
mappingStack.unshift(target.symbol);
target = (target as StringMappingType).type;
}
const mappedSource = reduceLeft(mappingStack, (memo, value) => getStringMappingType(value, memo), source);
return mappedSource === source && isMemberOfStringMapping(source, target);
}
return false;
}
function isValidTypeForTemplateLiteralPlaceholder(source: Type, target: Type): boolean {
if (source === target || target.flags & (TypeFlags.Any | TypeFlags.String)) {
return true;
@ -22179,7 +22228,8 @@ namespace ts {
const value = (source as StringLiteralType).value;
return !!(target.flags & TypeFlags.Number && isValidNumberString(value, /*roundTripOnly*/ false) ||
target.flags & TypeFlags.BigInt && isValidBigIntString(value, /*roundTripOnly*/ false) ||
target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName);
target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName ||
target.flags & TypeFlags.StringMapping && isMemberOfStringMapping(getStringLiteralType(value), target));
}
if (source.flags & TypeFlags.TemplateLiteral) {
const texts = (source as TemplateLiteralType).texts;

View File

@ -13,8 +13,8 @@ tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(43,5): error TS2322:
==== tests/cases/conformance/types/typeAliases/intrinsicTypes.ts (8 errors) ====
type TU1 = Uppercase<'hello'>; // "HELLO"
type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR"
type TU3 = Uppercase<string>; // string
type TU4 = Uppercase<any>; // any
type TU3 = Uppercase<string>; // Uppercase<string>
type TU4 = Uppercase<any>; // Uppercase<`${any}`>
type TU5 = Uppercase<never>; // never
type TU6 = Uppercase<42>; // Error
~~
@ -22,8 +22,8 @@ tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(43,5): error TS2322:
type TL1 = Lowercase<'HELLO'>; // "hello"
type TL2 = Lowercase<'FOO' | 'BAR'>; // "foo" | "bar"
type TL3 = Lowercase<string>; // string
type TL4 = Lowercase<any>; // any
type TL3 = Lowercase<string>; // Lowercase<string>
type TL4 = Lowercase<any>; // Lowercase<`${any}`>
type TL5 = Lowercase<never>; // never
type TL6 = Lowercase<42>; // Error
~~
@ -31,8 +31,8 @@ tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(43,5): error TS2322:
type TC1 = Capitalize<'hello'>; // "Hello"
type TC2 = Capitalize<'foo' | 'bar'>; // "Foo" | "Bar"
type TC3 = Capitalize<string>; // string
type TC4 = Capitalize<any>; // any
type TC3 = Capitalize<string>; // Capitalize<string>
type TC4 = Capitalize<any>; // Capitalize<`${any}`>
type TC5 = Capitalize<never>; // never
type TC6 = Capitalize<42>; // Error
~~
@ -40,8 +40,8 @@ tests/cases/conformance/types/typeAliases/intrinsicTypes.ts(43,5): error TS2322:
type TN1 = Uncapitalize<'Hello'>; // "hello"
type TN2 = Uncapitalize<'Foo' | 'Bar'>; // "foo" | "bar"
type TN3 = Uncapitalize<string>; // string
type TN4 = Uncapitalize<any>; // any
type TN3 = Uncapitalize<string>; // Uncapitalize<string>
type TN4 = Uncapitalize<any>; // Uncapitalize<`${any}`>
type TN5 = Uncapitalize<never>; // never
type TN6 = Uncapitalize<42>; // Error
~~

View File

@ -1,29 +1,29 @@
//// [intrinsicTypes.ts]
type TU1 = Uppercase<'hello'>; // "HELLO"
type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR"
type TU3 = Uppercase<string>; // string
type TU4 = Uppercase<any>; // any
type TU3 = Uppercase<string>; // Uppercase<string>
type TU4 = Uppercase<any>; // Uppercase<`${any}`>
type TU5 = Uppercase<never>; // never
type TU6 = Uppercase<42>; // Error
type TL1 = Lowercase<'HELLO'>; // "hello"
type TL2 = Lowercase<'FOO' | 'BAR'>; // "foo" | "bar"
type TL3 = Lowercase<string>; // string
type TL4 = Lowercase<any>; // any
type TL3 = Lowercase<string>; // Lowercase<string>
type TL4 = Lowercase<any>; // Lowercase<`${any}`>
type TL5 = Lowercase<never>; // never
type TL6 = Lowercase<42>; // Error
type TC1 = Capitalize<'hello'>; // "Hello"
type TC2 = Capitalize<'foo' | 'bar'>; // "Foo" | "Bar"
type TC3 = Capitalize<string>; // string
type TC4 = Capitalize<any>; // any
type TC3 = Capitalize<string>; // Capitalize<string>
type TC4 = Capitalize<any>; // Capitalize<`${any}`>
type TC5 = Capitalize<never>; // never
type TC6 = Capitalize<42>; // Error
type TN1 = Uncapitalize<'Hello'>; // "hello"
type TN2 = Uncapitalize<'Foo' | 'Bar'>; // "foo" | "bar"
type TN3 = Uncapitalize<string>; // string
type TN4 = Uncapitalize<any>; // any
type TN3 = Uncapitalize<string>; // Uncapitalize<string>
type TN4 = Uncapitalize<any>; // Uncapitalize<`${any}`>
type TN5 = Uncapitalize<never>; // never
type TN6 = Uncapitalize<42>; // Error

View File

@ -7,11 +7,11 @@ type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR"
>TU2 : Symbol(TU2, Decl(intrinsicTypes.ts, 0, 30))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
type TU3 = Uppercase<string>; // string
type TU3 = Uppercase<string>; // Uppercase<string>
>TU3 : Symbol(TU3, Decl(intrinsicTypes.ts, 1, 36))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
type TU4 = Uppercase<any>; // any
type TU4 = Uppercase<any>; // Uppercase<`${any}`>
>TU4 : Symbol(TU4, Decl(intrinsicTypes.ts, 2, 29))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
@ -31,11 +31,11 @@ type TL2 = Lowercase<'FOO' | 'BAR'>; // "foo" | "bar"
>TL2 : Symbol(TL2, Decl(intrinsicTypes.ts, 7, 30))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
type TL3 = Lowercase<string>; // string
type TL3 = Lowercase<string>; // Lowercase<string>
>TL3 : Symbol(TL3, Decl(intrinsicTypes.ts, 8, 36))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
type TL4 = Lowercase<any>; // any
type TL4 = Lowercase<any>; // Lowercase<`${any}`>
>TL4 : Symbol(TL4, Decl(intrinsicTypes.ts, 9, 29))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
@ -55,11 +55,11 @@ type TC2 = Capitalize<'foo' | 'bar'>; // "Foo" | "Bar"
>TC2 : Symbol(TC2, Decl(intrinsicTypes.ts, 14, 31))
>Capitalize : Symbol(Capitalize, Decl(lib.es5.d.ts, --, --))
type TC3 = Capitalize<string>; // string
type TC3 = Capitalize<string>; // Capitalize<string>
>TC3 : Symbol(TC3, Decl(intrinsicTypes.ts, 15, 37))
>Capitalize : Symbol(Capitalize, Decl(lib.es5.d.ts, --, --))
type TC4 = Capitalize<any>; // any
type TC4 = Capitalize<any>; // Capitalize<`${any}`>
>TC4 : Symbol(TC4, Decl(intrinsicTypes.ts, 16, 30))
>Capitalize : Symbol(Capitalize, Decl(lib.es5.d.ts, --, --))
@ -79,11 +79,11 @@ type TN2 = Uncapitalize<'Foo' | 'Bar'>; // "foo" | "bar"
>TN2 : Symbol(TN2, Decl(intrinsicTypes.ts, 21, 33))
>Uncapitalize : Symbol(Uncapitalize, Decl(lib.es5.d.ts, --, --))
type TN3 = Uncapitalize<string>; // string
type TN3 = Uncapitalize<string>; // Uncapitalize<string>
>TN3 : Symbol(TN3, Decl(intrinsicTypes.ts, 22, 39))
>Uncapitalize : Symbol(Uncapitalize, Decl(lib.es5.d.ts, --, --))
type TN4 = Uncapitalize<any>; // any
type TN4 = Uncapitalize<any>; // Uncapitalize<`${any}`>
>TN4 : Symbol(TN4, Decl(intrinsicTypes.ts, 23, 32))
>Uncapitalize : Symbol(Uncapitalize, Decl(lib.es5.d.ts, --, --))

View File

@ -5,11 +5,11 @@ type TU1 = Uppercase<'hello'>; // "HELLO"
type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR"
>TU2 : "FOO" | "BAR"
type TU3 = Uppercase<string>; // string
>TU3 : string
type TU3 = Uppercase<string>; // Uppercase<string>
>TU3 : Uppercase<string>
type TU4 = Uppercase<any>; // any
>TU4 : any
type TU4 = Uppercase<any>; // Uppercase<`${any}`>
>TU4 : Uppercase<`${any}`>
type TU5 = Uppercase<never>; // never
>TU5 : never
@ -23,11 +23,11 @@ type TL1 = Lowercase<'HELLO'>; // "hello"
type TL2 = Lowercase<'FOO' | 'BAR'>; // "foo" | "bar"
>TL2 : "foo" | "bar"
type TL3 = Lowercase<string>; // string
>TL3 : string
type TL3 = Lowercase<string>; // Lowercase<string>
>TL3 : Lowercase<string>
type TL4 = Lowercase<any>; // any
>TL4 : any
type TL4 = Lowercase<any>; // Lowercase<`${any}`>
>TL4 : Lowercase<`${any}`>
type TL5 = Lowercase<never>; // never
>TL5 : never
@ -41,11 +41,11 @@ type TC1 = Capitalize<'hello'>; // "Hello"
type TC2 = Capitalize<'foo' | 'bar'>; // "Foo" | "Bar"
>TC2 : "Foo" | "Bar"
type TC3 = Capitalize<string>; // string
>TC3 : string
type TC3 = Capitalize<string>; // Capitalize<string>
>TC3 : Capitalize<string>
type TC4 = Capitalize<any>; // any
>TC4 : any
type TC4 = Capitalize<any>; // Capitalize<`${any}`>
>TC4 : Capitalize<`${any}`>
type TC5 = Capitalize<never>; // never
>TC5 : never
@ -59,11 +59,11 @@ type TN1 = Uncapitalize<'Hello'>; // "hello"
type TN2 = Uncapitalize<'Foo' | 'Bar'>; // "foo" | "bar"
>TN2 : "foo" | "bar"
type TN3 = Uncapitalize<string>; // string
>TN3 : string
type TN3 = Uncapitalize<string>; // Uncapitalize<string>
>TN3 : Uncapitalize<string>
type TN4 = Uncapitalize<any>; // any
>TN4 : any
type TN4 = Uncapitalize<any>; // Uncapitalize<`${any}`>
>TN4 : Uncapitalize<`${any}`>
type TN5 = Uncapitalize<never>; // never
>TN5 : never

View File

@ -1,7 +1,8 @@
tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(10,11): error TS2322: Type 'Mapped2<K>[`get${K}`]' is not assignable to type '{ a: K; }'.
Type 'Mapped2<K>[`get${string}`]' is not assignable to type '{ a: K; }'.
tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(16,11): error TS2322: Type 'Mapped3<K>[Uppercase<K>]' is not assignable to type '{ a: K; }'.
Type 'Mapped3<K>[string]' is not assignable to type '{ a: K; }'.
Type 'Mapped3<K>[Uppercase<string>]' is not assignable to type '{ a: K; }'.
Type 'Mapped3<K>[string]' is not assignable to type '{ a: K; }'.
tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo<T>[`get${T}`]'.
@ -28,7 +29,8 @@ tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(25,57): error TS2
const x: { a: K } = obj[key]; // Error
~
!!! error TS2322: Type 'Mapped3<K>[Uppercase<K>]' is not assignable to type '{ a: K; }'.
!!! error TS2322: Type 'Mapped3<K>[string]' is not assignable to type '{ a: K; }'.
!!! error TS2322: Type 'Mapped3<K>[Uppercase<string>]' is not assignable to type '{ a: K; }'.
!!! error TS2322: Type 'Mapped3<K>[string]' is not assignable to type '{ a: K; }'.
}
// Repro from #47794

View File

@ -0,0 +1,28 @@
tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts(7,1): error TS2322: Type 'string' is not assignable to type 'Uppercase<Lowercase<string>>'.
tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts(15,1): error TS2322: Type 'string' is not assignable to type 'Uppercase<`${Lowercase<`${number}`>}`>'.
tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts(16,1): error TS2322: Type 'string' is not assignable to type 'Uppercase<`${Lowercase<`${number}`>}`>'.
==== tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts (3 errors) ====
declare var x: Uppercase<Lowercase<string>>;
// good
x = "A";
// bad
x = "a";
~
!!! error TS2322: Type 'string' is not assignable to type 'Uppercase<Lowercase<string>>'.
declare var y: Uppercase<Lowercase<`${number}`>>;
// good
y = "1";
// bad
y = "a";
~
!!! error TS2322: Type 'string' is not assignable to type 'Uppercase<`${Lowercase<`${number}`>}`>'.
y = "A";
~
!!! error TS2322: Type 'string' is not assignable to type 'Uppercase<`${Lowercase<`${number}`>}`>'.

View File

@ -0,0 +1,28 @@
//// [stringLiteralsAssignedToStringMappings.ts]
declare var x: Uppercase<Lowercase<string>>;
// good
x = "A";
// bad
x = "a";
declare var y: Uppercase<Lowercase<`${number}`>>;
// good
y = "1";
// bad
y = "a";
y = "A";
//// [stringLiteralsAssignedToStringMappings.js]
// good
x = "A";
// bad
x = "a";
// good
y = "1";
// bad
y = "a";
y = "A";

View File

@ -0,0 +1,30 @@
=== tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts ===
declare var x: Uppercase<Lowercase<string>>;
>x : Symbol(x, Decl(stringLiteralsAssignedToStringMappings.ts, 0, 11))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
// good
x = "A";
>x : Symbol(x, Decl(stringLiteralsAssignedToStringMappings.ts, 0, 11))
// bad
x = "a";
>x : Symbol(x, Decl(stringLiteralsAssignedToStringMappings.ts, 0, 11))
declare var y: Uppercase<Lowercase<`${number}`>>;
>y : Symbol(y, Decl(stringLiteralsAssignedToStringMappings.ts, 8, 11))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
// good
y = "1";
>y : Symbol(y, Decl(stringLiteralsAssignedToStringMappings.ts, 8, 11))
// bad
y = "a";
>y : Symbol(y, Decl(stringLiteralsAssignedToStringMappings.ts, 8, 11))
y = "A";
>y : Symbol(y, Decl(stringLiteralsAssignedToStringMappings.ts, 8, 11))

View File

@ -0,0 +1,36 @@
=== tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts ===
declare var x: Uppercase<Lowercase<string>>;
>x : Uppercase<Lowercase<string>>
// good
x = "A";
>x = "A" : "A"
>x : Uppercase<Lowercase<string>>
>"A" : "A"
// bad
x = "a";
>x = "a" : "a"
>x : Uppercase<Lowercase<string>>
>"a" : "a"
declare var y: Uppercase<Lowercase<`${number}`>>;
>y : Uppercase<`${Lowercase<`${number}`>}`>
// good
y = "1";
>y = "1" : "1"
>y : Uppercase<`${Lowercase<`${number}`>}`>
>"1" : "1"
// bad
y = "a";
>y = "a" : "a"
>y : Uppercase<`${Lowercase<`${number}`>}`>
>"a" : "a"
y = "A";
>y = "A" : "A"
>y : Uppercase<`${Lowercase<`${number}`>}`>
>"A" : "A"

View File

@ -0,0 +1,250 @@
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(25,5): error TS2322: Type '`aA${string}`' is not assignable to type '"aA"'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(26,5): error TS2322: Type '`AA${Uppercase<string>}`' is not assignable to type '"AA"'.
Type '`AA${string}`' is not assignable to type '"AA"'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(27,5): error TS2322: Type '`aa${Lowercase<string>}`' is not assignable to type '"aa"'.
Type '`aa${string}`' is not assignable to type '"aa"'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(30,5): error TS2322: Type '`AA${Uppercase<string>}`' is not assignable to type '`aA${string}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(31,5): error TS2322: Type '`aa${Lowercase<string>}`' is not assignable to type '`aA${string}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(33,5): error TS2322: Type '`aA${string}`' is not assignable to type '`AA${Uppercase<string>}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(34,5): error TS2322: Type '`aa${Lowercase<string>}`' is not assignable to type '`AA${Uppercase<string>}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(36,5): error TS2322: Type '`aA${string}`' is not assignable to type '`aa${Lowercase<string>}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(37,5): error TS2322: Type '`AA${Uppercase<string>}`' is not assignable to type '`aa${Lowercase<string>}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(51,5): error TS2322: Type 'string' is not assignable to type 'Uppercase<string>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(52,5): error TS2322: Type 'Lowercase<string>' is not assignable to type 'Uppercase<string>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(53,5): error TS2322: Type 'string' is not assignable to type 'Lowercase<string>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(54,5): error TS2322: Type 'Uppercase<string>' is not assignable to type 'Lowercase<string>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(56,5): error TS2322: Type 'string' is not assignable to type 'Uppercase<string>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(57,5): error TS2322: Type 'string' is not assignable to type 'Lowercase<string>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(78,5): error TS2322: Type 'Uppercase<string>' is not assignable to type 'Uppercase<Lowercase<string>>'.
Type 'string' is not assignable to type 'Lowercase<string>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(79,5): error TS2322: Type 'Uppercase<string>' is not assignable to type 'Uppercase<Lowercase<string>>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(83,5): error TS2322: Type 'Lowercase<Uppercase<string>>' is not assignable to type 'Uppercase<string>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(84,5): error TS2322: Type 'Lowercase<Uppercase<string>>' is not assignable to type 'Uppercase<string>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(85,5): error TS2322: Type 'Lowercase<Uppercase<string>>' is not assignable to type 'Uppercase<Lowercase<string>>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(87,5): error TS2322: Type 'Uppercase<string>' is not assignable to type 'Lowercase<Uppercase<string>>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(88,5): error TS2322: Type 'Uppercase<string>' is not assignable to type 'Lowercase<Uppercase<string>>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(89,5): error TS2322: Type 'Uppercase<Lowercase<string>>' is not assignable to type 'Lowercase<Uppercase<string>>'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(129,5): error TS2322: Type 'Capitalize<string>' is not assignable to type '`A${string}`'.
Type 'string' is not assignable to type '`A${string}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(130,5): error TS2322: Type 'Capitalize<string>' is not assignable to type '`A${string}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(131,5): error TS2322: Type 'Capitalize<string>' is not assignable to type '`A${string}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(147,5): error TS2322: Type 'Uncapitalize<string>' is not assignable to type '`a${string}`'.
Type 'string' is not assignable to type '`a${string}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(148,5): error TS2322: Type 'Uncapitalize<string>' is not assignable to type '`a${string}`'.
tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(149,5): error TS2322: Type 'Uncapitalize<string>' is not assignable to type '`a${string}`'.
==== tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts (29 errors) ====
// non-template
type A = "aA";
type B = Uppercase<A>;
type C = Lowercase<A>;
// templated
type ATemplate = `aA${string}`;
type BTemplate = Uppercase<ATemplate>;
type CTemplate = Lowercase<ATemplate>;
function f1(
a: A,
b: B,
c: C,
a_template: ATemplate,
b_template: BTemplate,
c_template: CTemplate
) {
// non-template versions should be assignable to templated versions (empty string matches string)
a_template = a;
b_template = b;
c_template = c;
// not the other way around
a = a_template;
~
!!! error TS2322: Type '`aA${string}`' is not assignable to type '"aA"'.
b = b_template;
~
!!! error TS2322: Type '`AA${Uppercase<string>}`' is not assignable to type '"AA"'.
!!! error TS2322: Type '`AA${string}`' is not assignable to type '"AA"'.
c = c_template;
~
!!! error TS2322: Type '`aa${Lowercase<string>}`' is not assignable to type '"aa"'.
!!! error TS2322: Type '`aa${string}`' is not assignable to type '"aa"'.
// Additionally, all the template versions should be mutually incompatible (they describe differing sets)
a_template = b_template;
~~~~~~~~~~
!!! error TS2322: Type '`AA${Uppercase<string>}`' is not assignable to type '`aA${string}`'.
a_template = c_template;
~~~~~~~~~~
!!! error TS2322: Type '`aa${Lowercase<string>}`' is not assignable to type '`aA${string}`'.
b_template = a_template;
~~~~~~~~~~
!!! error TS2322: Type '`aA${string}`' is not assignable to type '`AA${Uppercase<string>}`'.
b_template = c_template;
~~~~~~~~~~
!!! error TS2322: Type '`aa${Lowercase<string>}`' is not assignable to type '`AA${Uppercase<string>}`'.
c_template = a_template;
~~~~~~~~~~
!!! error TS2322: Type '`aA${string}`' is not assignable to type '`aa${Lowercase<string>}`'.
c_template = b_template;
~~~~~~~~~~
!!! error TS2322: Type '`AA${Uppercase<string>}`' is not assignable to type '`aa${Lowercase<string>}`'.
}
// Raw string mapping assignability
function f2(x1: string, x2: Uppercase<string>, x3: Lowercase<string>) {
// ok
x1 = x2;
x1 = x3;
x2 = "ABC";
x3 = "abc";
// should fail (sets do not match)
x2 = x1;
~~
!!! error TS2322: Type 'string' is not assignable to type 'Uppercase<string>'.
x2 = x3;
~~
!!! error TS2322: Type 'Lowercase<string>' is not assignable to type 'Uppercase<string>'.
x3 = x1;
~~
!!! error TS2322: Type 'string' is not assignable to type 'Lowercase<string>'.
x3 = x2;
~~
!!! error TS2322: Type 'Uppercase<string>' is not assignable to type 'Lowercase<string>'.
x2 = "AbC";
~~
!!! error TS2322: Type 'string' is not assignable to type 'Uppercase<string>'.
x3 = "AbC";
~~
!!! error TS2322: Type 'string' is not assignable to type 'Lowercase<string>'.
}
// Mappings over mappings
function f3(
x1: Uppercase<string>,
x2: Uppercase<Uppercase<string>>,
x3: Uppercase<Lowercase<string>>) {
// _ideally_ these would all be equivalent
x1 = x2;
x1 = x3;
x2 = x1;
x2 = x3;
// you'd think these were equivalent - the outer `Uppercase` conceptually
// makes the inner `Lowercase` effectively a noop - but that's not so;
// the german sharp s makes that not completely true (lowercases to ss,
// which then uppercases to SS), so arbitrary nestings of mappings make differing sets!
x3 = x1;
~~
!!! error TS2322: Type 'Uppercase<string>' is not assignable to type 'Uppercase<Lowercase<string>>'.
!!! error TS2322: Type 'string' is not assignable to type 'Lowercase<string>'.
x3 = x2;
~~
!!! error TS2322: Type 'Uppercase<string>' is not assignable to type 'Uppercase<Lowercase<string>>'.
// and this should also not be equivlent to any others
var x4: Lowercase<Uppercase<string>> = null as any;
x1 = x4;
~~
!!! error TS2322: Type 'Lowercase<Uppercase<string>>' is not assignable to type 'Uppercase<string>'.
x2 = x4;
~~
!!! error TS2322: Type 'Lowercase<Uppercase<string>>' is not assignable to type 'Uppercase<string>'.
x3 = x4;
~~
!!! error TS2322: Type 'Lowercase<Uppercase<string>>' is not assignable to type 'Uppercase<Lowercase<string>>'.
x4 = x1;
~~
!!! error TS2322: Type 'Uppercase<string>' is not assignable to type 'Lowercase<Uppercase<string>>'.
x4 = x2;
~~
!!! error TS2322: Type 'Uppercase<string>' is not assignable to type 'Lowercase<Uppercase<string>>'.
x4 = x3;
~~
!!! error TS2322: Type 'Uppercase<Lowercase<string>>' is not assignable to type 'Lowercase<Uppercase<string>>'.
}
// string mapping over non-string pattern literals is preserved
type NonStringPat = Uppercase<`aA${number}${bigint}${boolean}`>;
type EquivalentNonStringPat = `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}${Uppercase<`${boolean}`>}`;
function f4(x1: NonStringPat, x2: EquivalentNonStringPat) {
// Should both work
x1 = x2;
x2 = x1;
}
// Capitalize and uncapitalize on template literals
function f5(
cap_tem: `A${string}`,
cap_str: Capitalize<string>,
cap_tem_map: Capitalize<`A${string}`>,
cap_tem_map2: Capitalize<`a${string}`>,
uncap_tem: `a${string}`,
uncap_str: Uncapitalize<string>,
uncap_tem_map: Uncapitalize<`A${string}`>,
uncap_tem_map2: Uncapitalize<`a${string}`>,
) {
// All these are capitalized
cap_str = cap_tem;
cap_str = cap_tem_map;
cap_str = cap_tem_map2;
// these are all equivalent
cap_tem = cap_tem_map;
cap_tem = cap_tem_map2;
cap_tem_map = cap_tem_map2;
cap_tem_map = cap_tem;
cap_tem_map2 = cap_tem_map;
cap_tem_map2 = cap_tem;
// meanwhile, these all require a `A` prefix
cap_tem = cap_str;
~~~~~~~
!!! error TS2322: Type 'Capitalize<string>' is not assignable to type '`A${string}`'.
!!! error TS2322: Type 'string' is not assignable to type '`A${string}`'.
cap_tem_map = cap_str;
~~~~~~~~~~~
!!! error TS2322: Type 'Capitalize<string>' is not assignable to type '`A${string}`'.
cap_tem_map2 = cap_str;
~~~~~~~~~~~~
!!! error TS2322: Type 'Capitalize<string>' is not assignable to type '`A${string}`'.
// All these are uncapitalized
uncap_str = uncap_tem;
uncap_str = uncap_tem_map;
uncap_str = uncap_tem_map2;
// these are all equivalent
uncap_tem = uncap_tem_map;
uncap_tem = uncap_tem_map2;
uncap_tem_map = uncap_tem_map2;
uncap_tem_map = uncap_tem;
uncap_tem_map2 = uncap_tem_map;
uncap_tem_map2 = uncap_tem;
// meanwhile, these all require a `a` prefix
uncap_tem = uncap_str;
~~~~~~~~~
!!! error TS2322: Type 'Uncapitalize<string>' is not assignable to type '`a${string}`'.
!!! error TS2322: Type 'string' is not assignable to type '`a${string}`'.
uncap_tem_map = uncap_str;
~~~~~~~~~~~~~
!!! error TS2322: Type 'Uncapitalize<string>' is not assignable to type '`a${string}`'.
uncap_tem_map2 = uncap_str;
~~~~~~~~~~~~~~
!!! error TS2322: Type 'Uncapitalize<string>' is not assignable to type '`a${string}`'.
}

View File

@ -0,0 +1,245 @@
//// [stringMappingOverPatternLiterals.ts]
// non-template
type A = "aA";
type B = Uppercase<A>;
type C = Lowercase<A>;
// templated
type ATemplate = `aA${string}`;
type BTemplate = Uppercase<ATemplate>;
type CTemplate = Lowercase<ATemplate>;
function f1(
a: A,
b: B,
c: C,
a_template: ATemplate,
b_template: BTemplate,
c_template: CTemplate
) {
// non-template versions should be assignable to templated versions (empty string matches string)
a_template = a;
b_template = b;
c_template = c;
// not the other way around
a = a_template;
b = b_template;
c = c_template;
// Additionally, all the template versions should be mutually incompatible (they describe differing sets)
a_template = b_template;
a_template = c_template;
b_template = a_template;
b_template = c_template;
c_template = a_template;
c_template = b_template;
}
// Raw string mapping assignability
function f2(x1: string, x2: Uppercase<string>, x3: Lowercase<string>) {
// ok
x1 = x2;
x1 = x3;
x2 = "ABC";
x3 = "abc";
// should fail (sets do not match)
x2 = x1;
x2 = x3;
x3 = x1;
x3 = x2;
x2 = "AbC";
x3 = "AbC";
}
// Mappings over mappings
function f3(
x1: Uppercase<string>,
x2: Uppercase<Uppercase<string>>,
x3: Uppercase<Lowercase<string>>) {
// _ideally_ these would all be equivalent
x1 = x2;
x1 = x3;
x2 = x1;
x2 = x3;
// you'd think these were equivalent - the outer `Uppercase` conceptually
// makes the inner `Lowercase` effectively a noop - but that's not so;
// the german sharp s makes that not completely true (lowercases to ss,
// which then uppercases to SS), so arbitrary nestings of mappings make differing sets!
x3 = x1;
x3 = x2;
// and this should also not be equivlent to any others
var x4: Lowercase<Uppercase<string>> = null as any;
x1 = x4;
x2 = x4;
x3 = x4;
x4 = x1;
x4 = x2;
x4 = x3;
}
// string mapping over non-string pattern literals is preserved
type NonStringPat = Uppercase<`aA${number}${bigint}${boolean}`>;
type EquivalentNonStringPat = `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}${Uppercase<`${boolean}`>}`;
function f4(x1: NonStringPat, x2: EquivalentNonStringPat) {
// Should both work
x1 = x2;
x2 = x1;
}
// Capitalize and uncapitalize on template literals
function f5(
cap_tem: `A${string}`,
cap_str: Capitalize<string>,
cap_tem_map: Capitalize<`A${string}`>,
cap_tem_map2: Capitalize<`a${string}`>,
uncap_tem: `a${string}`,
uncap_str: Uncapitalize<string>,
uncap_tem_map: Uncapitalize<`A${string}`>,
uncap_tem_map2: Uncapitalize<`a${string}`>,
) {
// All these are capitalized
cap_str = cap_tem;
cap_str = cap_tem_map;
cap_str = cap_tem_map2;
// these are all equivalent
cap_tem = cap_tem_map;
cap_tem = cap_tem_map2;
cap_tem_map = cap_tem_map2;
cap_tem_map = cap_tem;
cap_tem_map2 = cap_tem_map;
cap_tem_map2 = cap_tem;
// meanwhile, these all require a `A` prefix
cap_tem = cap_str;
cap_tem_map = cap_str;
cap_tem_map2 = cap_str;
// All these are uncapitalized
uncap_str = uncap_tem;
uncap_str = uncap_tem_map;
uncap_str = uncap_tem_map2;
// these are all equivalent
uncap_tem = uncap_tem_map;
uncap_tem = uncap_tem_map2;
uncap_tem_map = uncap_tem_map2;
uncap_tem_map = uncap_tem;
uncap_tem_map2 = uncap_tem_map;
uncap_tem_map2 = uncap_tem;
// meanwhile, these all require a `a` prefix
uncap_tem = uncap_str;
uncap_tem_map = uncap_str;
uncap_tem_map2 = uncap_str;
}
//// [stringMappingOverPatternLiterals.js]
function f1(a, b, c, a_template, b_template, c_template) {
// non-template versions should be assignable to templated versions (empty string matches string)
a_template = a;
b_template = b;
c_template = c;
// not the other way around
a = a_template;
b = b_template;
c = c_template;
// Additionally, all the template versions should be mutually incompatible (they describe differing sets)
a_template = b_template;
a_template = c_template;
b_template = a_template;
b_template = c_template;
c_template = a_template;
c_template = b_template;
}
// Raw string mapping assignability
function f2(x1, x2, x3) {
// ok
x1 = x2;
x1 = x3;
x2 = "ABC";
x3 = "abc";
// should fail (sets do not match)
x2 = x1;
x2 = x3;
x3 = x1;
x3 = x2;
x2 = "AbC";
x3 = "AbC";
}
// Mappings over mappings
function f3(x1, x2, x3) {
// _ideally_ these would all be equivalent
x1 = x2;
x1 = x3;
x2 = x1;
x2 = x3;
// you'd think these were equivalent - the outer `Uppercase` conceptually
// makes the inner `Lowercase` effectively a noop - but that's not so;
// the german sharp s makes that not completely true (lowercases to ss,
// which then uppercases to SS), so arbitrary nestings of mappings make differing sets!
x3 = x1;
x3 = x2;
// and this should also not be equivlent to any others
var x4 = null;
x1 = x4;
x2 = x4;
x3 = x4;
x4 = x1;
x4 = x2;
x4 = x3;
}
function f4(x1, x2) {
// Should both work
x1 = x2;
x2 = x1;
}
// Capitalize and uncapitalize on template literals
function f5(cap_tem, cap_str, cap_tem_map, cap_tem_map2, uncap_tem, uncap_str, uncap_tem_map, uncap_tem_map2) {
// All these are capitalized
cap_str = cap_tem;
cap_str = cap_tem_map;
cap_str = cap_tem_map2;
// these are all equivalent
cap_tem = cap_tem_map;
cap_tem = cap_tem_map2;
cap_tem_map = cap_tem_map2;
cap_tem_map = cap_tem;
cap_tem_map2 = cap_tem_map;
cap_tem_map2 = cap_tem;
// meanwhile, these all require a `A` prefix
cap_tem = cap_str;
cap_tem_map = cap_str;
cap_tem_map2 = cap_str;
// All these are uncapitalized
uncap_str = uncap_tem;
uncap_str = uncap_tem_map;
uncap_str = uncap_tem_map2;
// these are all equivalent
uncap_tem = uncap_tem_map;
uncap_tem = uncap_tem_map2;
uncap_tem_map = uncap_tem_map2;
uncap_tem_map = uncap_tem;
uncap_tem_map2 = uncap_tem_map;
uncap_tem_map2 = uncap_tem;
// meanwhile, these all require a `a` prefix
uncap_tem = uncap_str;
uncap_tem_map = uncap_str;
uncap_tem_map2 = uncap_str;
}

View File

@ -0,0 +1,404 @@
=== tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts ===
// non-template
type A = "aA";
>A : Symbol(A, Decl(stringMappingOverPatternLiterals.ts, 0, 0))
type B = Uppercase<A>;
>B : Symbol(B, Decl(stringMappingOverPatternLiterals.ts, 1, 14))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>A : Symbol(A, Decl(stringMappingOverPatternLiterals.ts, 0, 0))
type C = Lowercase<A>;
>C : Symbol(C, Decl(stringMappingOverPatternLiterals.ts, 2, 22))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
>A : Symbol(A, Decl(stringMappingOverPatternLiterals.ts, 0, 0))
// templated
type ATemplate = `aA${string}`;
>ATemplate : Symbol(ATemplate, Decl(stringMappingOverPatternLiterals.ts, 3, 22))
type BTemplate = Uppercase<ATemplate>;
>BTemplate : Symbol(BTemplate, Decl(stringMappingOverPatternLiterals.ts, 6, 31))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>ATemplate : Symbol(ATemplate, Decl(stringMappingOverPatternLiterals.ts, 3, 22))
type CTemplate = Lowercase<ATemplate>;
>CTemplate : Symbol(CTemplate, Decl(stringMappingOverPatternLiterals.ts, 7, 38))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
>ATemplate : Symbol(ATemplate, Decl(stringMappingOverPatternLiterals.ts, 3, 22))
function f1(
>f1 : Symbol(f1, Decl(stringMappingOverPatternLiterals.ts, 8, 38))
a: A,
>a : Symbol(a, Decl(stringMappingOverPatternLiterals.ts, 10, 12))
>A : Symbol(A, Decl(stringMappingOverPatternLiterals.ts, 0, 0))
b: B,
>b : Symbol(b, Decl(stringMappingOverPatternLiterals.ts, 11, 9))
>B : Symbol(B, Decl(stringMappingOverPatternLiterals.ts, 1, 14))
c: C,
>c : Symbol(c, Decl(stringMappingOverPatternLiterals.ts, 12, 9))
>C : Symbol(C, Decl(stringMappingOverPatternLiterals.ts, 2, 22))
a_template: ATemplate,
>a_template : Symbol(a_template, Decl(stringMappingOverPatternLiterals.ts, 13, 9))
>ATemplate : Symbol(ATemplate, Decl(stringMappingOverPatternLiterals.ts, 3, 22))
b_template: BTemplate,
>b_template : Symbol(b_template, Decl(stringMappingOverPatternLiterals.ts, 14, 26))
>BTemplate : Symbol(BTemplate, Decl(stringMappingOverPatternLiterals.ts, 6, 31))
c_template: CTemplate
>c_template : Symbol(c_template, Decl(stringMappingOverPatternLiterals.ts, 15, 26))
>CTemplate : Symbol(CTemplate, Decl(stringMappingOverPatternLiterals.ts, 7, 38))
) {
// non-template versions should be assignable to templated versions (empty string matches string)
a_template = a;
>a_template : Symbol(a_template, Decl(stringMappingOverPatternLiterals.ts, 13, 9))
>a : Symbol(a, Decl(stringMappingOverPatternLiterals.ts, 10, 12))
b_template = b;
>b_template : Symbol(b_template, Decl(stringMappingOverPatternLiterals.ts, 14, 26))
>b : Symbol(b, Decl(stringMappingOverPatternLiterals.ts, 11, 9))
c_template = c;
>c_template : Symbol(c_template, Decl(stringMappingOverPatternLiterals.ts, 15, 26))
>c : Symbol(c, Decl(stringMappingOverPatternLiterals.ts, 12, 9))
// not the other way around
a = a_template;
>a : Symbol(a, Decl(stringMappingOverPatternLiterals.ts, 10, 12))
>a_template : Symbol(a_template, Decl(stringMappingOverPatternLiterals.ts, 13, 9))
b = b_template;
>b : Symbol(b, Decl(stringMappingOverPatternLiterals.ts, 11, 9))
>b_template : Symbol(b_template, Decl(stringMappingOverPatternLiterals.ts, 14, 26))
c = c_template;
>c : Symbol(c, Decl(stringMappingOverPatternLiterals.ts, 12, 9))
>c_template : Symbol(c_template, Decl(stringMappingOverPatternLiterals.ts, 15, 26))
// Additionally, all the template versions should be mutually incompatible (they describe differing sets)
a_template = b_template;
>a_template : Symbol(a_template, Decl(stringMappingOverPatternLiterals.ts, 13, 9))
>b_template : Symbol(b_template, Decl(stringMappingOverPatternLiterals.ts, 14, 26))
a_template = c_template;
>a_template : Symbol(a_template, Decl(stringMappingOverPatternLiterals.ts, 13, 9))
>c_template : Symbol(c_template, Decl(stringMappingOverPatternLiterals.ts, 15, 26))
b_template = a_template;
>b_template : Symbol(b_template, Decl(stringMappingOverPatternLiterals.ts, 14, 26))
>a_template : Symbol(a_template, Decl(stringMappingOverPatternLiterals.ts, 13, 9))
b_template = c_template;
>b_template : Symbol(b_template, Decl(stringMappingOverPatternLiterals.ts, 14, 26))
>c_template : Symbol(c_template, Decl(stringMappingOverPatternLiterals.ts, 15, 26))
c_template = a_template;
>c_template : Symbol(c_template, Decl(stringMappingOverPatternLiterals.ts, 15, 26))
>a_template : Symbol(a_template, Decl(stringMappingOverPatternLiterals.ts, 13, 9))
c_template = b_template;
>c_template : Symbol(c_template, Decl(stringMappingOverPatternLiterals.ts, 15, 26))
>b_template : Symbol(b_template, Decl(stringMappingOverPatternLiterals.ts, 14, 26))
}
// Raw string mapping assignability
function f2(x1: string, x2: Uppercase<string>, x3: Lowercase<string>) {
>f2 : Symbol(f2, Decl(stringMappingOverPatternLiterals.ts, 37, 1))
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 41, 12))
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 41, 23))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 41, 46))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
// ok
x1 = x2;
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 41, 12))
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 41, 23))
x1 = x3;
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 41, 12))
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 41, 46))
x2 = "ABC";
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 41, 23))
x3 = "abc";
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 41, 46))
// should fail (sets do not match)
x2 = x1;
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 41, 23))
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 41, 12))
x2 = x3;
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 41, 23))
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 41, 46))
x3 = x1;
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 41, 46))
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 41, 12))
x3 = x2;
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 41, 46))
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 41, 23))
x2 = "AbC";
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 41, 23))
x3 = "AbC";
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 41, 46))
}
// Mappings over mappings
function f3(
>f3 : Symbol(f3, Decl(stringMappingOverPatternLiterals.ts, 57, 1))
x1: Uppercase<string>,
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 61, 12))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
x2: Uppercase<Uppercase<string>>,
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 62, 26))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
x3: Uppercase<Lowercase<string>>) {
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 63, 37))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
// _ideally_ these would all be equivalent
x1 = x2;
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 61, 12))
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 62, 26))
x1 = x3;
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 61, 12))
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 63, 37))
x2 = x1;
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 62, 26))
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 61, 12))
x2 = x3;
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 62, 26))
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 63, 37))
// you'd think these were equivalent - the outer `Uppercase` conceptually
// makes the inner `Lowercase` effectively a noop - but that's not so;
// the german sharp s makes that not completely true (lowercases to ss,
// which then uppercases to SS), so arbitrary nestings of mappings make differing sets!
x3 = x1;
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 63, 37))
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 61, 12))
x3 = x2;
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 63, 37))
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 62, 26))
// and this should also not be equivlent to any others
var x4: Lowercase<Uppercase<string>> = null as any;
>x4 : Symbol(x4, Decl(stringMappingOverPatternLiterals.ts, 81, 7))
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
x1 = x4;
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 61, 12))
>x4 : Symbol(x4, Decl(stringMappingOverPatternLiterals.ts, 81, 7))
x2 = x4;
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 62, 26))
>x4 : Symbol(x4, Decl(stringMappingOverPatternLiterals.ts, 81, 7))
x3 = x4;
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 63, 37))
>x4 : Symbol(x4, Decl(stringMappingOverPatternLiterals.ts, 81, 7))
x4 = x1;
>x4 : Symbol(x4, Decl(stringMappingOverPatternLiterals.ts, 81, 7))
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 61, 12))
x4 = x2;
>x4 : Symbol(x4, Decl(stringMappingOverPatternLiterals.ts, 81, 7))
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 62, 26))
x4 = x3;
>x4 : Symbol(x4, Decl(stringMappingOverPatternLiterals.ts, 81, 7))
>x3 : Symbol(x3, Decl(stringMappingOverPatternLiterals.ts, 63, 37))
}
// string mapping over non-string pattern literals is preserved
type NonStringPat = Uppercase<`aA${number}${bigint}${boolean}`>;
>NonStringPat : Symbol(NonStringPat, Decl(stringMappingOverPatternLiterals.ts, 89, 1))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
type EquivalentNonStringPat = `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}${Uppercase<`${boolean}`>}`;
>EquivalentNonStringPat : Symbol(EquivalentNonStringPat, Decl(stringMappingOverPatternLiterals.ts, 93, 64))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
function f4(x1: NonStringPat, x2: EquivalentNonStringPat) {
>f4 : Symbol(f4, Decl(stringMappingOverPatternLiterals.ts, 94, 111))
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 96, 12))
>NonStringPat : Symbol(NonStringPat, Decl(stringMappingOverPatternLiterals.ts, 89, 1))
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 96, 29))
>EquivalentNonStringPat : Symbol(EquivalentNonStringPat, Decl(stringMappingOverPatternLiterals.ts, 93, 64))
// Should both work
x1 = x2;
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 96, 12))
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 96, 29))
x2 = x1;
>x2 : Symbol(x2, Decl(stringMappingOverPatternLiterals.ts, 96, 29))
>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 96, 12))
}
// Capitalize and uncapitalize on template literals
function f5(
>f5 : Symbol(f5, Decl(stringMappingOverPatternLiterals.ts, 100, 1))
cap_tem: `A${string}`,
>cap_tem : Symbol(cap_tem, Decl(stringMappingOverPatternLiterals.ts, 104, 12))
cap_str: Capitalize<string>,
>cap_str : Symbol(cap_str, Decl(stringMappingOverPatternLiterals.ts, 105, 26))
>Capitalize : Symbol(Capitalize, Decl(lib.es5.d.ts, --, --))
cap_tem_map: Capitalize<`A${string}`>,
>cap_tem_map : Symbol(cap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 106, 32))
>Capitalize : Symbol(Capitalize, Decl(lib.es5.d.ts, --, --))
cap_tem_map2: Capitalize<`a${string}`>,
>cap_tem_map2 : Symbol(cap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 107, 42))
>Capitalize : Symbol(Capitalize, Decl(lib.es5.d.ts, --, --))
uncap_tem: `a${string}`,
>uncap_tem : Symbol(uncap_tem, Decl(stringMappingOverPatternLiterals.ts, 108, 43))
uncap_str: Uncapitalize<string>,
>uncap_str : Symbol(uncap_str, Decl(stringMappingOverPatternLiterals.ts, 109, 28))
>Uncapitalize : Symbol(Uncapitalize, Decl(lib.es5.d.ts, --, --))
uncap_tem_map: Uncapitalize<`A${string}`>,
>uncap_tem_map : Symbol(uncap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 110, 36))
>Uncapitalize : Symbol(Uncapitalize, Decl(lib.es5.d.ts, --, --))
uncap_tem_map2: Uncapitalize<`a${string}`>,
>uncap_tem_map2 : Symbol(uncap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 111, 46))
>Uncapitalize : Symbol(Uncapitalize, Decl(lib.es5.d.ts, --, --))
) {
// All these are capitalized
cap_str = cap_tem;
>cap_str : Symbol(cap_str, Decl(stringMappingOverPatternLiterals.ts, 105, 26))
>cap_tem : Symbol(cap_tem, Decl(stringMappingOverPatternLiterals.ts, 104, 12))
cap_str = cap_tem_map;
>cap_str : Symbol(cap_str, Decl(stringMappingOverPatternLiterals.ts, 105, 26))
>cap_tem_map : Symbol(cap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 106, 32))
cap_str = cap_tem_map2;
>cap_str : Symbol(cap_str, Decl(stringMappingOverPatternLiterals.ts, 105, 26))
>cap_tem_map2 : Symbol(cap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 107, 42))
// these are all equivalent
cap_tem = cap_tem_map;
>cap_tem : Symbol(cap_tem, Decl(stringMappingOverPatternLiterals.ts, 104, 12))
>cap_tem_map : Symbol(cap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 106, 32))
cap_tem = cap_tem_map2;
>cap_tem : Symbol(cap_tem, Decl(stringMappingOverPatternLiterals.ts, 104, 12))
>cap_tem_map2 : Symbol(cap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 107, 42))
cap_tem_map = cap_tem_map2;
>cap_tem_map : Symbol(cap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 106, 32))
>cap_tem_map2 : Symbol(cap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 107, 42))
cap_tem_map = cap_tem;
>cap_tem_map : Symbol(cap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 106, 32))
>cap_tem : Symbol(cap_tem, Decl(stringMappingOverPatternLiterals.ts, 104, 12))
cap_tem_map2 = cap_tem_map;
>cap_tem_map2 : Symbol(cap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 107, 42))
>cap_tem_map : Symbol(cap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 106, 32))
cap_tem_map2 = cap_tem;
>cap_tem_map2 : Symbol(cap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 107, 42))
>cap_tem : Symbol(cap_tem, Decl(stringMappingOverPatternLiterals.ts, 104, 12))
// meanwhile, these all require a `A` prefix
cap_tem = cap_str;
>cap_tem : Symbol(cap_tem, Decl(stringMappingOverPatternLiterals.ts, 104, 12))
>cap_str : Symbol(cap_str, Decl(stringMappingOverPatternLiterals.ts, 105, 26))
cap_tem_map = cap_str;
>cap_tem_map : Symbol(cap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 106, 32))
>cap_str : Symbol(cap_str, Decl(stringMappingOverPatternLiterals.ts, 105, 26))
cap_tem_map2 = cap_str;
>cap_tem_map2 : Symbol(cap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 107, 42))
>cap_str : Symbol(cap_str, Decl(stringMappingOverPatternLiterals.ts, 105, 26))
// All these are uncapitalized
uncap_str = uncap_tem;
>uncap_str : Symbol(uncap_str, Decl(stringMappingOverPatternLiterals.ts, 109, 28))
>uncap_tem : Symbol(uncap_tem, Decl(stringMappingOverPatternLiterals.ts, 108, 43))
uncap_str = uncap_tem_map;
>uncap_str : Symbol(uncap_str, Decl(stringMappingOverPatternLiterals.ts, 109, 28))
>uncap_tem_map : Symbol(uncap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 110, 36))
uncap_str = uncap_tem_map2;
>uncap_str : Symbol(uncap_str, Decl(stringMappingOverPatternLiterals.ts, 109, 28))
>uncap_tem_map2 : Symbol(uncap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 111, 46))
// these are all equivalent
uncap_tem = uncap_tem_map;
>uncap_tem : Symbol(uncap_tem, Decl(stringMappingOverPatternLiterals.ts, 108, 43))
>uncap_tem_map : Symbol(uncap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 110, 36))
uncap_tem = uncap_tem_map2;
>uncap_tem : Symbol(uncap_tem, Decl(stringMappingOverPatternLiterals.ts, 108, 43))
>uncap_tem_map2 : Symbol(uncap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 111, 46))
uncap_tem_map = uncap_tem_map2;
>uncap_tem_map : Symbol(uncap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 110, 36))
>uncap_tem_map2 : Symbol(uncap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 111, 46))
uncap_tem_map = uncap_tem;
>uncap_tem_map : Symbol(uncap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 110, 36))
>uncap_tem : Symbol(uncap_tem, Decl(stringMappingOverPatternLiterals.ts, 108, 43))
uncap_tem_map2 = uncap_tem_map;
>uncap_tem_map2 : Symbol(uncap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 111, 46))
>uncap_tem_map : Symbol(uncap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 110, 36))
uncap_tem_map2 = uncap_tem;
>uncap_tem_map2 : Symbol(uncap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 111, 46))
>uncap_tem : Symbol(uncap_tem, Decl(stringMappingOverPatternLiterals.ts, 108, 43))
// meanwhile, these all require a `a` prefix
uncap_tem = uncap_str;
>uncap_tem : Symbol(uncap_tem, Decl(stringMappingOverPatternLiterals.ts, 108, 43))
>uncap_str : Symbol(uncap_str, Decl(stringMappingOverPatternLiterals.ts, 109, 28))
uncap_tem_map = uncap_str;
>uncap_tem_map : Symbol(uncap_tem_map, Decl(stringMappingOverPatternLiterals.ts, 110, 36))
>uncap_str : Symbol(uncap_str, Decl(stringMappingOverPatternLiterals.ts, 109, 28))
uncap_tem_map2 = uncap_str;
>uncap_tem_map2 : Symbol(uncap_tem_map2, Decl(stringMappingOverPatternLiterals.ts, 111, 46))
>uncap_str : Symbol(uncap_str, Decl(stringMappingOverPatternLiterals.ts, 109, 28))
}

View File

@ -0,0 +1,435 @@
=== tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts ===
// non-template
type A = "aA";
>A : "aA"
type B = Uppercase<A>;
>B : "AA"
type C = Lowercase<A>;
>C : "aa"
// templated
type ATemplate = `aA${string}`;
>ATemplate : `aA${string}`
type BTemplate = Uppercase<ATemplate>;
>BTemplate : `AA${Uppercase<string>}`
type CTemplate = Lowercase<ATemplate>;
>CTemplate : `aa${Lowercase<string>}`
function f1(
>f1 : (a: A, b: B, c: C, a_template: ATemplate, b_template: BTemplate, c_template: CTemplate) => void
a: A,
>a : "aA"
b: B,
>b : "AA"
c: C,
>c : "aa"
a_template: ATemplate,
>a_template : `aA${string}`
b_template: BTemplate,
>b_template : `AA${Uppercase<string>}`
c_template: CTemplate
>c_template : `aa${Lowercase<string>}`
) {
// non-template versions should be assignable to templated versions (empty string matches string)
a_template = a;
>a_template = a : "aA"
>a_template : `aA${string}`
>a : "aA"
b_template = b;
>b_template = b : "AA"
>b_template : `AA${Uppercase<string>}`
>b : "AA"
c_template = c;
>c_template = c : "aa"
>c_template : `aa${Lowercase<string>}`
>c : "aa"
// not the other way around
a = a_template;
>a = a_template : `aA${string}`
>a : "aA"
>a_template : `aA${string}`
b = b_template;
>b = b_template : `AA${Uppercase<string>}`
>b : "AA"
>b_template : `AA${Uppercase<string>}`
c = c_template;
>c = c_template : `aa${Lowercase<string>}`
>c : "aa"
>c_template : `aa${Lowercase<string>}`
// Additionally, all the template versions should be mutually incompatible (they describe differing sets)
a_template = b_template;
>a_template = b_template : `AA${Uppercase<string>}`
>a_template : `aA${string}`
>b_template : `AA${Uppercase<string>}`
a_template = c_template;
>a_template = c_template : `aa${Lowercase<string>}`
>a_template : `aA${string}`
>c_template : `aa${Lowercase<string>}`
b_template = a_template;
>b_template = a_template : `aA${string}`
>b_template : `AA${Uppercase<string>}`
>a_template : `aA${string}`
b_template = c_template;
>b_template = c_template : `aa${Lowercase<string>}`
>b_template : `AA${Uppercase<string>}`
>c_template : `aa${Lowercase<string>}`
c_template = a_template;
>c_template = a_template : `aA${string}`
>c_template : `aa${Lowercase<string>}`
>a_template : `aA${string}`
c_template = b_template;
>c_template = b_template : `AA${Uppercase<string>}`
>c_template : `aa${Lowercase<string>}`
>b_template : `AA${Uppercase<string>}`
}
// Raw string mapping assignability
function f2(x1: string, x2: Uppercase<string>, x3: Lowercase<string>) {
>f2 : (x1: string, x2: Uppercase<string>, x3: Lowercase<string>) => void
>x1 : string
>x2 : Uppercase<string>
>x3 : Lowercase<string>
// ok
x1 = x2;
>x1 = x2 : Uppercase<string>
>x1 : string
>x2 : Uppercase<string>
x1 = x3;
>x1 = x3 : Lowercase<string>
>x1 : string
>x3 : Lowercase<string>
x2 = "ABC";
>x2 = "ABC" : "ABC"
>x2 : Uppercase<string>
>"ABC" : "ABC"
x3 = "abc";
>x3 = "abc" : "abc"
>x3 : Lowercase<string>
>"abc" : "abc"
// should fail (sets do not match)
x2 = x1;
>x2 = x1 : string
>x2 : Uppercase<string>
>x1 : string
x2 = x3;
>x2 = x3 : Lowercase<string>
>x2 : Uppercase<string>
>x3 : Lowercase<string>
x3 = x1;
>x3 = x1 : string
>x3 : Lowercase<string>
>x1 : string
x3 = x2;
>x3 = x2 : Uppercase<string>
>x3 : Lowercase<string>
>x2 : Uppercase<string>
x2 = "AbC";
>x2 = "AbC" : "AbC"
>x2 : Uppercase<string>
>"AbC" : "AbC"
x3 = "AbC";
>x3 = "AbC" : "AbC"
>x3 : Lowercase<string>
>"AbC" : "AbC"
}
// Mappings over mappings
function f3(
>f3 : (x1: Uppercase<string>, x2: Uppercase<Uppercase<string>>, x3: Uppercase<Lowercase<string>>) => void
x1: Uppercase<string>,
>x1 : Uppercase<string>
x2: Uppercase<Uppercase<string>>,
>x2 : Uppercase<string>
x3: Uppercase<Lowercase<string>>) {
>x3 : Uppercase<Lowercase<string>>
// _ideally_ these would all be equivalent
x1 = x2;
>x1 = x2 : Uppercase<string>
>x1 : Uppercase<string>
>x2 : Uppercase<string>
x1 = x3;
>x1 = x3 : Uppercase<Lowercase<string>>
>x1 : Uppercase<string>
>x3 : Uppercase<Lowercase<string>>
x2 = x1;
>x2 = x1 : Uppercase<string>
>x2 : Uppercase<string>
>x1 : Uppercase<string>
x2 = x3;
>x2 = x3 : Uppercase<Lowercase<string>>
>x2 : Uppercase<string>
>x3 : Uppercase<Lowercase<string>>
// you'd think these were equivalent - the outer `Uppercase` conceptually
// makes the inner `Lowercase` effectively a noop - but that's not so;
// the german sharp s makes that not completely true (lowercases to ss,
// which then uppercases to SS), so arbitrary nestings of mappings make differing sets!
x3 = x1;
>x3 = x1 : Uppercase<string>
>x3 : Uppercase<Lowercase<string>>
>x1 : Uppercase<string>
x3 = x2;
>x3 = x2 : Uppercase<string>
>x3 : Uppercase<Lowercase<string>>
>x2 : Uppercase<string>
// and this should also not be equivlent to any others
var x4: Lowercase<Uppercase<string>> = null as any;
>x4 : Lowercase<Uppercase<string>>
>null as any : any
>null : null
x1 = x4;
>x1 = x4 : Lowercase<Uppercase<string>>
>x1 : Uppercase<string>
>x4 : Lowercase<Uppercase<string>>
x2 = x4;
>x2 = x4 : Lowercase<Uppercase<string>>
>x2 : Uppercase<string>
>x4 : Lowercase<Uppercase<string>>
x3 = x4;
>x3 = x4 : Lowercase<Uppercase<string>>
>x3 : Uppercase<Lowercase<string>>
>x4 : Lowercase<Uppercase<string>>
x4 = x1;
>x4 = x1 : Uppercase<string>
>x4 : Lowercase<Uppercase<string>>
>x1 : Uppercase<string>
x4 = x2;
>x4 = x2 : Uppercase<string>
>x4 : Lowercase<Uppercase<string>>
>x2 : Uppercase<string>
x4 = x3;
>x4 = x3 : Uppercase<Lowercase<string>>
>x4 : Lowercase<Uppercase<string>>
>x3 : Uppercase<Lowercase<string>>
}
// string mapping over non-string pattern literals is preserved
type NonStringPat = Uppercase<`aA${number}${bigint}${boolean}`>;
>NonStringPat : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
type EquivalentNonStringPat = `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}${Uppercase<`${boolean}`>}`;
>EquivalentNonStringPat : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
function f4(x1: NonStringPat, x2: EquivalentNonStringPat) {
>f4 : (x1: NonStringPat, x2: EquivalentNonStringPat) => void
>x1 : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
>x2 : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
// Should both work
x1 = x2;
>x1 = x2 : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
>x1 : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
>x2 : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
x2 = x1;
>x2 = x1 : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
>x2 : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
>x1 : `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}FALSE` | `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}TRUE`
}
// Capitalize and uncapitalize on template literals
function f5(
>f5 : (cap_tem: `A${string}`, cap_str: Capitalize<string>, cap_tem_map: Capitalize<`A${string}`>, cap_tem_map2: Capitalize<`a${string}`>, uncap_tem: `a${string}`, uncap_str: Uncapitalize<string>, uncap_tem_map: Uncapitalize<`A${string}`>, uncap_tem_map2: Uncapitalize<`a${string}`>) => void
cap_tem: `A${string}`,
>cap_tem : `A${string}`
cap_str: Capitalize<string>,
>cap_str : Capitalize<string>
cap_tem_map: Capitalize<`A${string}`>,
>cap_tem_map : `A${string}`
cap_tem_map2: Capitalize<`a${string}`>,
>cap_tem_map2 : `A${string}`
uncap_tem: `a${string}`,
>uncap_tem : `a${string}`
uncap_str: Uncapitalize<string>,
>uncap_str : Uncapitalize<string>
uncap_tem_map: Uncapitalize<`A${string}`>,
>uncap_tem_map : `a${string}`
uncap_tem_map2: Uncapitalize<`a${string}`>,
>uncap_tem_map2 : `a${string}`
) {
// All these are capitalized
cap_str = cap_tem;
>cap_str = cap_tem : `A${string}`
>cap_str : Capitalize<string>
>cap_tem : `A${string}`
cap_str = cap_tem_map;
>cap_str = cap_tem_map : `A${string}`
>cap_str : Capitalize<string>
>cap_tem_map : `A${string}`
cap_str = cap_tem_map2;
>cap_str = cap_tem_map2 : `A${string}`
>cap_str : Capitalize<string>
>cap_tem_map2 : `A${string}`
// these are all equivalent
cap_tem = cap_tem_map;
>cap_tem = cap_tem_map : `A${string}`
>cap_tem : `A${string}`
>cap_tem_map : `A${string}`
cap_tem = cap_tem_map2;
>cap_tem = cap_tem_map2 : `A${string}`
>cap_tem : `A${string}`
>cap_tem_map2 : `A${string}`
cap_tem_map = cap_tem_map2;
>cap_tem_map = cap_tem_map2 : `A${string}`
>cap_tem_map : `A${string}`
>cap_tem_map2 : `A${string}`
cap_tem_map = cap_tem;
>cap_tem_map = cap_tem : `A${string}`
>cap_tem_map : `A${string}`
>cap_tem : `A${string}`
cap_tem_map2 = cap_tem_map;
>cap_tem_map2 = cap_tem_map : `A${string}`
>cap_tem_map2 : `A${string}`
>cap_tem_map : `A${string}`
cap_tem_map2 = cap_tem;
>cap_tem_map2 = cap_tem : `A${string}`
>cap_tem_map2 : `A${string}`
>cap_tem : `A${string}`
// meanwhile, these all require a `A` prefix
cap_tem = cap_str;
>cap_tem = cap_str : Capitalize<string>
>cap_tem : `A${string}`
>cap_str : Capitalize<string>
cap_tem_map = cap_str;
>cap_tem_map = cap_str : Capitalize<string>
>cap_tem_map : `A${string}`
>cap_str : Capitalize<string>
cap_tem_map2 = cap_str;
>cap_tem_map2 = cap_str : Capitalize<string>
>cap_tem_map2 : `A${string}`
>cap_str : Capitalize<string>
// All these are uncapitalized
uncap_str = uncap_tem;
>uncap_str = uncap_tem : `a${string}`
>uncap_str : Uncapitalize<string>
>uncap_tem : `a${string}`
uncap_str = uncap_tem_map;
>uncap_str = uncap_tem_map : `a${string}`
>uncap_str : Uncapitalize<string>
>uncap_tem_map : `a${string}`
uncap_str = uncap_tem_map2;
>uncap_str = uncap_tem_map2 : `a${string}`
>uncap_str : Uncapitalize<string>
>uncap_tem_map2 : `a${string}`
// these are all equivalent
uncap_tem = uncap_tem_map;
>uncap_tem = uncap_tem_map : `a${string}`
>uncap_tem : `a${string}`
>uncap_tem_map : `a${string}`
uncap_tem = uncap_tem_map2;
>uncap_tem = uncap_tem_map2 : `a${string}`
>uncap_tem : `a${string}`
>uncap_tem_map2 : `a${string}`
uncap_tem_map = uncap_tem_map2;
>uncap_tem_map = uncap_tem_map2 : `a${string}`
>uncap_tem_map : `a${string}`
>uncap_tem_map2 : `a${string}`
uncap_tem_map = uncap_tem;
>uncap_tem_map = uncap_tem : `a${string}`
>uncap_tem_map : `a${string}`
>uncap_tem : `a${string}`
uncap_tem_map2 = uncap_tem_map;
>uncap_tem_map2 = uncap_tem_map : `a${string}`
>uncap_tem_map2 : `a${string}`
>uncap_tem_map : `a${string}`
uncap_tem_map2 = uncap_tem;
>uncap_tem_map2 = uncap_tem : `a${string}`
>uncap_tem_map2 : `a${string}`
>uncap_tem : `a${string}`
// meanwhile, these all require a `a` prefix
uncap_tem = uncap_str;
>uncap_tem = uncap_str : Uncapitalize<string>
>uncap_tem : `a${string}`
>uncap_str : Uncapitalize<string>
uncap_tem_map = uncap_str;
>uncap_tem_map = uncap_str : Uncapitalize<string>
>uncap_tem_map : `a${string}`
>uncap_str : Uncapitalize<string>
uncap_tem_map2 = uncap_str;
>uncap_tem_map2 = uncap_str : Uncapitalize<string>
>uncap_tem_map2 : `a${string}`
>uncap_str : Uncapitalize<string>
}

View File

@ -0,0 +1,16 @@
declare var x: Uppercase<Lowercase<string>>;
// good
x = "A";
// bad
x = "a";
declare var y: Uppercase<Lowercase<`${number}`>>;
// good
y = "1";
// bad
y = "a";
y = "A";

View File

@ -0,0 +1,150 @@
// non-template
type A = "aA";
type B = Uppercase<A>;
type C = Lowercase<A>;
// templated
type ATemplate = `aA${string}`;
type BTemplate = Uppercase<ATemplate>;
type CTemplate = Lowercase<ATemplate>;
function f1(
a: A,
b: B,
c: C,
a_template: ATemplate,
b_template: BTemplate,
c_template: CTemplate
) {
// non-template versions should be assignable to templated versions (empty string matches string)
a_template = a;
b_template = b;
c_template = c;
// not the other way around
a = a_template;
b = b_template;
c = c_template;
// Additionally, all the template versions should be mutually incompatible (they describe differing sets)
a_template = b_template;
a_template = c_template;
b_template = a_template;
b_template = c_template;
c_template = a_template;
c_template = b_template;
}
// Raw string mapping assignability
function f2(x1: string, x2: Uppercase<string>, x3: Lowercase<string>) {
// ok
x1 = x2;
x1 = x3;
x2 = "ABC";
x3 = "abc";
// should fail (sets do not match)
x2 = x1;
x2 = x3;
x3 = x1;
x3 = x2;
x2 = "AbC";
x3 = "AbC";
}
// Mappings over mappings
function f3(
x1: Uppercase<string>,
x2: Uppercase<Uppercase<string>>,
x3: Uppercase<Lowercase<string>>) {
// _ideally_ these would all be equivalent
x1 = x2;
x1 = x3;
x2 = x1;
x2 = x3;
// you'd think these were equivalent - the outer `Uppercase` conceptually
// makes the inner `Lowercase` effectively a noop - but that's not so;
// the german sharp s makes that not completely true (lowercases to ss,
// which then uppercases to SS), so arbitrary nestings of mappings make differing sets!
x3 = x1;
x3 = x2;
// and this should also not be equivlent to any others
var x4: Lowercase<Uppercase<string>> = null as any;
x1 = x4;
x2 = x4;
x3 = x4;
x4 = x1;
x4 = x2;
x4 = x3;
}
// string mapping over non-string pattern literals is preserved
type NonStringPat = Uppercase<`aA${number}${bigint}${boolean}`>;
type EquivalentNonStringPat = `AA${Uppercase<`${number}`>}${Uppercase<`${bigint}`>}${Uppercase<`${boolean}`>}`;
function f4(x1: NonStringPat, x2: EquivalentNonStringPat) {
// Should both work
x1 = x2;
x2 = x1;
}
// Capitalize and uncapitalize on template literals
function f5(
cap_tem: `A${string}`,
cap_str: Capitalize<string>,
cap_tem_map: Capitalize<`A${string}`>,
cap_tem_map2: Capitalize<`a${string}`>,
uncap_tem: `a${string}`,
uncap_str: Uncapitalize<string>,
uncap_tem_map: Uncapitalize<`A${string}`>,
uncap_tem_map2: Uncapitalize<`a${string}`>,
) {
// All these are capitalized
cap_str = cap_tem;
cap_str = cap_tem_map;
cap_str = cap_tem_map2;
// these are all equivalent
cap_tem = cap_tem_map;
cap_tem = cap_tem_map2;
cap_tem_map = cap_tem_map2;
cap_tem_map = cap_tem;
cap_tem_map2 = cap_tem_map;
cap_tem_map2 = cap_tem;
// meanwhile, these all require a `A` prefix
cap_tem = cap_str;
cap_tem_map = cap_str;
cap_tem_map2 = cap_str;
// All these are uncapitalized
uncap_str = uncap_tem;
uncap_str = uncap_tem_map;
uncap_str = uncap_tem_map2;
// these are all equivalent
uncap_tem = uncap_tem_map;
uncap_tem = uncap_tem_map2;
uncap_tem_map = uncap_tem_map2;
uncap_tem_map = uncap_tem;
uncap_tem_map2 = uncap_tem_map;
uncap_tem_map2 = uncap_tem;
// meanwhile, these all require a `a` prefix
uncap_tem = uncap_str;
uncap_tem_map = uncap_str;
uncap_tem_map2 = uncap_str;
}

View File

@ -3,29 +3,29 @@
type TU1 = Uppercase<'hello'>; // "HELLO"
type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR"
type TU3 = Uppercase<string>; // string
type TU4 = Uppercase<any>; // any
type TU3 = Uppercase<string>; // Uppercase<string>
type TU4 = Uppercase<any>; // Uppercase<`${any}`>
type TU5 = Uppercase<never>; // never
type TU6 = Uppercase<42>; // Error
type TL1 = Lowercase<'HELLO'>; // "hello"
type TL2 = Lowercase<'FOO' | 'BAR'>; // "foo" | "bar"
type TL3 = Lowercase<string>; // string
type TL4 = Lowercase<any>; // any
type TL3 = Lowercase<string>; // Lowercase<string>
type TL4 = Lowercase<any>; // Lowercase<`${any}`>
type TL5 = Lowercase<never>; // never
type TL6 = Lowercase<42>; // Error
type TC1 = Capitalize<'hello'>; // "Hello"
type TC2 = Capitalize<'foo' | 'bar'>; // "Foo" | "Bar"
type TC3 = Capitalize<string>; // string
type TC4 = Capitalize<any>; // any
type TC3 = Capitalize<string>; // Capitalize<string>
type TC4 = Capitalize<any>; // Capitalize<`${any}`>
type TC5 = Capitalize<never>; // never
type TC6 = Capitalize<42>; // Error
type TN1 = Uncapitalize<'Hello'>; // "hello"
type TN2 = Uncapitalize<'Foo' | 'Bar'>; // "foo" | "bar"
type TN3 = Uncapitalize<string>; // string
type TN4 = Uncapitalize<any>; // any
type TN3 = Uncapitalize<string>; // Uncapitalize<string>
type TN4 = Uncapitalize<any>; // Uncapitalize<`${any}`>
type TN5 = Uncapitalize<never>; // never
type TN6 = Uncapitalize<42>; // Error