diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f175b6806551b..1508e98e89645 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -339,6 +339,7 @@ import { getPropertyAssignmentAliasLikeExpression, getPropertyNameForPropertyNameNode, getPropertyNameFromType, + getRawTextOfTemplateLiteralLike, getResolutionDiagnostic, getResolutionModeOverride, getResolvedExternalModuleName, @@ -651,6 +652,7 @@ import { isNewExpression, isNodeDescendantOf, isNonNullAccess, + isNoSubstitutionTemplateLiteral, isNullishCoalesce, isNumericLiteral, isNumericLiteralName, @@ -719,6 +721,7 @@ import { isSuperCall, isSuperProperty, isTaggedTemplateExpression, + isTemplateLiteral, isTemplateSpan, isThisContainerOrFunctionBlock, isThisIdentifier, @@ -998,6 +1001,7 @@ import { SyntheticExpression, TaggedTemplateExpression, TemplateExpression, + TemplateLiteralLikeNode, TemplateLiteralType, TemplateLiteralTypeNode, Ternary, @@ -2169,6 +2173,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var deferredGlobalAsyncIterableIteratorType: GenericType | undefined; var deferredGlobalAsyncGeneratorType: GenericType | undefined; var deferredGlobalTemplateStringsArrayType: ObjectType | undefined; + var deferredGlobalTemplateStringsArrayOfSymbol: Symbol | undefined; var deferredGlobalImportMetaType: ObjectType; var deferredGlobalImportMetaExpressionType: ObjectType; var deferredGlobalImportCallOptionsType: ObjectType | undefined; @@ -16628,6 +16633,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return deferredGlobalRecordSymbol === unknownSymbol ? undefined : deferredGlobalRecordSymbol; } + function getGlobalTemplateStringsArrayOfSymbol(): Symbol | undefined { + deferredGlobalTemplateStringsArrayOfSymbol ||= getGlobalTypeAliasSymbol("TemplateStringsArrayOf" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; + return deferredGlobalTemplateStringsArrayOfSymbol === unknownSymbol ? undefined : deferredGlobalTemplateStringsArrayOfSymbol; + } + /** * Instantiates a global type that is generic with some element type, and returns that instantiation. */ @@ -24301,6 +24311,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isMutableArrayOrTuple(type) || !(type.flags & (TypeFlags.Any | TypeFlags.Nullable)) && isTypeAssignableTo(type, anyArrayType); } + /** + * Returns `type` if it is an array or tuple type. If `type` is an intersection type, + * returns the rightmost constituent that is an array or tuple type, but only if there are no + * other constituents to that contain properties that overlap with array- or tuple- specific + * members (i.e., index signatures, numeric string property names, or `length`). + */ + function tryGetNonShadowedArrayOrTupleType(type: Type) { + if (isArrayOrTupleType(type)) { + return type; + } + + if (!(type.flags & TypeFlags.Intersection)) { + return undefined; + } + + let arrayOrTupleConstituent: TypeReference | undefined; + for (const constituent of (type as IntersectionType).types) { + if (isArrayOrTupleType(constituent)) { + // If this is an intersection of two array or tuple types, prefer neither. + if (arrayOrTupleConstituent) { + return undefined; + } + arrayOrTupleConstituent = constituent; + } + } + + if (arrayOrTupleConstituent) { + for (const constituent of (type as IntersectionType).types) { + if (constituent !== arrayOrTupleConstituent) { + const properties = getPropertiesOfType(constituent); + for (const property of properties) { + if (isNumericLiteralName(property.escapedName) || property.escapedName === "length" as __String) { + return undefined; + } + } + + if (some(getIndexInfosOfType(constituent))) { + return undefined; + } + } + } + } + + return arrayOrTupleConstituent; + } + + function getSingleBaseForNonAugmentingSubtype(type: Type) { if (!(getObjectFlags(type) & ObjectFlags.Reference) || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)) { return undefined; @@ -26075,29 +26132,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Infer from the members of source and target only if the two types are possibly related if (!typesDefinitelyUnrelated(source, target)) { - if (isArrayOrTupleType(source)) { + const sourceArrayOrTuple = tryGetNonShadowedArrayOrTupleType(source); + if (sourceArrayOrTuple) { if (isTupleType(target)) { - const sourceArity = getTypeReferenceArity(source); + const sourceArity = getTypeReferenceArity(sourceArrayOrTuple); const targetArity = getTypeReferenceArity(target); const elementTypes = getTypeArguments(target); const elementFlags = target.target.elementFlags; // When source and target are tuple types with the same structure (fixed, variadic, and rest are matched // to the same kind in each position), simply infer between the element types. - if (isTupleType(source) && isTupleTypeStructureMatching(source, target)) { + if (isTupleType(sourceArrayOrTuple) && isTupleTypeStructureMatching(sourceArrayOrTuple, target)) { for (let i = 0; i < targetArity; i++) { - inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); + inferFromTypes(getTypeArguments(sourceArrayOrTuple)[i], elementTypes[i]); } return; } - const startLength = isTupleType(source) ? Math.min(source.target.fixedLength, target.target.fixedLength) : 0; - const endLength = Math.min(isTupleType(source) ? getEndElementCount(source.target, ElementFlags.Fixed) : 0, target.target.hasRestElement ? getEndElementCount(target.target, ElementFlags.Fixed) : 0); + const startLength = isTupleType(sourceArrayOrTuple) ? Math.min(sourceArrayOrTuple.target.fixedLength, target.target.fixedLength) : 0; + const endLength = Math.min(isTupleType(sourceArrayOrTuple) ? getEndElementCount(sourceArrayOrTuple.target, ElementFlags.Fixed) : 0, target.target.hasRestElement ? getEndElementCount(target.target, ElementFlags.Fixed) : 0); // Infer between starting fixed elements. for (let i = 0; i < startLength; i++) { - inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); + inferFromTypes(getTypeArguments(sourceArrayOrTuple)[i], elementTypes[i]); } - if (!isTupleType(source) || sourceArity - startLength - endLength === 1 && source.target.elementFlags[startLength] & ElementFlags.Rest) { + if (!isTupleType(sourceArrayOrTuple) || sourceArity - startLength - endLength === 1 && sourceArrayOrTuple.target.elementFlags[startLength] & ElementFlags.Rest) { // Single rest element remains in source, infer from that to every element in target - const restType = getTypeArguments(source)[startLength]; + const restType = getTypeArguments(sourceArrayOrTuple)[startLength]; for (let i = startLength; i < targetArity - endLength; i++) { inferFromTypes(elementFlags[i] & ElementFlags.Variadic ? createArrayType(restType) : restType, elementTypes[i]); } @@ -26110,8 +26168,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetInfo = getInferenceInfoForType(elementTypes[startLength]); if (targetInfo && targetInfo.impliedArity !== undefined) { // Infer slices from source based on implied arity of T. - inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]); - inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); + inferFromTypes(sliceTupleType(sourceArrayOrTuple, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]); + inferFromTypes(sliceTupleType(sourceArrayOrTuple, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); } } else if (elementFlags[startLength] & ElementFlags.Variadic && elementFlags[startLength + 1] & ElementFlags.Rest) { @@ -26121,8 +26179,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constraint = param && getBaseConstraintOfType(param); if (constraint && isTupleType(constraint) && !constraint.target.hasRestElement) { const impliedArity = constraint.target.fixedLength; - inferFromTypes(sliceTupleType(source, startLength, sourceArity - (startLength + impliedArity)), elementTypes[startLength]); - inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength + impliedArity, endLength)!, elementTypes[startLength + 1]); + inferFromTypes(sliceTupleType(sourceArrayOrTuple, startLength, sourceArity - (startLength + impliedArity)), elementTypes[startLength]); + inferFromTypes(getElementTypeOfSliceOfTupleType(sourceArrayOrTuple, startLength + impliedArity, endLength)!, elementTypes[startLength + 1]); } } else if (elementFlags[startLength] & ElementFlags.Rest && elementFlags[startLength + 1] & ElementFlags.Variadic) { @@ -26134,9 +26192,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const impliedArity = constraint.target.fixedLength; const endIndex = sourceArity - getEndElementCount(target.target, ElementFlags.Fixed); const startIndex = endIndex - impliedArity; - const trailingSlice = createTupleType(getTypeArguments(source).slice(startIndex, endIndex), source.target.elementFlags.slice(startIndex, endIndex), /*readonly*/ false, source.target.labeledElementDeclarations && source.target.labeledElementDeclarations.slice(startIndex, endIndex)); + const trailingSlice = createTupleType(getTypeArguments(sourceArrayOrTuple).slice(startIndex, endIndex), sourceArrayOrTuple.target.elementFlags.slice(startIndex, endIndex), /*readonly*/ false, sourceArrayOrTuple.target.labeledElementDeclarations && sourceArrayOrTuple.target.labeledElementDeclarations.slice(startIndex, endIndex)); - inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength, endLength + impliedArity)!, elementTypes[startLength]); + inferFromTypes(getElementTypeOfSliceOfTupleType(sourceArrayOrTuple, startLength, endLength + impliedArity)!, elementTypes[startLength]); inferFromTypes(trailingSlice, elementTypes[startLength + 1]); } } @@ -26145,12 +26203,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Middle of target is exactly one variadic element. Infer the slice between the fixed parts in the source. // If target ends in optional element(s), make a lower priority a speculative inference. const endsInOptional = target.target.elementFlags[targetArity - 1] & ElementFlags.Optional; - const sourceSlice = sliceTupleType(source, startLength, endLength); + const sourceSlice = sliceTupleType(sourceArrayOrTuple, startLength, endLength); inferWithPriority(sourceSlice, elementTypes[startLength], endsInOptional ? InferencePriority.SpeculativeTuple : 0); } else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Rest) { // Middle of target is exactly one rest element. If middle of source is not empty, infer union of middle element types. - const restType = getElementTypeOfSliceOfTupleType(source, startLength, endLength); + const restType = getElementTypeOfSliceOfTupleType(sourceArrayOrTuple, startLength, endLength); if (restType) { inferFromTypes(restType, elementTypes[startLength]); } @@ -26158,12 +26216,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Infer between ending fixed elements for (let i = 0; i < endLength; i++) { - inferFromTypes(getTypeArguments(source)[sourceArity - i - 1], elementTypes[targetArity - i - 1]); + inferFromTypes(getTypeArguments(sourceArrayOrTuple)[sourceArity - i - 1], elementTypes[targetArity - i - 1]); } return; } if (isArrayType(target)) { - inferFromIndexTypes(source, target); + inferFromIndexTypes(sourceArrayOrTuple, target); return; } } @@ -31336,7 +31394,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkIteratedTypeOrElementType(IterationUse.Spread, arrayOrIterableType, undefinedType, node.expression); } + function getTemplateStringsArrayOf(cookedTypes: Type[], rawTypes: Type[]) { + const templateStringsArrayOfAlias = getGlobalTemplateStringsArrayOfSymbol(); + if (!templateStringsArrayOfAlias) return getGlobalTemplateStringsArrayType(); + const cookedType = createTupleType(cookedTypes, /*elementFlags*/ undefined, /*readonly*/ true); + const rawType = createTupleType(rawTypes, /*elementFlags*/ undefined, /*readonly*/ true); + return getTypeAliasInstantiation(templateStringsArrayOfAlias, [cookedType, rawType]); + } + + function getRawLiteralType(node: TemplateLiteralLikeNode) { + const text = getRawTextOfTemplateLiteralLike(node, getSourceFileOfNode(node)); + return getStringLiteralType(text); + } + function checkSyntheticExpression(node: SyntheticExpression): Type { + if (isTemplateLiteral(node.parent) && node.type === getGlobalTemplateStringsArrayType()) { + const cookedStrings: Type[] = []; + const rawStrings: Type[] = []; + if (isNoSubstitutionTemplateLiteral(node.parent)) { + cookedStrings.push(getStringLiteralType(node.parent.text)); + rawStrings.push(getRawLiteralType(node.parent)); + } + else { + cookedStrings.push(getStringLiteralType(node.parent.head.text)); + rawStrings.push(getRawLiteralType(node.parent.head)); + for (const templateSpan of node.parent.templateSpans) { + cookedStrings.push(getStringLiteralType(templateSpan.literal.text)); + rawStrings.push(getRawLiteralType(templateSpan.literal)); + } + } + return getTemplateStringsArrayOf(cookedStrings, rawStrings); + } return node.isSpread ? getIndexedAccessType(node.type, numberType) : node.type; } @@ -34606,10 +34694,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let typeArguments: NodeArray | undefined; if (!isDecorator && !isInstanceof && !isSuperCall(node)) { - typeArguments = (node as CallExpression).typeArguments; + typeArguments = node.typeArguments; // We already perform checking on the type arguments on the class declaration itself. - if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || (node as CallExpression).expression.kind !== SyntaxKind.SuperKeyword) { + if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || node.expression.kind !== SyntaxKind.SuperKeyword) { forEach(typeArguments, checkSourceElement); } } diff --git a/src/compiler/transformers/taggedTemplate.ts b/src/compiler/transformers/taggedTemplate.ts index a905dcb26ecb8..b52ce34c86117 100644 --- a/src/compiler/transformers/taggedTemplate.ts +++ b/src/compiler/transformers/taggedTemplate.ts @@ -2,7 +2,7 @@ import { CallExpression, Debug, Expression, - getSourceTextOfNodeFromSourceFile, + getRawTextOfTemplateLiteralLike, hasInvalidEscape, Identifier, isExpression, @@ -12,7 +12,6 @@ import { NoSubstitutionTemplateLiteral, setTextRange, SourceFile, - SyntaxKind, TaggedTemplateExpression, TemplateHead, TemplateLiteralLikeNode, @@ -108,25 +107,6 @@ function createTemplateCooked(factory: NodeFactory, template: TemplateHead | Tem * @param node The ES6 template literal. */ function getRawLiteral(factory: NodeFactory, node: TemplateLiteralLikeNode, currentSourceFile: SourceFile) { - // Find original source text, since we need to emit the raw strings of the tagged template. - // The raw strings contain the (escaped) strings of what the user wrote. - // Examples: `\n` is converted to "\\n", a template string with a newline to "\n". - let text = node.rawText; - if (text === undefined) { - Debug.assertIsDefined(currentSourceFile, "Template literal node is missing 'rawText' and does not have a source file. Possibly bad transform."); - text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node); - - // text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"), - // thus we need to remove those characters. - // First template piece starts with "`", others with "}" - // Last template piece ends with "`", others with "${" - const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail; - text = text.substring(1, text.length - (isLast ? 1 : 2)); - } - - // Newline normalization: - // ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's - // and LineTerminatorSequences are normalized to for both TV and TRV. - text = text.replace(/\r\n?/g, "\n"); + const text = getRawTextOfTemplateLiteralLike(node, currentSourceFile); return setTextRange(factory.createStringLiteral(text), node); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 6bbc51a4ad121..1585f90f77c86 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1719,6 +1719,30 @@ export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile | u return Debug.fail(`Literal kind '${node.kind}' not accounted for.`); } +/** @internal */ +export function getRawTextOfTemplateLiteralLike(node: TemplateLiteralLikeNode, sourceFile: SourceFile) { + // Find original source text, since we need to emit the raw strings of the tagged template. + // The raw strings contain the (escaped) strings of what the user wrote. + // Examples: `\n` is converted to "\\n", a template string with a newline to "\n". + let text = node.rawText; + if (text === undefined) { + Debug.assertIsDefined(sourceFile, "Template literal node is missing 'rawText' and does not have a source file. Possibly bad transform."); + text = getSourceTextOfNodeFromSourceFile(sourceFile, node); + + // text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"), + // thus we need to remove those characters. + // First template piece starts with "`", others with "}" + // Last template piece ends with "`", others with "${" + const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail; + text = text.substring(1, text.length - (isLast ? 1 : 2)); + } + + // Newline normalization: + // ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's + // and LineTerminatorSequences are normalized to for both TV and TRV. + return text.replace(/\r\n?/g, "\n"); +} + function canUseOriginalText(node: LiteralLikeNode, flags: GetLiteralTextFlags): boolean { if (nodeIsSynthesized(node) || !node.parent || (flags & GetLiteralTextFlags.TerminateUnterminatedLiterals && node.isUnterminated)) { return false; diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 64577f69ced7c..bb2997bd1a229 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1132,6 +1132,7 @@ export namespace Completion { varEntry("Number"), interfaceEntry("NumberConstructor"), interfaceEntry("TemplateStringsArray"), + typeEntry("TemplateStringsArrayOf"), interfaceEntry("ImportMeta"), interfaceEntry("ImportCallOptions"), deprecatedInterfaceEntry("ImportAssertions"), diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index e404df509a1c0..dd6f3e800fa19 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -604,6 +604,8 @@ interface TemplateStringsArray extends ReadonlyArray { readonly raw: readonly string[]; } +type TemplateStringsArrayOf = Cooked & { readonly raw: Raw }; + /** * The type of `import.meta`. * diff --git a/tests/baselines/reference/importHelpers.types b/tests/baselines/reference/importHelpers.types index 2027d3c5988dd..0dbb7c032db74 100644 --- a/tests/baselines/reference/importHelpers.types +++ b/tests/baselines/reference/importHelpers.types @@ -33,8 +33,8 @@ function id(x: T) { } export const result = id`hello world`; ->result : TemplateStringsArray ->id`hello world` : TemplateStringsArray +>result : TemplateStringsArrayOf +>id`hello world` : TemplateStringsArrayOf >id : (x: T) => T >`hello world` : "hello world" @@ -71,8 +71,8 @@ function id(x: T) { } const result = id`hello world`; ->result : TemplateStringsArray ->id`hello world` : TemplateStringsArray +>result : TemplateStringsArrayOf +>id`hello world` : TemplateStringsArrayOf >id : (x: T) => T >`hello world` : "hello world" diff --git a/tests/baselines/reference/inferTypes1.errors.txt b/tests/baselines/reference/inferTypes1.errors.txt index aac97232d02fb..b3d35f7ce68d7 100644 --- a/tests/baselines/reference/inferTypes1.errors.txt +++ b/tests/baselines/reference/inferTypes1.errors.txt @@ -246,4 +246,9 @@ inferTypes1.ts(153,40): error TS2322: Type 'T' is not assignable to type 'string const result = invoker('test', true)({ test: (a: boolean) => 123 }) type Foo2 = ReturnType<(...args: A) => string>; + + // Infer from an intersected tuple + type Head = T extends [infer THead, ...infer _] ? THead : never; + type T100 = Head<["a", "c"] & { foo: "bar" }>; // "a" + type T101 = Head<["a", "c"] & readonly ["a", "c"]>; // "a" | "c" \ No newline at end of file diff --git a/tests/baselines/reference/inferTypes1.js b/tests/baselines/reference/inferTypes1.js index 5f9d5f6a87604..9230a0dd47d88 100644 --- a/tests/baselines/reference/inferTypes1.js +++ b/tests/baselines/reference/inferTypes1.js @@ -187,6 +187,11 @@ function invoker (key: K, const result = invoker('test', true)({ test: (a: boolean) => 123 }) type Foo2 = ReturnType<(...args: A) => string>; + +// Infer from an intersected tuple +type Head = T extends [infer THead, ...infer _] ? THead : never; +type T100 = Head<["a", "c"] & { foo: "bar" }>; // "a" +type T101 = Head<["a", "c"] & readonly ["a", "c"]>; // "a" | "c" //// [inferTypes1.js] diff --git a/tests/baselines/reference/inferTypes1.symbols b/tests/baselines/reference/inferTypes1.symbols index 1b4c00288ad4d..841aba8a7de1d 100644 --- a/tests/baselines/reference/inferTypes1.symbols +++ b/tests/baselines/reference/inferTypes1.symbols @@ -777,3 +777,21 @@ type Foo2 = ReturnType<(...args: A) => string>; >args : Symbol(args, Decl(inferTypes1.ts, 185, 41)) >A : Symbol(A, Decl(inferTypes1.ts, 185, 10)) +// Infer from an intersected tuple +type Head = T extends [infer THead, ...infer _] ? THead : never; +>Head : Symbol(Head, Decl(inferTypes1.ts, 185, 64)) +>T : Symbol(T, Decl(inferTypes1.ts, 188, 10)) +>T : Symbol(T, Decl(inferTypes1.ts, 188, 10)) +>THead : Symbol(THead, Decl(inferTypes1.ts, 188, 48)) +>_ : Symbol(_, Decl(inferTypes1.ts, 188, 64)) +>THead : Symbol(THead, Decl(inferTypes1.ts, 188, 48)) + +type T100 = Head<["a", "c"] & { foo: "bar" }>; // "a" +>T100 : Symbol(T100, Decl(inferTypes1.ts, 188, 84)) +>Head : Symbol(Head, Decl(inferTypes1.ts, 185, 64)) +>foo : Symbol(foo, Decl(inferTypes1.ts, 189, 31)) + +type T101 = Head<["a", "c"] & readonly ["a", "c"]>; // "a" | "c" +>T101 : Symbol(T101, Decl(inferTypes1.ts, 189, 46)) +>Head : Symbol(Head, Decl(inferTypes1.ts, 185, 64)) + diff --git a/tests/baselines/reference/inferTypes1.types b/tests/baselines/reference/inferTypes1.types index 3ce2bf2dd5011..fa8b0566d55d4 100644 --- a/tests/baselines/reference/inferTypes1.types +++ b/tests/baselines/reference/inferTypes1.types @@ -493,3 +493,14 @@ type Foo2 = ReturnType<(...args: A) => string>; >Foo2 : string >args : A +// Infer from an intersected tuple +type Head = T extends [infer THead, ...infer _] ? THead : never; +>Head : Head + +type T100 = Head<["a", "c"] & { foo: "bar" }>; // "a" +>T100 : "a" +>foo : "bar" + +type T101 = Head<["a", "c"] & readonly ["a", "c"]>; // "a" | "c" +>T101 : "a" | "c" + diff --git a/tests/baselines/reference/taggedTemplateWithSpecificTemplateStrings.symbols b/tests/baselines/reference/taggedTemplateWithSpecificTemplateStrings.symbols new file mode 100644 index 0000000000000..c6dfd29a88325 --- /dev/null +++ b/tests/baselines/reference/taggedTemplateWithSpecificTemplateStrings.symbols @@ -0,0 +1,349 @@ +//// [tests/cases/conformance/es6/templates/taggedTemplateWithSpecificTemplateStrings.ts] //// + +=== taggedTemplateWithSpecificTemplateStrings.ts === +// overload resolution +declare function f1(array: TemplateStringsArrayOf, ...args: any): "A"; +>f1 : Symbol(f1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 0, 0), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 99), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 99)) +>array : Symbol(array, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 20)) +>TemplateStringsArrayOf : Symbol(TemplateStringsArrayOf, Decl(lib.es5.d.ts, --, --)) +>args : Symbol(args, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 79)) + +declare function f1(array: TemplateStringsArrayOf, ...args: any): "B"; +>f1 : Symbol(f1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 0, 0), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 99), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 99)) +>array : Symbol(array, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 20)) +>TemplateStringsArrayOf : Symbol(TemplateStringsArrayOf, Decl(lib.es5.d.ts, --, --)) +>args : Symbol(args, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 79)) + +declare function f1(array: TemplateStringsArray, ...args: any): "C"; +>f1 : Symbol(f1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 0, 0), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 99), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 99)) +>array : Symbol(array, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 3, 20)) +>TemplateStringsArray : Symbol(TemplateStringsArray, Decl(lib.es5.d.ts, --, --)) +>args : Symbol(args, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 3, 48)) + +const f1_r0 = f1`a`; // "A" +>f1_r0 : Symbol(f1_r0, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 4, 5)) +>f1 : Symbol(f1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 0, 0), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 99), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 99)) + +const f1_r1 = f1`a${"b"}`; // "A" +>f1_r1 : Symbol(f1_r1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 5, 5)) +>f1 : Symbol(f1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 0, 0), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 99), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 99)) + +const f1_r2 = f1`b`; // "B" +>f1_r2 : Symbol(f1_r2, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 6, 5)) +>f1 : Symbol(f1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 0, 0), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 99), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 99)) + +const f1_r3 = f1`b${"b"}`; // "B" +>f1_r3 : Symbol(f1_r3, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 7, 5)) +>f1 : Symbol(f1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 0, 0), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 99), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 99)) + +const f1_r4 = f1`c`; // "C" +>f1_r4 : Symbol(f1_r4, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 8, 5)) +>f1 : Symbol(f1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 0, 0), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 99), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 99)) + +const f1_r5 = f1`c${"b"}`; // "C" +>f1_r5 : Symbol(f1_r5, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 9, 5)) +>f1 : Symbol(f1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 0, 0), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 1, 99), Decl(taggedTemplateWithSpecificTemplateStrings.ts, 2, 99)) + +// constrained type parameter +declare function f0(array: T, ...args: A): [T, A]; +>f0 : Symbol(f0, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 9, 26)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 12, 20)) +>TemplateStringsArray : Symbol(TemplateStringsArray, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 12, 51)) +>array : Symbol(array, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 12, 72)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 12, 20)) +>args : Symbol(args, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 12, 81)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 12, 51)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 12, 20)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 12, 51)) + +const f0_r0 = f0`a${"b"}c`; // [TemplateStringsArrayOf, ["b"]] +>f0_r0 : Symbol(f0_r0, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 13, 5)) +>f0 : Symbol(f0, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 9, 26)) + +// interpolation example +type TemplatePrimitive = string | number | bigint | boolean | null | undefined; +>TemplatePrimitive : Symbol(TemplatePrimitive, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 13, 27)) + +type Interpolate = +>Interpolate : Symbol(Interpolate, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 16, 79)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 18, 17)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 18, 45)) +>R : Symbol(R, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 18, 62)) + + T extends readonly [infer TH extends string, ...infer TT extends readonly string[]] ? +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 18, 17)) +>TH : Symbol(TH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 19, 29)) +>TT : Symbol(TT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 19, 57)) + + A extends [infer AH extends TemplatePrimitive, ...infer AT extends TemplatePrimitive[]] ? +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 18, 45)) +>AH : Symbol(AH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 20, 24)) +>TemplatePrimitive : Symbol(TemplatePrimitive, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 13, 27)) +>AT : Symbol(AT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 20, 63)) +>TemplatePrimitive : Symbol(TemplatePrimitive, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 13, 27)) + + Interpolate : +>Interpolate : Symbol(Interpolate, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 16, 79)) +>TT : Symbol(TT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 19, 57)) +>AT : Symbol(AT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 20, 63)) +>R : Symbol(R, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 18, 62)) +>TH : Symbol(TH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 19, 29)) +>AH : Symbol(AH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 20, 24)) + + Interpolate : +>Interpolate : Symbol(Interpolate, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 16, 79)) +>TT : Symbol(TT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 19, 57)) +>R : Symbol(R, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 18, 62)) +>TH : Symbol(TH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 19, 29)) + + R; +>R : Symbol(R, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 18, 62)) + +// string interpolation +declare function interp(array: T, ...args: A): Interpolate; +>interp : Symbol(interp, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 23, 10)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 26, 24)) +>TemplateStringsArray : Symbol(TemplateStringsArray, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 26, 55)) +>TemplatePrimitive : Symbol(TemplatePrimitive, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 13, 27)) +>array : Symbol(array, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 26, 87)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 26, 24)) +>args : Symbol(args, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 26, 96)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 26, 55)) +>Interpolate : Symbol(Interpolate, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 16, 79)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 26, 24)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 26, 55)) + +const interp_r0 = interp`a${"b"}c`; // "abc" +>interp_r0 : Symbol(interp_r0, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 27, 5)) +>interp : Symbol(interp, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 23, 10)) + +const interp_r1 = interp`a${1}c`; // "a1c" +>interp_r1 : Symbol(interp_r1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 28, 5)) +>interp : Symbol(interp, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 23, 10)) + +// "a\nb\nc" +const interp_r2 = interp`a\n${"b"} +>interp_r2 : Symbol(interp_r2, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 31, 5)) +>interp : Symbol(interp, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 23, 10)) + +c`; + +// raw string interpolation (i.e., 'String.raw') +declare function raw(array: T, ...args: A): Interpolate; +>raw : Symbol(raw, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 32, 3)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 35, 21)) +>TemplateStringsArray : Symbol(TemplateStringsArray, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 35, 52)) +>TemplatePrimitive : Symbol(TemplatePrimitive, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 13, 27)) +>array : Symbol(array, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 35, 84)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 35, 21)) +>args : Symbol(args, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 35, 93)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 35, 52)) +>Interpolate : Symbol(Interpolate, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 16, 79)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 35, 21)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 35, 52)) + +const raw_r0 = raw`a${"b"}c`; // "abc" +>raw_r0 : Symbol(raw_r0, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 36, 5)) +>raw : Symbol(raw, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 32, 3)) + +const raw_r1 = raw`a${1}c`; // "a1c" +>raw_r1 : Symbol(raw_r1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 37, 5)) +>raw : Symbol(raw, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 32, 3)) + +// "a\\nb\nc" +const raw_r2 = raw`a\n${"b"} +>raw_r2 : Symbol(raw_r2, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 40, 5)) +>raw : Symbol(raw, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 32, 3)) + +c`; + +// Jest's `it.each`: +type Whitespace = " " | "\t" | "\v" +>Whitespace : Symbol(Whitespace, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 41, 3)) + +type Trim = +>Trim : Symbol(Trim, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 44, 35)) +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 46, 10)) +>Chars : Symbol(Chars, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 46, 27)) +>Whitespace : Symbol(Whitespace, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 41, 3)) + + S extends `${Chars}${infer R}` ? Trim : +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 46, 10)) +>Chars : Symbol(Chars, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 46, 27)) +>R : Symbol(R, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 47, 30)) +>Trim : Symbol(Trim, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 44, 35)) +>R : Symbol(R, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 47, 30)) +>Chars : Symbol(Chars, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 46, 27)) + + S extends `${infer R}${Chars}` ? Trim : +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 46, 10)) +>R : Symbol(R, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 48, 22)) +>Chars : Symbol(Chars, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 46, 27)) +>Trim : Symbol(Trim, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 44, 35)) +>R : Symbol(R, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 48, 22)) +>Chars : Symbol(Chars, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 46, 27)) + + S; +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 46, 10)) + +type Split = +>Split : Symbol(Split, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 49, 6)) +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 51, 11)) +>D : Symbol(D, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 51, 28)) + + S extends D ? [] : +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 51, 11)) +>D : Symbol(D, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 51, 28)) + + S extends `${infer H}${D}${infer T}` ? [H, ...Split] : +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 51, 11)) +>H : Symbol(H, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 53, 22)) +>D : Symbol(D, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 51, 28)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 53, 36)) +>H : Symbol(H, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 53, 22)) +>Split : Symbol(Split, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 49, 6)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 53, 36)) +>D : Symbol(D, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 51, 28)) + + [S]; +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 51, 11)) + +type ParseRows = +>ParseRows : Symbol(ParseRows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 54, 8)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 15)) +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 31)) +>Row : Symbol(Row, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 60)) +>Rows : Symbol(Rows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 84)) + + [A, S] extends [[infer AH, ...infer AT], readonly [infer TH extends string, ...infer TT extends string[]]] ? +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 15)) +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 31)) +>AH : Symbol(AH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 26)) +>AT : Symbol(AT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 39)) +>TH : Symbol(TH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 60)) +>TT : Symbol(TT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 88)) + + Trim extends "|" ? ParseRows : +>Trim : Symbol(Trim, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 44, 35)) +>TH : Symbol(TH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 60)) +>Whitespace : Symbol(Whitespace, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 41, 3)) +>ParseRows : Symbol(ParseRows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 54, 8)) +>AT : Symbol(AT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 39)) +>TT : Symbol(TT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 88)) +>Row : Symbol(Row, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 60)) +>AH : Symbol(AH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 26)) +>Rows : Symbol(Rows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 84)) + + Trim extends "\n" | "" ? ParseRows : +>Trim : Symbol(Trim, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 44, 35)) +>TH : Symbol(TH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 60)) +>Whitespace : Symbol(Whitespace, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 41, 3)) +>ParseRows : Symbol(ParseRows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 54, 8)) +>AT : Symbol(AT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 39)) +>TT : Symbol(TT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 88)) +>Rows : Symbol(Rows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 84)) +>Row : Symbol(Row, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 60)) +>AH : Symbol(AH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 57, 26)) + + never : + [A, S] extends [[], readonly []] ? Rows : +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 15)) +>S : Symbol(S, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 31)) +>Rows : Symbol(Rows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 56, 84)) + + never; + +type JestEachArgument = { +>JestEachArgument : Symbol(JestEachArgument, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 62, 10)) +>Headers : Symbol(Headers, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 64, 22)) +>Rows : Symbol(Rows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 64, 47)) + + [P1 in keyof Rows]: { +>P1 : Symbol(P1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 65, 5)) +>Rows : Symbol(Rows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 64, 47)) + + [P2 in keyof Headers as P2 extends `${number}` ? Trim : never]: +>P2 : Symbol(P2, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 66, 9)) +>Headers : Symbol(Headers, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 64, 22)) +>P2 : Symbol(P2, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 66, 9)) +>Trim : Symbol(Trim, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 44, 35)) +>Headers : Symbol(Headers, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 64, 22)) +>P2 : Symbol(P2, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 66, 9)) + + P2 extends keyof Rows[P1] ? Rows[P1][P2] : undefined; +>P2 : Symbol(P2, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 66, 9)) +>Rows : Symbol(Rows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 64, 47)) +>P1 : Symbol(P1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 65, 5)) +>Rows : Symbol(Rows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 64, 47)) +>P1 : Symbol(P1, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 65, 5)) +>P2 : Symbol(P2, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 66, 9)) + + }; +}[number]; + +type JestEachFunction = (name: string, cb: (arg: Arg) => void, timeout?: number) => void; +>JestEachFunction : Symbol(JestEachFunction, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 69, 10)) +>Arg : Symbol(Arg, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 71, 22)) +>name : Symbol(name, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 71, 30)) +>cb : Symbol(cb, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 71, 43)) +>arg : Symbol(arg, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 71, 49)) +>Arg : Symbol(Arg, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 71, 22)) +>timeout : Symbol(timeout, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 71, 67)) + +type JestEach = +>JestEach : Symbol(JestEach, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 71, 94)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 73, 14)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 73, 42)) + + T extends readonly [infer TH extends string, ...infer TT extends readonly string[]] ? +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 73, 14)) +>TH : Symbol(TH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 74, 29)) +>TT : Symbol(TT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 74, 57)) + + JestEachFunction, "|">, ParseRows>> : +>JestEachFunction : Symbol(JestEachFunction, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 69, 10)) +>JestEachArgument : Symbol(JestEachArgument, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 62, 10)) +>Split : Symbol(Split, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 49, 6)) +>Trim : Symbol(Trim, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 44, 35)) +>TH : Symbol(TH, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 74, 29)) +>ParseRows : Symbol(ParseRows, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 54, 8)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 73, 42)) +>TT : Symbol(TT, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 74, 57)) + + null; + +declare function each(strs: T, ...args: A): JestEach; +>each : Symbol(each, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 76, 13)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 78, 22)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 78, 50)) +>strs : Symbol(strs, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 78, 72)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 78, 22)) +>args : Symbol(args, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 78, 80)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 78, 50)) +>JestEach : Symbol(JestEach, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 71, 94)) +>T : Symbol(T, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 78, 22)) +>A : Symbol(A, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 78, 50)) + +each` +>each : Symbol(each, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 76, 13)) + + foo | bar + ${"a"} | ${1} + ${"c"} | ${undefined} +>undefined : Symbol(undefined) + +`("test", ({ foo, bar }) => { +>foo : Symbol(foo, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 84, 12)) +>bar : Symbol(bar, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 84, 17)) + + foo; +>foo : Symbol(foo, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 84, 12)) + + bar; +>bar : Symbol(bar, Decl(taggedTemplateWithSpecificTemplateStrings.ts, 84, 17)) + +}); + diff --git a/tests/baselines/reference/taggedTemplateWithSpecificTemplateStrings.types b/tests/baselines/reference/taggedTemplateWithSpecificTemplateStrings.types new file mode 100644 index 0000000000000..8b80fd6c8e59b --- /dev/null +++ b/tests/baselines/reference/taggedTemplateWithSpecificTemplateStrings.types @@ -0,0 +1,229 @@ +//// [tests/cases/conformance/es6/templates/taggedTemplateWithSpecificTemplateStrings.ts] //// + +=== taggedTemplateWithSpecificTemplateStrings.ts === +// overload resolution +declare function f1(array: TemplateStringsArrayOf, ...args: any): "A"; +>f1 : { (array: TemplateStringsArrayOf, ...args: any): "A"; (array: TemplateStringsArrayOf, ...args: any): "B"; (array: TemplateStringsArray, ...args: any): "C"; } +>array : TemplateStringsArrayOf +>args : any + +declare function f1(array: TemplateStringsArrayOf, ...args: any): "B"; +>f1 : { (array: TemplateStringsArrayOf, ...args: any): "A"; (array: TemplateStringsArrayOf, ...args: any): "B"; (array: TemplateStringsArray, ...args: any): "C"; } +>array : TemplateStringsArrayOf +>args : any + +declare function f1(array: TemplateStringsArray, ...args: any): "C"; +>f1 : { (array: TemplateStringsArrayOf, ...args: any): "A"; (array: TemplateStringsArrayOf, ...args: any): "B"; (array: TemplateStringsArray, ...args: any): "C"; } +>array : TemplateStringsArray +>args : any + +const f1_r0 = f1`a`; // "A" +>f1_r0 : "A" +>f1`a` : "A" +>f1 : { (array: TemplateStringsArrayOf, ...args: any): "A"; (array: TemplateStringsArrayOf, ...args: any): "B"; (array: TemplateStringsArray, ...args: any): "C"; } +>`a` : "a" + +const f1_r1 = f1`a${"b"}`; // "A" +>f1_r1 : "A" +>f1`a${"b"}` : "A" +>f1 : { (array: TemplateStringsArrayOf, ...args: any): "A"; (array: TemplateStringsArrayOf, ...args: any): "B"; (array: TemplateStringsArray, ...args: any): "C"; } +>`a${"b"}` : string +>"b" : "b" + +const f1_r2 = f1`b`; // "B" +>f1_r2 : "B" +>f1`b` : "B" +>f1 : { (array: TemplateStringsArrayOf, ...args: any): "A"; (array: TemplateStringsArrayOf, ...args: any): "B"; (array: TemplateStringsArray, ...args: any): "C"; } +>`b` : "b" + +const f1_r3 = f1`b${"b"}`; // "B" +>f1_r3 : "B" +>f1`b${"b"}` : "B" +>f1 : { (array: TemplateStringsArrayOf, ...args: any): "A"; (array: TemplateStringsArrayOf, ...args: any): "B"; (array: TemplateStringsArray, ...args: any): "C"; } +>`b${"b"}` : string +>"b" : "b" + +const f1_r4 = f1`c`; // "C" +>f1_r4 : "C" +>f1`c` : "C" +>f1 : { (array: TemplateStringsArrayOf, ...args: any): "A"; (array: TemplateStringsArrayOf, ...args: any): "B"; (array: TemplateStringsArray, ...args: any): "C"; } +>`c` : "c" + +const f1_r5 = f1`c${"b"}`; // "C" +>f1_r5 : "C" +>f1`c${"b"}` : "C" +>f1 : { (array: TemplateStringsArrayOf, ...args: any): "A"; (array: TemplateStringsArrayOf, ...args: any): "B"; (array: TemplateStringsArray, ...args: any): "C"; } +>`c${"b"}` : string +>"b" : "b" + +// constrained type parameter +declare function f0(array: T, ...args: A): [T, A]; +>f0 : (array: T, ...args: A) => [T, A] +>array : T +>args : A + +const f0_r0 = f0`a${"b"}c`; // [TemplateStringsArrayOf, ["b"]] +>f0_r0 : [TemplateStringsArrayOf, ["b"]] +>f0`a${"b"}c` : [TemplateStringsArrayOf, ["b"]] +>f0 : (array: T, ...args: A) => [T, A] +>`a${"b"}c` : string +>"b" : "b" + +// interpolation example +type TemplatePrimitive = string | number | bigint | boolean | null | undefined; +>TemplatePrimitive : string | number | bigint | boolean | null | undefined + +type Interpolate = +>Interpolate : Interpolate + + T extends readonly [infer TH extends string, ...infer TT extends readonly string[]] ? + A extends [infer AH extends TemplatePrimitive, ...infer AT extends TemplatePrimitive[]] ? + Interpolate : + Interpolate : + R; + +// string interpolation +declare function interp(array: T, ...args: A): Interpolate; +>interp : (array: T, ...args: A) => Interpolate +>array : T +>args : A + +const interp_r0 = interp`a${"b"}c`; // "abc" +>interp_r0 : "abc" +>interp`a${"b"}c` : "abc" +>interp : (array: T, ...args: A) => Interpolate +>`a${"b"}c` : string +>"b" : "b" + +const interp_r1 = interp`a${1}c`; // "a1c" +>interp_r1 : "a1c" +>interp`a${1}c` : "a1c" +>interp : (array: T, ...args: A) => Interpolate +>`a${1}c` : string +>1 : 1 + +// "a\nb\nc" +const interp_r2 = interp`a\n${"b"} +>interp_r2 : "a\nb\nc" +>interp`a\n${"b"}c` : "a\nb\nc" +>interp : (array: T, ...args: A) => Interpolate +>`a\n${"b"}c` : string +>"b" : "b" + +c`; + +// raw string interpolation (i.e., 'String.raw') +declare function raw(array: T, ...args: A): Interpolate; +>raw : (array: T, ...args: A) => Interpolate +>array : T +>args : A + +const raw_r0 = raw`a${"b"}c`; // "abc" +>raw_r0 : "abc" +>raw`a${"b"}c` : "abc" +>raw : (array: T, ...args: A) => Interpolate +>`a${"b"}c` : string +>"b" : "b" + +const raw_r1 = raw`a${1}c`; // "a1c" +>raw_r1 : "a1c" +>raw`a${1}c` : "a1c" +>raw : (array: T, ...args: A) => Interpolate +>`a${1}c` : string +>1 : 1 + +// "a\\nb\nc" +const raw_r2 = raw`a\n${"b"} +>raw_r2 : "a\\nb\nc" +>raw`a\n${"b"}c` : "a\\nb\nc" +>raw : (array: T, ...args: A) => Interpolate +>`a\n${"b"}c` : string +>"b" : "b" + +c`; + +// Jest's `it.each`: +type Whitespace = " " | "\t" | "\v" +>Whitespace : " " | "\t" | "\v" + +type Trim = +>Trim : Trim + + S extends `${Chars}${infer R}` ? Trim : + S extends `${infer R}${Chars}` ? Trim : + S; + +type Split = +>Split : Split + + S extends D ? [] : + S extends `${infer H}${D}${infer T}` ? [H, ...Split] : + [S]; + +type ParseRows = +>ParseRows : ParseRows + + [A, S] extends [[infer AH, ...infer AT], readonly [infer TH extends string, ...infer TT extends string[]]] ? + Trim extends "|" ? ParseRows : + Trim extends "\n" | "" ? ParseRows : + never : + [A, S] extends [[], readonly []] ? Rows : + never; + +type JestEachArgument = { +>JestEachArgument : JestEachArgument + + [P1 in keyof Rows]: { + [P2 in keyof Headers as P2 extends `${number}` ? Trim : never]: + P2 extends keyof Rows[P1] ? Rows[P1][P2] : undefined; + }; +}[number]; + +type JestEachFunction = (name: string, cb: (arg: Arg) => void, timeout?: number) => void; +>JestEachFunction : JestEachFunction +>name : string +>cb : (arg: Arg) => void +>arg : Arg +>timeout : number | undefined + +type JestEach = +>JestEach : JestEach + + T extends readonly [infer TH extends string, ...infer TT extends readonly string[]] ? + JestEachFunction, "|">, ParseRows>> : + null; + +declare function each(strs: T, ...args: A): JestEach; +>each : (strs: T, ...args: A) => JestEach +>strs : T +>args : A + +each` +>each` foo | bar ${"a"} | ${1} ${"c"} | ${undefined}`("test", ({ foo, bar }) => { foo; bar;}) : void +>each` foo | bar ${"a"} | ${1} ${"c"} | ${undefined}` : JestEachFunction<{ foo: string; bar: number; } | { foo: string; bar: undefined; }> +>each : (strs: T, ...args: A) => JestEach +>` foo | bar ${"a"} | ${1} ${"c"} | ${undefined}` : string + + foo | bar + ${"a"} | ${1} +>"a" : "a" +>1 : 1 + + ${"c"} | ${undefined} +>"c" : "c" +>undefined : undefined + +`("test", ({ foo, bar }) => { +>"test" : "test" +>({ foo, bar }) => { foo; bar;} : ({ foo, bar }: { foo: string; bar: number; } | { foo: string; bar: undefined; }) => void +>foo : string +>bar : number | undefined + + foo; +>foo : string + + bar; +>bar : number | undefined + +}); + diff --git a/tests/baselines/reference/taggedTemplateWithoutDeclaredHelper.types b/tests/baselines/reference/taggedTemplateWithoutDeclaredHelper.types index 91c6296249119..459ad6d849002 100644 --- a/tests/baselines/reference/taggedTemplateWithoutDeclaredHelper.types +++ b/tests/baselines/reference/taggedTemplateWithoutDeclaredHelper.types @@ -10,8 +10,8 @@ function id(x: T) { } export const result = id `hello world`; ->result : TemplateStringsArray ->id `hello world` : TemplateStringsArray +>result : TemplateStringsArrayOf +>id `hello world` : TemplateStringsArrayOf >id : (x: T) => T >`hello world` : "hello world" diff --git a/tests/baselines/reference/taggedTemplatesInModuleAndGlobal.types b/tests/baselines/reference/taggedTemplatesInModuleAndGlobal.types index d4696b7a75bd7..30b4a664e0861 100644 --- a/tests/baselines/reference/taggedTemplatesInModuleAndGlobal.types +++ b/tests/baselines/reference/taggedTemplatesInModuleAndGlobal.types @@ -13,20 +13,20 @@ namespace n { } function templateObjectFactory() { ->templateObjectFactory : () => TemplateStringsArray +>templateObjectFactory : () => TemplateStringsArrayOf return id`hello world`; ->id`hello world` : TemplateStringsArray +>id`hello world` : TemplateStringsArrayOf >id : (x: T) => T >`hello world` : "hello world" } let result = templateObjectFactory() === templateObjectFactory(); >result : boolean >templateObjectFactory() === templateObjectFactory() : boolean ->templateObjectFactory() : TemplateStringsArray ->templateObjectFactory : () => TemplateStringsArray ->templateObjectFactory() : TemplateStringsArray ->templateObjectFactory : () => TemplateStringsArray +>templateObjectFactory() : TemplateStringsArrayOf +>templateObjectFactory : () => TemplateStringsArrayOf +>templateObjectFactory() : TemplateStringsArrayOf +>templateObjectFactory : () => TemplateStringsArrayOf } === module.ts === export { } @@ -39,18 +39,18 @@ function id(x: T): T { } function templateObjectFactory() { ->templateObjectFactory : () => TemplateStringsArray +>templateObjectFactory : () => TemplateStringsArrayOf return id`hello world`; ->id`hello world` : TemplateStringsArray +>id`hello world` : TemplateStringsArrayOf >id : (x: T) => T >`hello world` : "hello world" } let result = templateObjectFactory() === templateObjectFactory(); >result : boolean >templateObjectFactory() === templateObjectFactory() : boolean ->templateObjectFactory() : TemplateStringsArray ->templateObjectFactory : () => TemplateStringsArray ->templateObjectFactory() : TemplateStringsArray ->templateObjectFactory : () => TemplateStringsArray +>templateObjectFactory() : TemplateStringsArrayOf +>templateObjectFactory : () => TemplateStringsArrayOf +>templateObjectFactory() : TemplateStringsArrayOf +>templateObjectFactory : () => TemplateStringsArrayOf diff --git a/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_namespaceSameNameAsIntrinsic.js b/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_namespaceSameNameAsIntrinsic.js index a51c0a2445f5e..7234598b7b3f4 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_namespaceSameNameAsIntrinsic.js +++ b/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_namespaceSameNameAsIntrinsic.js @@ -1030,6 +1030,12 @@ Info seq [hh:mm:ss:mss] response: "kindModifiers": "declare", "sortText": "15" }, + { + "name": "TemplateStringsArrayOf", + "kind": "type", + "kindModifiers": "declare", + "sortText": "15" + }, { "name": "ThisParameterType", "kind": "type", diff --git a/tests/cases/conformance/es6/templates/taggedTemplateWithSpecificTemplateStrings.ts b/tests/cases/conformance/es6/templates/taggedTemplateWithSpecificTemplateStrings.ts new file mode 100644 index 0000000000000..fa2ad1cc40191 --- /dev/null +++ b/tests/cases/conformance/es6/templates/taggedTemplateWithSpecificTemplateStrings.ts @@ -0,0 +1,92 @@ +// @target: esnext +// @noEmit: true +// @strict: true + +// overload resolution +declare function f1(array: TemplateStringsArrayOf, ...args: any): "A"; +declare function f1(array: TemplateStringsArrayOf, ...args: any): "B"; +declare function f1(array: TemplateStringsArray, ...args: any): "C"; +const f1_r0 = f1`a`; // "A" +const f1_r1 = f1`a${"b"}`; // "A" +const f1_r2 = f1`b`; // "B" +const f1_r3 = f1`b${"b"}`; // "B" +const f1_r4 = f1`c`; // "C" +const f1_r5 = f1`c${"b"}`; // "C" + +// constrained type parameter +declare function f0(array: T, ...args: A): [T, A]; +const f0_r0 = f0`a${"b"}c`; // [TemplateStringsArrayOf, ["b"]] + +// interpolation example +type TemplatePrimitive = string | number | bigint | boolean | null | undefined; + +type Interpolate = + T extends readonly [infer TH extends string, ...infer TT extends readonly string[]] ? + A extends [infer AH extends TemplatePrimitive, ...infer AT extends TemplatePrimitive[]] ? + Interpolate : + Interpolate : + R; + +// string interpolation +declare function interp(array: T, ...args: A): Interpolate; +const interp_r0 = interp`a${"b"}c`; // "abc" +const interp_r1 = interp`a${1}c`; // "a1c" + +// "a\nb\nc" +const interp_r2 = interp`a\n${"b"} +c`; + +// raw string interpolation (i.e., 'String.raw') +declare function raw(array: T, ...args: A): Interpolate; +const raw_r0 = raw`a${"b"}c`; // "abc" +const raw_r1 = raw`a${1}c`; // "a1c" + +// "a\\nb\nc" +const raw_r2 = raw`a\n${"b"} +c`; + +// Jest's `it.each`: +type Whitespace = " " | "\t" | "\v" + +type Trim = + S extends `${Chars}${infer R}` ? Trim : + S extends `${infer R}${Chars}` ? Trim : + S; + +type Split = + S extends D ? [] : + S extends `${infer H}${D}${infer T}` ? [H, ...Split] : + [S]; + +type ParseRows = + [A, S] extends [[infer AH, ...infer AT], readonly [infer TH extends string, ...infer TT extends string[]]] ? + Trim extends "|" ? ParseRows : + Trim extends "\n" | "" ? ParseRows : + never : + [A, S] extends [[], readonly []] ? Rows : + never; + +type JestEachArgument = { + [P1 in keyof Rows]: { + [P2 in keyof Headers as P2 extends `${number}` ? Trim : never]: + P2 extends keyof Rows[P1] ? Rows[P1][P2] : undefined; + }; +}[number]; + +type JestEachFunction = (name: string, cb: (arg: Arg) => void, timeout?: number) => void; + +type JestEach = + T extends readonly [infer TH extends string, ...infer TT extends readonly string[]] ? + JestEachFunction, "|">, ParseRows>> : + null; + +declare function each(strs: T, ...args: A): JestEach; + +each` + foo | bar + ${"a"} | ${1} + ${"c"} | ${undefined} +`("test", ({ foo, bar }) => { + foo; + bar; +}); diff --git a/tests/cases/conformance/types/conditional/inferTypes1.ts b/tests/cases/conformance/types/conditional/inferTypes1.ts index 42e5897dc663f..61a9dc3c1d9cf 100644 --- a/tests/cases/conformance/types/conditional/inferTypes1.ts +++ b/tests/cases/conformance/types/conditional/inferTypes1.ts @@ -187,3 +187,8 @@ function invoker (key: K, const result = invoker('test', true)({ test: (a: boolean) => 123 }) type Foo2 = ReturnType<(...args: A) => string>; + +// Infer from an intersected tuple +type Head = T extends [infer THead, ...infer _] ? THead : never; +type T100 = Head<["a", "c"] & { foo: "bar" }>; // "a" +type T101 = Head<["a", "c"] & readonly ["a", "c"]>; // "a" | "c"