diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 67599bccd2aba..28913c5814e17 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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 + 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; diff --git a/tests/baselines/reference/intrinsicTypes.errors.txt b/tests/baselines/reference/intrinsicTypes.errors.txt index 1be876189490b..57ddb10a02a4c 100644 --- a/tests/baselines/reference/intrinsicTypes.errors.txt +++ b/tests/baselines/reference/intrinsicTypes.errors.txt @@ -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 - type TU4 = Uppercase; // any + type TU3 = Uppercase; // Uppercase + type TU4 = Uppercase; // Uppercase<`${any}`> type TU5 = Uppercase; // 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 - type TL4 = Lowercase; // any + type TL3 = Lowercase; // Lowercase + type TL4 = Lowercase; // Lowercase<`${any}`> type TL5 = Lowercase; // 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 - type TC4 = Capitalize; // any + type TC3 = Capitalize; // Capitalize + type TC4 = Capitalize; // Capitalize<`${any}`> type TC5 = Capitalize; // 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 - type TN4 = Uncapitalize; // any + type TN3 = Uncapitalize; // Uncapitalize + type TN4 = Uncapitalize; // Uncapitalize<`${any}`> type TN5 = Uncapitalize; // never type TN6 = Uncapitalize<42>; // Error ~~ diff --git a/tests/baselines/reference/intrinsicTypes.js b/tests/baselines/reference/intrinsicTypes.js index 697371da226ff..c8cb24fb9c5c3 100644 --- a/tests/baselines/reference/intrinsicTypes.js +++ b/tests/baselines/reference/intrinsicTypes.js @@ -1,29 +1,29 @@ //// [intrinsicTypes.ts] type TU1 = Uppercase<'hello'>; // "HELLO" type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR" -type TU3 = Uppercase; // string -type TU4 = Uppercase; // any +type TU3 = Uppercase; // Uppercase +type TU4 = Uppercase; // Uppercase<`${any}`> type TU5 = Uppercase; // never type TU6 = Uppercase<42>; // Error type TL1 = Lowercase<'HELLO'>; // "hello" type TL2 = Lowercase<'FOO' | 'BAR'>; // "foo" | "bar" -type TL3 = Lowercase; // string -type TL4 = Lowercase; // any +type TL3 = Lowercase; // Lowercase +type TL4 = Lowercase; // Lowercase<`${any}`> type TL5 = Lowercase; // never type TL6 = Lowercase<42>; // Error type TC1 = Capitalize<'hello'>; // "Hello" type TC2 = Capitalize<'foo' | 'bar'>; // "Foo" | "Bar" -type TC3 = Capitalize; // string -type TC4 = Capitalize; // any +type TC3 = Capitalize; // Capitalize +type TC4 = Capitalize; // Capitalize<`${any}`> type TC5 = Capitalize; // never type TC6 = Capitalize<42>; // Error type TN1 = Uncapitalize<'Hello'>; // "hello" type TN2 = Uncapitalize<'Foo' | 'Bar'>; // "foo" | "bar" -type TN3 = Uncapitalize; // string -type TN4 = Uncapitalize; // any +type TN3 = Uncapitalize; // Uncapitalize +type TN4 = Uncapitalize; // Uncapitalize<`${any}`> type TN5 = Uncapitalize; // never type TN6 = Uncapitalize<42>; // Error diff --git a/tests/baselines/reference/intrinsicTypes.symbols b/tests/baselines/reference/intrinsicTypes.symbols index 13efe08aaa237..8e5e78359a9c8 100644 --- a/tests/baselines/reference/intrinsicTypes.symbols +++ b/tests/baselines/reference/intrinsicTypes.symbols @@ -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 +type TU3 = Uppercase; // Uppercase >TU3 : Symbol(TU3, Decl(intrinsicTypes.ts, 1, 36)) >Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --)) -type TU4 = Uppercase; // any +type TU4 = Uppercase; // 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 +type TL3 = Lowercase; // Lowercase >TL3 : Symbol(TL3, Decl(intrinsicTypes.ts, 8, 36)) >Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --)) -type TL4 = Lowercase; // any +type TL4 = Lowercase; // 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 +type TC3 = Capitalize; // Capitalize >TC3 : Symbol(TC3, Decl(intrinsicTypes.ts, 15, 37)) >Capitalize : Symbol(Capitalize, Decl(lib.es5.d.ts, --, --)) -type TC4 = Capitalize; // any +type TC4 = Capitalize; // 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 +type TN3 = Uncapitalize; // Uncapitalize >TN3 : Symbol(TN3, Decl(intrinsicTypes.ts, 22, 39)) >Uncapitalize : Symbol(Uncapitalize, Decl(lib.es5.d.ts, --, --)) -type TN4 = Uncapitalize; // any +type TN4 = Uncapitalize; // Uncapitalize<`${any}`> >TN4 : Symbol(TN4, Decl(intrinsicTypes.ts, 23, 32)) >Uncapitalize : Symbol(Uncapitalize, Decl(lib.es5.d.ts, --, --)) diff --git a/tests/baselines/reference/intrinsicTypes.types b/tests/baselines/reference/intrinsicTypes.types index 00123d307e0f7..d17e37284c10b 100644 --- a/tests/baselines/reference/intrinsicTypes.types +++ b/tests/baselines/reference/intrinsicTypes.types @@ -5,11 +5,11 @@ type TU1 = Uppercase<'hello'>; // "HELLO" type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR" >TU2 : "FOO" | "BAR" -type TU3 = Uppercase; // string ->TU3 : string +type TU3 = Uppercase; // Uppercase +>TU3 : Uppercase -type TU4 = Uppercase; // any ->TU4 : any +type TU4 = Uppercase; // Uppercase<`${any}`> +>TU4 : Uppercase<`${any}`> type TU5 = Uppercase; // 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 ->TL3 : string +type TL3 = Lowercase; // Lowercase +>TL3 : Lowercase -type TL4 = Lowercase; // any ->TL4 : any +type TL4 = Lowercase; // Lowercase<`${any}`> +>TL4 : Lowercase<`${any}`> type TL5 = Lowercase; // 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 ->TC3 : string +type TC3 = Capitalize; // Capitalize +>TC3 : Capitalize -type TC4 = Capitalize; // any ->TC4 : any +type TC4 = Capitalize; // Capitalize<`${any}`> +>TC4 : Capitalize<`${any}`> type TC5 = Capitalize; // 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 ->TN3 : string +type TN3 = Uncapitalize; // Uncapitalize +>TN3 : Uncapitalize -type TN4 = Uncapitalize; // any ->TN4 : any +type TN4 = Uncapitalize; // Uncapitalize<`${any}`> +>TN4 : Uncapitalize<`${any}`> type TN5 = Uncapitalize; // never >TN5 : never diff --git a/tests/baselines/reference/mappedTypeConstraints2.errors.txt b/tests/baselines/reference/mappedTypeConstraints2.errors.txt index 7950e9d0f5494..d2bb04de62400 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.errors.txt +++ b/tests/baselines/reference/mappedTypeConstraints2.errors.txt @@ -1,7 +1,8 @@ tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(10,11): error TS2322: Type 'Mapped2[`get${K}`]' is not assignable to type '{ a: K; }'. Type 'Mapped2[`get${string}`]' is not assignable to type '{ a: K; }'. tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(16,11): error TS2322: Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. - Type 'Mapped3[string]' is not assignable to type '{ a: K; }'. + Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. + Type 'Mapped3[string]' is not assignable to type '{ a: K; }'. tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo[`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[Uppercase]' is not assignable to type '{ a: K; }'. -!!! error TS2322: Type 'Mapped3[string]' is not assignable to type '{ a: K; }'. +!!! error TS2322: Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. +!!! error TS2322: Type 'Mapped3[string]' is not assignable to type '{ a: K; }'. } // Repro from #47794 diff --git a/tests/baselines/reference/stringLiteralsAssignedToStringMappings.errors.txt b/tests/baselines/reference/stringLiteralsAssignedToStringMappings.errors.txt new file mode 100644 index 0000000000000..63890e6891284 --- /dev/null +++ b/tests/baselines/reference/stringLiteralsAssignedToStringMappings.errors.txt @@ -0,0 +1,28 @@ +tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts(7,1): error TS2322: Type 'string' is not assignable to type 'Uppercase>'. +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>; + + // good + x = "A"; + + // bad + x = "a"; + ~ +!!! error TS2322: Type 'string' is not assignable to type 'Uppercase>'. + + declare var y: Uppercase>; + + // 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}`>}`>'. \ No newline at end of file diff --git a/tests/baselines/reference/stringLiteralsAssignedToStringMappings.js b/tests/baselines/reference/stringLiteralsAssignedToStringMappings.js new file mode 100644 index 0000000000000..3b870caff6642 --- /dev/null +++ b/tests/baselines/reference/stringLiteralsAssignedToStringMappings.js @@ -0,0 +1,28 @@ +//// [stringLiteralsAssignedToStringMappings.ts] +declare var x: Uppercase>; + +// good +x = "A"; + +// bad +x = "a"; + +declare var y: Uppercase>; + +// good +y = "1"; + +// bad +y = "a"; +y = "A"; + +//// [stringLiteralsAssignedToStringMappings.js] +// good +x = "A"; +// bad +x = "a"; +// good +y = "1"; +// bad +y = "a"; +y = "A"; diff --git a/tests/baselines/reference/stringLiteralsAssignedToStringMappings.symbols b/tests/baselines/reference/stringLiteralsAssignedToStringMappings.symbols new file mode 100644 index 0000000000000..e680e6a0ba120 --- /dev/null +++ b/tests/baselines/reference/stringLiteralsAssignedToStringMappings.symbols @@ -0,0 +1,30 @@ +=== tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts === +declare var x: Uppercase>; +>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>; +>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)) + diff --git a/tests/baselines/reference/stringLiteralsAssignedToStringMappings.types b/tests/baselines/reference/stringLiteralsAssignedToStringMappings.types new file mode 100644 index 0000000000000..34e7963a8e662 --- /dev/null +++ b/tests/baselines/reference/stringLiteralsAssignedToStringMappings.types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts === +declare var x: Uppercase>; +>x : Uppercase> + +// good +x = "A"; +>x = "A" : "A" +>x : Uppercase> +>"A" : "A" + +// bad +x = "a"; +>x = "a" : "a" +>x : Uppercase> +>"a" : "a" + +declare var y: Uppercase>; +>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" + diff --git a/tests/baselines/reference/stringMappingOverPatternLiterals.errors.txt b/tests/baselines/reference/stringMappingOverPatternLiterals.errors.txt new file mode 100644 index 0000000000000..c816db1a0d536 --- /dev/null +++ b/tests/baselines/reference/stringMappingOverPatternLiterals.errors.txt @@ -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}`' 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}`' 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}`' is not assignable to type '`aA${string}`'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(31,5): error TS2322: Type '`aa${Lowercase}`' 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}`'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(34,5): error TS2322: Type '`aa${Lowercase}`' is not assignable to type '`AA${Uppercase}`'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(36,5): error TS2322: Type '`aA${string}`' is not assignable to type '`aa${Lowercase}`'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(37,5): error TS2322: Type '`AA${Uppercase}`' is not assignable to type '`aa${Lowercase}`'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(51,5): error TS2322: Type 'string' is not assignable to type 'Uppercase'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(52,5): error TS2322: Type 'Lowercase' is not assignable to type 'Uppercase'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(53,5): error TS2322: Type 'string' is not assignable to type 'Lowercase'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(54,5): error TS2322: Type 'Uppercase' is not assignable to type 'Lowercase'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(56,5): error TS2322: Type 'string' is not assignable to type 'Uppercase'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(57,5): error TS2322: Type 'string' is not assignable to type 'Lowercase'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(78,5): error TS2322: Type 'Uppercase' is not assignable to type 'Uppercase>'. + Type 'string' is not assignable to type 'Lowercase'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(79,5): error TS2322: Type 'Uppercase' is not assignable to type 'Uppercase>'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(83,5): error TS2322: Type 'Lowercase>' is not assignable to type 'Uppercase'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(84,5): error TS2322: Type 'Lowercase>' is not assignable to type 'Uppercase'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(85,5): error TS2322: Type 'Lowercase>' is not assignable to type 'Uppercase>'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(87,5): error TS2322: Type 'Uppercase' is not assignable to type 'Lowercase>'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(88,5): error TS2322: Type 'Uppercase' is not assignable to type 'Lowercase>'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(89,5): error TS2322: Type 'Uppercase>' is not assignable to type 'Lowercase>'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(129,5): error TS2322: Type 'Capitalize' 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' is not assignable to type '`A${string}`'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(131,5): error TS2322: Type 'Capitalize' is not assignable to type '`A${string}`'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(147,5): error TS2322: Type 'Uncapitalize' 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' is not assignable to type '`a${string}`'. +tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts(149,5): error TS2322: Type 'Uncapitalize' is not assignable to type '`a${string}`'. + + +==== tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts (29 errors) ==== + // non-template + type A = "aA"; + type B = Uppercase; + type C = Lowercase; + + // templated + type ATemplate = `aA${string}`; + type BTemplate = Uppercase; + type CTemplate = Lowercase; + + 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}`' 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}`' 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}`' is not assignable to type '`aA${string}`'. + a_template = c_template; + ~~~~~~~~~~ +!!! error TS2322: Type '`aa${Lowercase}`' is not assignable to type '`aA${string}`'. + + b_template = a_template; + ~~~~~~~~~~ +!!! error TS2322: Type '`aA${string}`' is not assignable to type '`AA${Uppercase}`'. + b_template = c_template; + ~~~~~~~~~~ +!!! error TS2322: Type '`aa${Lowercase}`' is not assignable to type '`AA${Uppercase}`'. + + c_template = a_template; + ~~~~~~~~~~ +!!! error TS2322: Type '`aA${string}`' is not assignable to type '`aa${Lowercase}`'. + c_template = b_template; + ~~~~~~~~~~ +!!! error TS2322: Type '`AA${Uppercase}`' is not assignable to type '`aa${Lowercase}`'. + } + + // Raw string mapping assignability + + function f2(x1: string, x2: Uppercase, x3: Lowercase) { + // 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'. + x2 = x3; + ~~ +!!! error TS2322: Type 'Lowercase' is not assignable to type 'Uppercase'. + x3 = x1; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'Lowercase'. + x3 = x2; + ~~ +!!! error TS2322: Type 'Uppercase' is not assignable to type 'Lowercase'. + + x2 = "AbC"; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'Uppercase'. + x3 = "AbC"; + ~~ +!!! error TS2322: Type 'string' is not assignable to type 'Lowercase'. + } + + // Mappings over mappings + + function f3( + x1: Uppercase, + x2: Uppercase>, + x3: Uppercase>) { + + // _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' is not assignable to type 'Uppercase>'. +!!! error TS2322: Type 'string' is not assignable to type 'Lowercase'. + x3 = x2; + ~~ +!!! error TS2322: Type 'Uppercase' is not assignable to type 'Uppercase>'. + + // and this should also not be equivlent to any others + var x4: Lowercase> = null as any; + x1 = x4; + ~~ +!!! error TS2322: Type 'Lowercase>' is not assignable to type 'Uppercase'. + x2 = x4; + ~~ +!!! error TS2322: Type 'Lowercase>' is not assignable to type 'Uppercase'. + x3 = x4; + ~~ +!!! error TS2322: Type 'Lowercase>' is not assignable to type 'Uppercase>'. + + x4 = x1; + ~~ +!!! error TS2322: Type 'Uppercase' is not assignable to type 'Lowercase>'. + x4 = x2; + ~~ +!!! error TS2322: Type 'Uppercase' is not assignable to type 'Lowercase>'. + x4 = x3; + ~~ +!!! error TS2322: Type 'Uppercase>' is not assignable to type 'Lowercase>'. + } + + // 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, + cap_tem_map: Capitalize<`A${string}`>, + cap_tem_map2: Capitalize<`a${string}`>, + uncap_tem: `a${string}`, + uncap_str: Uncapitalize, + 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' 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' is not assignable to type '`A${string}`'. + cap_tem_map2 = cap_str; + ~~~~~~~~~~~~ +!!! error TS2322: Type 'Capitalize' 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' 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' is not assignable to type '`a${string}`'. + uncap_tem_map2 = uncap_str; + ~~~~~~~~~~~~~~ +!!! error TS2322: Type 'Uncapitalize' is not assignable to type '`a${string}`'. + } \ No newline at end of file diff --git a/tests/baselines/reference/stringMappingOverPatternLiterals.js b/tests/baselines/reference/stringMappingOverPatternLiterals.js new file mode 100644 index 0000000000000..7196c71e1f13c --- /dev/null +++ b/tests/baselines/reference/stringMappingOverPatternLiterals.js @@ -0,0 +1,245 @@ +//// [stringMappingOverPatternLiterals.ts] +// non-template +type A = "aA"; +type B = Uppercase; +type C = Lowercase; + +// templated +type ATemplate = `aA${string}`; +type BTemplate = Uppercase; +type CTemplate = Lowercase; + +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, x3: Lowercase) { + // 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, + x2: Uppercase>, + x3: Uppercase>) { + + // _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> = 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, + cap_tem_map: Capitalize<`A${string}`>, + cap_tem_map2: Capitalize<`a${string}`>, + uncap_tem: `a${string}`, + uncap_str: Uncapitalize, + 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; +} diff --git a/tests/baselines/reference/stringMappingOverPatternLiterals.symbols b/tests/baselines/reference/stringMappingOverPatternLiterals.symbols new file mode 100644 index 0000000000000..be7369268fcba --- /dev/null +++ b/tests/baselines/reference/stringMappingOverPatternLiterals.symbols @@ -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; +>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; +>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; +>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; +>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, x3: Lowercase) { +>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, +>x1 : Symbol(x1, Decl(stringMappingOverPatternLiterals.ts, 61, 12)) +>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --)) + + x2: Uppercase>, +>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>) { +>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> = 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, +>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, +>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)) +} diff --git a/tests/baselines/reference/stringMappingOverPatternLiterals.types b/tests/baselines/reference/stringMappingOverPatternLiterals.types new file mode 100644 index 0000000000000..eb6730c14977c --- /dev/null +++ b/tests/baselines/reference/stringMappingOverPatternLiterals.types @@ -0,0 +1,435 @@ +=== tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts === +// non-template +type A = "aA"; +>A : "aA" + +type B = Uppercase; +>B : "AA" + +type C = Lowercase; +>C : "aa" + +// templated +type ATemplate = `aA${string}`; +>ATemplate : `aA${string}` + +type BTemplate = Uppercase; +>BTemplate : `AA${Uppercase}` + +type CTemplate = Lowercase; +>CTemplate : `aa${Lowercase}` + +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}` + + c_template: CTemplate +>c_template : `aa${Lowercase}` + +) { + // 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}` +>b : "AA" + + c_template = c; +>c_template = c : "aa" +>c_template : `aa${Lowercase}` +>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}` +>b : "AA" +>b_template : `AA${Uppercase}` + + c = c_template; +>c = c_template : `aa${Lowercase}` +>c : "aa" +>c_template : `aa${Lowercase}` + + // Additionally, all the template versions should be mutually incompatible (they describe differing sets) + a_template = b_template; +>a_template = b_template : `AA${Uppercase}` +>a_template : `aA${string}` +>b_template : `AA${Uppercase}` + + a_template = c_template; +>a_template = c_template : `aa${Lowercase}` +>a_template : `aA${string}` +>c_template : `aa${Lowercase}` + + b_template = a_template; +>b_template = a_template : `aA${string}` +>b_template : `AA${Uppercase}` +>a_template : `aA${string}` + + b_template = c_template; +>b_template = c_template : `aa${Lowercase}` +>b_template : `AA${Uppercase}` +>c_template : `aa${Lowercase}` + + c_template = a_template; +>c_template = a_template : `aA${string}` +>c_template : `aa${Lowercase}` +>a_template : `aA${string}` + + c_template = b_template; +>c_template = b_template : `AA${Uppercase}` +>c_template : `aa${Lowercase}` +>b_template : `AA${Uppercase}` +} + +// Raw string mapping assignability + +function f2(x1: string, x2: Uppercase, x3: Lowercase) { +>f2 : (x1: string, x2: Uppercase, x3: Lowercase) => void +>x1 : string +>x2 : Uppercase +>x3 : Lowercase + + // ok + x1 = x2; +>x1 = x2 : Uppercase +>x1 : string +>x2 : Uppercase + + x1 = x3; +>x1 = x3 : Lowercase +>x1 : string +>x3 : Lowercase + + x2 = "ABC"; +>x2 = "ABC" : "ABC" +>x2 : Uppercase +>"ABC" : "ABC" + + x3 = "abc"; +>x3 = "abc" : "abc" +>x3 : Lowercase +>"abc" : "abc" + + // should fail (sets do not match) + x2 = x1; +>x2 = x1 : string +>x2 : Uppercase +>x1 : string + + x2 = x3; +>x2 = x3 : Lowercase +>x2 : Uppercase +>x3 : Lowercase + + x3 = x1; +>x3 = x1 : string +>x3 : Lowercase +>x1 : string + + x3 = x2; +>x3 = x2 : Uppercase +>x3 : Lowercase +>x2 : Uppercase + + x2 = "AbC"; +>x2 = "AbC" : "AbC" +>x2 : Uppercase +>"AbC" : "AbC" + + x3 = "AbC"; +>x3 = "AbC" : "AbC" +>x3 : Lowercase +>"AbC" : "AbC" +} + +// Mappings over mappings + +function f3( +>f3 : (x1: Uppercase, x2: Uppercase>, x3: Uppercase>) => void + + x1: Uppercase, +>x1 : Uppercase + + x2: Uppercase>, +>x2 : Uppercase + + x3: Uppercase>) { +>x3 : Uppercase> + + // _ideally_ these would all be equivalent + x1 = x2; +>x1 = x2 : Uppercase +>x1 : Uppercase +>x2 : Uppercase + + x1 = x3; +>x1 = x3 : Uppercase> +>x1 : Uppercase +>x3 : Uppercase> + + x2 = x1; +>x2 = x1 : Uppercase +>x2 : Uppercase +>x1 : Uppercase + + x2 = x3; +>x2 = x3 : Uppercase> +>x2 : Uppercase +>x3 : Uppercase> + + // 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 +>x3 : Uppercase> +>x1 : Uppercase + + x3 = x2; +>x3 = x2 : Uppercase +>x3 : Uppercase> +>x2 : Uppercase + + // and this should also not be equivlent to any others + var x4: Lowercase> = null as any; +>x4 : Lowercase> +>null as any : any +>null : null + + x1 = x4; +>x1 = x4 : Lowercase> +>x1 : Uppercase +>x4 : Lowercase> + + x2 = x4; +>x2 = x4 : Lowercase> +>x2 : Uppercase +>x4 : Lowercase> + + x3 = x4; +>x3 = x4 : Lowercase> +>x3 : Uppercase> +>x4 : Lowercase> + + x4 = x1; +>x4 = x1 : Uppercase +>x4 : Lowercase> +>x1 : Uppercase + + x4 = x2; +>x4 = x2 : Uppercase +>x4 : Lowercase> +>x2 : Uppercase + + x4 = x3; +>x4 = x3 : Uppercase> +>x4 : Lowercase> +>x3 : Uppercase> +} + +// 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, cap_tem_map: Capitalize<`A${string}`>, cap_tem_map2: Capitalize<`a${string}`>, uncap_tem: `a${string}`, uncap_str: Uncapitalize, uncap_tem_map: Uncapitalize<`A${string}`>, uncap_tem_map2: Uncapitalize<`a${string}`>) => void + + cap_tem: `A${string}`, +>cap_tem : `A${string}` + + cap_str: Capitalize, +>cap_str : Capitalize + + 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, +>uncap_str : Uncapitalize + + 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 +>cap_tem : `A${string}` + + cap_str = cap_tem_map; +>cap_str = cap_tem_map : `A${string}` +>cap_str : Capitalize +>cap_tem_map : `A${string}` + + cap_str = cap_tem_map2; +>cap_str = cap_tem_map2 : `A${string}` +>cap_str : Capitalize +>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 +>cap_tem : `A${string}` +>cap_str : Capitalize + + cap_tem_map = cap_str; +>cap_tem_map = cap_str : Capitalize +>cap_tem_map : `A${string}` +>cap_str : Capitalize + + cap_tem_map2 = cap_str; +>cap_tem_map2 = cap_str : Capitalize +>cap_tem_map2 : `A${string}` +>cap_str : Capitalize + + // All these are uncapitalized + uncap_str = uncap_tem; +>uncap_str = uncap_tem : `a${string}` +>uncap_str : Uncapitalize +>uncap_tem : `a${string}` + + uncap_str = uncap_tem_map; +>uncap_str = uncap_tem_map : `a${string}` +>uncap_str : Uncapitalize +>uncap_tem_map : `a${string}` + + uncap_str = uncap_tem_map2; +>uncap_str = uncap_tem_map2 : `a${string}` +>uncap_str : Uncapitalize +>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 +>uncap_tem : `a${string}` +>uncap_str : Uncapitalize + + uncap_tem_map = uncap_str; +>uncap_tem_map = uncap_str : Uncapitalize +>uncap_tem_map : `a${string}` +>uncap_str : Uncapitalize + + uncap_tem_map2 = uncap_str; +>uncap_tem_map2 = uncap_str : Uncapitalize +>uncap_tem_map2 : `a${string}` +>uncap_str : Uncapitalize +} diff --git a/tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts b/tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts new file mode 100644 index 0000000000000..23c5b70242131 --- /dev/null +++ b/tests/cases/conformance/types/literal/stringLiteralsAssignedToStringMappings.ts @@ -0,0 +1,16 @@ +declare var x: Uppercase>; + +// good +x = "A"; + +// bad +x = "a"; + +declare var y: Uppercase>; + +// good +y = "1"; + +// bad +y = "a"; +y = "A"; \ No newline at end of file diff --git a/tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts b/tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts new file mode 100644 index 0000000000000..a5c9e942b3bf9 --- /dev/null +++ b/tests/cases/conformance/types/literal/stringMappingOverPatternLiterals.ts @@ -0,0 +1,150 @@ +// non-template +type A = "aA"; +type B = Uppercase; +type C = Lowercase; + +// templated +type ATemplate = `aA${string}`; +type BTemplate = Uppercase; +type CTemplate = Lowercase; + +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, x3: Lowercase) { + // 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, + x2: Uppercase>, + x3: Uppercase>) { + + // _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> = 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, + cap_tem_map: Capitalize<`A${string}`>, + cap_tem_map2: Capitalize<`a${string}`>, + uncap_tem: `a${string}`, + uncap_str: Uncapitalize, + 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; +} \ No newline at end of file diff --git a/tests/cases/conformance/types/typeAliases/intrinsicTypes.ts b/tests/cases/conformance/types/typeAliases/intrinsicTypes.ts index cfdf08d0609f0..118595e53cd73 100644 --- a/tests/cases/conformance/types/typeAliases/intrinsicTypes.ts +++ b/tests/cases/conformance/types/typeAliases/intrinsicTypes.ts @@ -3,29 +3,29 @@ type TU1 = Uppercase<'hello'>; // "HELLO" type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR" -type TU3 = Uppercase; // string -type TU4 = Uppercase; // any +type TU3 = Uppercase; // Uppercase +type TU4 = Uppercase; // Uppercase<`${any}`> type TU5 = Uppercase; // never type TU6 = Uppercase<42>; // Error type TL1 = Lowercase<'HELLO'>; // "hello" type TL2 = Lowercase<'FOO' | 'BAR'>; // "foo" | "bar" -type TL3 = Lowercase; // string -type TL4 = Lowercase; // any +type TL3 = Lowercase; // Lowercase +type TL4 = Lowercase; // Lowercase<`${any}`> type TL5 = Lowercase; // never type TL6 = Lowercase<42>; // Error type TC1 = Capitalize<'hello'>; // "Hello" type TC2 = Capitalize<'foo' | 'bar'>; // "Foo" | "Bar" -type TC3 = Capitalize; // string -type TC4 = Capitalize; // any +type TC3 = Capitalize; // Capitalize +type TC4 = Capitalize; // Capitalize<`${any}`> type TC5 = Capitalize; // never type TC6 = Capitalize<42>; // Error type TN1 = Uncapitalize<'Hello'>; // "hello" type TN2 = Uncapitalize<'Foo' | 'Bar'>; // "foo" | "bar" -type TN3 = Uncapitalize; // string -type TN4 = Uncapitalize; // any +type TN3 = Uncapitalize; // Uncapitalize +type TN4 = Uncapitalize; // Uncapitalize<`${any}`> type TN5 = Uncapitalize; // never type TN6 = Uncapitalize<42>; // Error