diff --git a/scripts/configureNightly.ts b/scripts/configureNightly.ts index 640f330b376..778f5ce3727 100644 --- a/scripts/configureNightly.ts +++ b/scripts/configureNightly.ts @@ -19,47 +19,57 @@ function main(): void { // Acquire the version from the package.json file and modify it appropriately. const packageJsonFilePath = ts.normalizePath(sys.args[0]); - const packageJsonContents = sys.readFile(packageJsonFilePath); - const packageJsonValue: PackageJson = JSON.parse(packageJsonContents); + const packageJsonValue: PackageJson = JSON.parse(sys.readFile(packageJsonFilePath)); - const nightlyVersion = getNightlyVersionString(packageJsonValue.version); - - // Modify the package.json structure - packageJsonValue.version = nightlyVersion; + const { majorMinor, patch } = parsePackageJsonVersion(packageJsonValue.version); + const nightlyPatch = getNightlyPatch(patch); // Acquire and modify the source file that exposes the version string. const tsFilePath = ts.normalizePath(sys.args[1]); - const tsFileContents = sys.readFile(tsFilePath); - const versionAssignmentRegExp = /export\s+const\s+version\s+=\s+".*";/; - const modifiedTsFileContents = tsFileContents.replace(versionAssignmentRegExp, `export const version = "${nightlyVersion}";`); + const tsFileContents = ts.sys.readFile(tsFilePath); + const modifiedTsFileContents = updateTsFile(tsFilePath, tsFileContents, majorMinor, patch, nightlyPatch); // Ensure we are actually changing something - the user probably wants to know that the update failed. if (tsFileContents === modifiedTsFileContents) { let err = `\n '${tsFilePath}' was not updated while configuring for a nightly publish.\n `; - - if (tsFileContents.match(versionAssignmentRegExp)) { - err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`; - } - else { - err += `The file seems to no longer have a string matching '${versionAssignmentRegExp}'.`; - } - + err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`; throw err + "\n"; } // Finally write the changes to disk. + // Modify the package.json structure + packageJsonValue.version = `${majorMinor}.${nightlyPatch}`; sys.writeFile(packageJsonFilePath, JSON.stringify(packageJsonValue, /*replacer:*/ undefined, /*space:*/ 4)) sys.writeFile(tsFilePath, modifiedTsFileContents); } -function getNightlyVersionString(versionString: string): string { - // If the version string already contains "-nightly", - // then get the base string and update based on that. - const dashNightlyPos = versionString.indexOf("-dev"); - if (dashNightlyPos >= 0) { - versionString = versionString.slice(0, dashNightlyPos); +function updateTsFile(tsFilePath: string, tsFileContents: string, majorMinor: string, patch: string, nightlyPatch: string): string { + const majorMinorRgx = /export const versionMajorMinor = "(\d+\.\d+)"/; + const majorMinorMatch = majorMinorRgx.exec(tsFileContents); + ts.Debug.assert(majorMinorMatch !== null, "", () => `The file seems to no longer have a string matching '${majorMinorRgx}'.`); + const parsedMajorMinor = majorMinorMatch[1]; + ts.Debug.assert(parsedMajorMinor === majorMinor, "versionMajorMinor does not match.", () => `${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`); + + const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)`;/; + const patchMatch = versionRgx.exec(tsFileContents); + ts.Debug.assert(patchMatch !== null, "The file seems to no longer have a string matching", () => versionRgx.toString()); + const parsedPatch = patchMatch[1]; + if (parsedPatch !== patch) { + throw new Error(`patch does not match. ${tsFilePath}: '${parsedPatch}; package.json: '${patch}'`); } + return tsFileContents.replace(versionRgx, `export const version = \`\${versionMajorMinor}.${nightlyPatch}\`;`); +} + +function parsePackageJsonVersion(versionString: string): { majorMinor: string, patch: string } { + const versionRgx = /(\d+\.\d+)\.(\d+)($|\-)/; + const match = versionString.match(versionRgx); + ts.Debug.assert(match !== null, "package.json 'version' should match", () => versionRgx.toString()); + return { majorMinor: match[1], patch: match[2] }; +} + +/** e.g. 0-dev.20170707 */ +function getNightlyPatch(plainPatch: string): string { // We're going to append a representation of the current time at the end of the current version. // String.prototype.toISOString() returns a 24-character string formatted as 'YYYY-MM-DDTHH:mm:ss.sssZ', // but we'd prefer to just remove separators and limit ourselves to YYYYMMDD. @@ -67,7 +77,7 @@ function getNightlyVersionString(versionString: string): string { const now = new Date(); const timeStr = now.toISOString().replace(/:|T|\.|-/g, "").slice(0, 8); - return `${versionString}-dev.${timeStr}`; + return `${plainPatch}-dev.${timeStr}`; } main(); \ No newline at end of file diff --git a/scripts/tslint/typeOperatorSpacingRule.ts b/scripts/tslint/typeOperatorSpacingRule.ts index 4bd70e6eefa..d7da2e6b5e8 100644 --- a/scripts/tslint/typeOperatorSpacingRule.ts +++ b/scripts/tslint/typeOperatorSpacingRule.ts @@ -19,7 +19,7 @@ function walk(ctx: Lint.WalkContext): void { ts.forEachChild(node, recur); } - function check(types: ts.TypeNode[]): void { + function check(types: ReadonlyArray): void { let expectedStart = types[0].end + 2; // space, | or & for (let i = 1; i < types.length; i++) { const currentType = types[i]; diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 803c9f60709..0b58f080fe2 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -308,7 +308,7 @@ namespace ts { * @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.) * @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations. */ - function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol { + function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags, isReplaceableByMethod?: boolean): Symbol { Debug.assert(!hasDynamicName(node)); const isDefaultExport = hasModifier(node, ModifierFlags.Default); @@ -345,15 +345,20 @@ namespace ts { // you have multiple 'vars' with the same name in the same container). In this case // just add this node into the declarations list of the symbol. symbol = symbolTable.get(name); - if (!symbol) { - symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name)); - } - if (name && (includes & SymbolFlags.Classifiable)) { + if (includes & SymbolFlags.Classifiable) { classifiableNames.set(name, true); } - if (symbol.flags & excludes) { + if (!symbol) { + symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name)); + if (isReplaceableByMethod) symbol.isReplaceableByMethod = true; + } + else if (isReplaceableByMethod && !symbol.isReplaceableByMethod) { + // A symbol already exists, so don't add this as a declaration. + return symbol; + } + else if (symbol.flags & excludes) { if (symbol.isReplaceableByMethod) { // Javascript constructor-declared symbols can be discarded in favor of // prototype symbols like methods. @@ -1327,7 +1332,7 @@ namespace ts { function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) { const name = !isOmittedExpression(node) ? node.name : undefined; if (isBindingPattern(name)) { - for (const child of name.elements) { + for (const child of name.elements) { bindInitializedVariableFlow(child); } } @@ -2061,8 +2066,10 @@ namespace ts { case SyntaxKind.Parameter: return bindParameter(node); case SyntaxKind.VariableDeclaration: + return bindVariableDeclarationOrBindingElement(node); case SyntaxKind.BindingElement: - return bindVariableDeclarationOrBindingElement(node); + node.flowNode = currentFlow; + return bindVariableDeclarationOrBindingElement(node); case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: return bindPropertyWorker(node as PropertyDeclaration | PropertySignature); @@ -2342,11 +2349,8 @@ namespace ts { // this.foo assignment in a JavaScript class // Bind this property to the containing class const containingClass = container.parent; - const symbol = declareSymbol(hasModifier(container, ModifierFlags.Static) ? containingClass.symbol.exports : containingClass.symbol.members, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None); - if (symbol) { - // symbols declared through 'this' property assignements can be overwritten by subsequent method declarations - (symbol as Symbol).isReplaceableByMethod = true; - } + const symbolTable = hasModifier(container, ModifierFlags.Static) ? containingClass.symbol.exports : containingClass.symbol.members; + declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None, /*isReplaceableByMethod*/ true); break; } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dafa75372e1..043e9755ce2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -117,6 +117,7 @@ namespace ts { }, getParameterType: getTypeAtPosition, getReturnTypeOfSignature, + getNullableType, getNonNullableType, typeToTypeNode: nodeBuilder.typeToTypeNode, indexInfoToIndexSignatureDeclaration: nodeBuilder.indexInfoToIndexSignatureDeclaration, @@ -2669,7 +2670,7 @@ namespace ts { entityName = nameIdentifier; } - let typeArgumentNodes: TypeNode[] | undefined; + let typeArgumentNodes: ReadonlyArray | undefined; if (typeArguments.length > 0) { const typeParameterCount = (type.target.typeParameters || emptyArray).length; typeArgumentNodes = mapToTypeNodes(typeArguments.slice(i, typeParameterCount), context); @@ -2906,7 +2907,7 @@ namespace ts { function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName { Debug.assert(chain && 0 <= index && index < chain.length); const symbol = chain[index]; - let typeParameterNodes: TypeNode[] | undefined; + let typeParameterNodes: ReadonlyArray | undefined; if (context.flags & NodeBuilderFlags.WriteTypeParametersInQualifiedName && index > 0) { const parentSymbol = chain[index - 1]; let typeParameters: TypeParameter[]; @@ -3301,7 +3302,7 @@ namespace ts { function writeTypeReference(type: TypeReference, flags: TypeFormatFlags) { const typeArguments = type.typeArguments || emptyArray; if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) { - writeType(typeArguments[0], TypeFormatFlags.InElementType); + writeType(typeArguments[0], TypeFormatFlags.InElementType | TypeFormatFlags.InArrayType); writePunctuation(writer, SyntaxKind.OpenBracketToken); writePunctuation(writer, SyntaxKind.CloseBracketToken); } @@ -3426,9 +3427,15 @@ namespace ts { } function writeTypeOfSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) { + if (typeFormatFlags & TypeFormatFlags.InArrayType) { + writePunctuation(writer, SyntaxKind.OpenParenToken); + } writeKeyword(writer, SyntaxKind.TypeOfKeyword); writeSpace(writer); buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags); + if (typeFormatFlags & TypeFormatFlags.InArrayType) { + writePunctuation(writer, SyntaxKind.CloseParenToken); + } } function writePropertyWithModifiers(prop: Symbol) { @@ -3666,7 +3673,7 @@ namespace ts { } } - function buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { + function buildDisplayForTypeParametersAndDelimiters(typeParameters: ReadonlyArray, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { if (typeParameters && typeParameters.length) { writePunctuation(writer, SyntaxKind.LessThanToken); buildDisplayForCommaSeparatedList(typeParameters, writer, p => buildTypeParameterDisplay(p, writer, enclosingDeclaration, flags, symbolStack)); @@ -3674,7 +3681,7 @@ namespace ts { } } - function buildDisplayForCommaSeparatedList(list: T[], writer: SymbolWriter, action: (item: T) => void) { + function buildDisplayForCommaSeparatedList(list: ReadonlyArray, writer: SymbolWriter, action: (item: T) => void) { for (let i = 0; i < list.length; i++) { if (i > 0) { writePunctuation(writer, SyntaxKind.CommaToken); @@ -3684,7 +3691,7 @@ namespace ts { } } - function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node) { + function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: ReadonlyArray, mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node) { if (typeParameters && typeParameters.length) { writePunctuation(writer, SyntaxKind.LessThanToken); let flags = TypeFormatFlags.InFirstTypeArgument; @@ -4088,8 +4095,8 @@ namespace ts { /** Return the inferred type for a binding element */ function getTypeForBindingElement(declaration: BindingElement): Type { - const pattern = declaration.parent; - const parentType = getTypeForBindingElementParent(pattern.parent); + const pattern = declaration.parent; + const parentType = getTypeForBindingElementParent(pattern.parent); // If parent has the unknown (error) type, then so does this binding element if (parentType === unknownType) { return unknownType; @@ -4134,7 +4141,8 @@ namespace ts { // or otherwise the type of the string index signature. const text = getTextOfPropertyName(name); - type = getTypeOfPropertyOfType(parentType, text) || + const declaredType = getTypeOfPropertyOfType(parentType, text); + type = declaredType && getFlowTypeOfReference(declaration, declaredType) || isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); if (!type) { @@ -4736,7 +4744,7 @@ namespace ts { // Appends the type parameters given by a list of declarations to a set of type parameters and returns the resulting set. // The function allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set // in-place and returns the same array. - function appendTypeParameters(typeParameters: TypeParameter[], declarations: TypeParameterDeclaration[]): TypeParameter[] { + function appendTypeParameters(typeParameters: TypeParameter[], declarations: ReadonlyArray): TypeParameter[] { for (const declaration of declarations) { const tp = getDeclaredTypeOfTypeParameter(getSymbolOfNode(declaration)); if (!typeParameters) { @@ -4823,14 +4831,14 @@ namespace ts { return getClassExtendsHeritageClauseElement(type.symbol.valueDeclaration); } - function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: TypeNode[], location: Node): Signature[] { + function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray, location: Node): Signature[] { const typeArgCount = length(typeArgumentNodes); const isJavaScript = isInJavaScriptFile(location); return filter(getSignaturesOfType(type, SignatureKind.Construct), sig => (isJavaScript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters)); } - function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: TypeNode[], location: Node): Signature[] { + function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray, location: Node): Signature[] { const signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location); const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode); return sameMap(signatures, sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments) : sig); @@ -6870,8 +6878,19 @@ namespace ts { return node.flags & NodeFlags.JSDoc && node.kind === SyntaxKind.TypeReference; } - function getPrimitiveTypeFromJSDocTypeReference(node: TypeReferenceNode): Type { + function getIntendedTypeFromJSDocTypeReference(node: TypeReferenceNode): Type { if (isIdentifier(node.typeName)) { + if (node.typeName.text === "Object") { + if (node.typeArguments && node.typeArguments.length === 2) { + const indexed = getTypeFromTypeNode(node.typeArguments[0]); + const target = getTypeFromTypeNode(node.typeArguments[1]); + const index = createIndexInfo(target, /*isReadonly*/ false); + if (indexed === stringType || indexed === numberType) { + return createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, indexed === stringType && index, indexed === numberType && index); + } + } + return anyType; + } switch (node.typeName.text) { case "String": return stringType; @@ -6885,8 +6904,6 @@ namespace ts { return undefinedType; case "Null": return nullType; - case "Object": - return anyType; case "Function": case "function": return globalFunctionType; @@ -6912,7 +6929,7 @@ namespace ts { let type: Type; let meaning = SymbolFlags.Type; if (isJSDocTypeReference(node)) { - type = getPrimitiveTypeFromJSDocTypeReference(node); + type = getIntendedTypeFromJSDocTypeReference(node); meaning |= SymbolFlags.Value; } if (!type) { @@ -9954,6 +9971,11 @@ namespace ts { neverType; } + /** + * Add undefined or null or both to a type if they are missing. + * @param type - type to add undefined and/or null to if not present + * @param flags - Either TypeFlags.Undefined or TypeFlags.Null, or both + */ function getNullableType(type: Type, flags: TypeFlags): Type { const missing = (flags & ~type.flags) & (TypeFlags.Undefined | TypeFlags.Null); return missing === 0 ? type : @@ -10656,7 +10678,7 @@ namespace ts { // The result is undefined if the reference isn't a dotted name. We prefix nodes // occurring in an apparent type position with '@' because the control flow type // of such nodes may be based on the apparent type instead of the declared type. - function getFlowCacheKey(node: Node): string { + function getFlowCacheKey(node: Node): string | undefined { if (node.kind === SyntaxKind.Identifier) { const symbol = getResolvedSymbol(node); return symbol !== unknownSymbol ? (isApparentTypePosition(node) ? "@" : "") + getSymbolId(symbol) : undefined; @@ -10666,7 +10688,14 @@ namespace ts { } if (node.kind === SyntaxKind.PropertyAccessExpression) { const key = getFlowCacheKey((node).expression); - return key && key + "." + (node).name.text; + return key && key + "." + unescapeLeadingUnderscores((node).name.text); + } + if (node.kind === SyntaxKind.BindingElement) { + const container = (node as BindingElement).parent.parent; + const key = container.kind === SyntaxKind.BindingElement ? getFlowCacheKey(container) : (container.initializer && getFlowCacheKey(container.initializer)); + const text = getBindingElementNameText(node as BindingElement); + const result = key && text && (key + "." + text); + return result; } return undefined; } @@ -10682,6 +10711,28 @@ namespace ts { return undefined; } + function getBindingElementNameText(element: BindingElement): string | undefined { + if (element.parent.kind === SyntaxKind.ObjectBindingPattern) { + const name = element.propertyName || element.name; + switch (name.kind) { + case SyntaxKind.Identifier: + return unescapeLeadingUnderscores(name.text); + case SyntaxKind.ComputedPropertyName: + if (isComputedNonLiteralName(name as PropertyName)) return undefined; + return (name.expression as LiteralExpression).text; + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + return name.text; + default: + // Per types, array and object binding patterns remain, however they should never be present if propertyName is not defined + Debug.fail("Unexpected name kind for binding element name"); + } + } + else { + return "" + element.parent.elements.indexOf(element); + } + } + function isMatchingReference(source: Node, target: Node): boolean { switch (source.kind) { case SyntaxKind.Identifier: @@ -10696,6 +10747,17 @@ namespace ts { return target.kind === SyntaxKind.PropertyAccessExpression && (source).name.text === (target).name.text && isMatchingReference((source).expression, (target).expression); + case SyntaxKind.BindingElement: + if (target.kind !== SyntaxKind.PropertyAccessExpression) return false; + const t = target as PropertyAccessExpression; + if (t.name.text !== getBindingElementNameText(source as BindingElement)) return false; + if (source.parent.parent.kind === SyntaxKind.BindingElement && isMatchingReference(source.parent.parent, t.expression)) { + return true; + } + if (source.parent.parent.kind === SyntaxKind.VariableDeclaration) { + const maybeId = (source.parent.parent as VariableDeclaration).initializer; + return maybeId && isMatchingReference(maybeId, t.expression); + } } return false; } @@ -11486,6 +11548,10 @@ namespace ts { const cache = flowLoopCaches[id] || (flowLoopCaches[id] = createMap()); if (!key) { key = getFlowCacheKey(reference); + // No cache key is generated when binding patterns are in unnarrowable situations + if (!key) { + return declaredType; + } } const cached = cache.get(key); if (cached) { @@ -12602,7 +12668,7 @@ namespace ts { } } } - if (noImplicitThis) { + if (noImplicitThis || isInJavaScriptFile(func)) { const containingLiteral = getContainingObjectLiteral(func); if (containingLiteral) { // We have an object literal method. Check if the containing object literal has a contextual type @@ -14846,7 +14912,7 @@ namespace ts { } } - function getSpreadArgumentIndex(args: Expression[]): number { + function getSpreadArgumentIndex(args: ReadonlyArray): number { for (let i = 0; i < args.length; i++) { const arg = args[i]; if (arg && arg.kind === SyntaxKind.SpreadElement) { @@ -14856,7 +14922,7 @@ namespace ts { return -1; } - function hasCorrectArity(node: CallLikeExpression, args: Expression[], signature: Signature, signatureHelpTrailingComma = false) { + function hasCorrectArity(node: CallLikeExpression, args: ReadonlyArray, signature: Signature, signatureHelpTrailingComma = false) { let argCount: number; // Apparent number of arguments we will have in this call let typeArguments: NodeArray; // Type arguments (undefined if none) let callIsIncomplete: boolean; // In incomplete call we want to be lenient when we have too few arguments @@ -14967,7 +15033,7 @@ namespace ts { return getSignatureInstantiation(signature, getInferredTypes(context)); } - function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): Type[] { + function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray, excludeArgument: boolean[], context: InferenceContext): Type[] { // Clear out all the inference results from the last time inferTypeArguments was called on this context for (const inference of context.inferences) { // As an optimization, we don't have to clear (and later recompute) inferred types @@ -15055,7 +15121,7 @@ namespace ts { return getInferredTypes(context); } - function checkTypeArguments(signature: Signature, typeArgumentNodes: TypeNode[], typeArgumentTypes: Type[], reportErrors: boolean, headMessage?: DiagnosticMessage): boolean { + function checkTypeArguments(signature: Signature, typeArgumentNodes: ReadonlyArray, typeArgumentTypes: Type[], reportErrors: boolean, headMessage?: DiagnosticMessage): boolean { const typeParameters = signature.typeParameters; let typeArgumentsAreAssignable = true; let mapper: TypeMapper; @@ -15119,7 +15185,13 @@ namespace ts { return checkTypeRelatedTo(attributesType, paramType, relation, /*errorNode*/ undefined, headMessage); } - function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean) { + function checkApplicableSignature( + node: CallLikeExpression, + args: ReadonlyArray, + signature: Signature, + relation: Map, + excludeArgument: boolean[], + reportErrors: boolean) { if (isJsxOpeningLikeElement(node)) { return checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation); } @@ -15187,16 +15259,16 @@ namespace ts { * If 'node' is a Decorator, the argument list will be `undefined`, and its arguments and types * will be supplied from calls to `getEffectiveArgumentCount` and `getEffectiveArgumentType`. */ - function getEffectiveCallArguments(node: CallLikeExpression): Expression[] { - let args: Expression[]; + function getEffectiveCallArguments(node: CallLikeExpression): ReadonlyArray { if (node.kind === SyntaxKind.TaggedTemplateExpression) { const template = (node).template; - args = [undefined]; + const args: Expression[] = [undefined]; if (template.kind === SyntaxKind.TemplateExpression) { forEach((template).templateSpans, span => { args.push(span.expression); }); } + return args; } else if (node.kind === SyntaxKind.Decorator) { // For a decorator, we return undefined as we will determine @@ -15205,13 +15277,11 @@ namespace ts { return undefined; } else if (isJsxOpeningLikeElement(node)) { - args = node.attributes.properties.length > 0 ? [node.attributes] : emptyArray; + return node.attributes.properties.length > 0 ? [node.attributes] : emptyArray; } else { - args = node.arguments || emptyArray; + return node.arguments || emptyArray; } - - return args; } @@ -15228,7 +15298,7 @@ namespace ts { * us to match a property decorator. * Otherwise, the argument count is the length of the 'args' array. */ - function getEffectiveArgumentCount(node: CallLikeExpression, args: Expression[], signature: Signature) { + function getEffectiveArgumentCount(node: CallLikeExpression, args: ReadonlyArray, signature: Signature) { if (node.kind === SyntaxKind.Decorator) { switch (node.parent.kind) { case SyntaxKind.ClassDeclaration: @@ -15460,7 +15530,7 @@ namespace ts { /** * Gets the effective argument expression for an argument in a call expression. */ - function getEffectiveArgument(node: CallLikeExpression, args: Expression[], argIndex: number) { + function getEffectiveArgument(node: CallLikeExpression, args: ReadonlyArray, argIndex: number) { // For a decorator or the first argument of a tagged template expression we return undefined. if (node.kind === SyntaxKind.Decorator || (argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression)) { @@ -15492,7 +15562,7 @@ namespace ts { const isDecorator = node.kind === SyntaxKind.Decorator; const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node); - let typeArguments: TypeNode[]; + let typeArguments: ReadonlyArray; if (!isTaggedTemplate && !isDecorator && !isJsxOpeningOrSelfClosingElement) { typeArguments = (node).typeArguments; @@ -16256,15 +16326,19 @@ namespace ts { } function checkAssertion(node: AssertionExpression) { - const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(checkExpression(node.expression))); + return checkAssertionWorker(node, node.type, node.expression); + } - checkSourceElement(node.type); - const targetType = getTypeFromTypeNode(node.type); + function checkAssertionWorker(errNode: Node, type: TypeNode, expression: UnaryExpression | Expression, checkMode?: CheckMode) { + const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(checkExpression(expression, checkMode))); + + checkSourceElement(type); + const targetType = getTypeFromTypeNode(type); if (produceDiagnostics && targetType !== unknownType) { const widenedType = getWidenedType(exprType); if (!isTypeComparableTo(targetType, widenedType)) { - checkTypeComparableTo(exprType, targetType, node, Diagnostics.Type_0_cannot_be_converted_to_type_1); + checkTypeComparableTo(exprType, targetType, errNode, Diagnostics.Type_0_cannot_be_converted_to_type_1); } } return targetType; @@ -17001,7 +17075,7 @@ namespace ts { } /** Note: If property cannot be a SpreadAssignment, then allProperties does not need to be provided */ - function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElementLike, allProperties?: ObjectLiteralElementLike[]) { + function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElementLike, allProperties?: ReadonlyArray) { if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) { const name = (property).name; if (name.kind === SyntaxKind.ComputedPropertyName) { @@ -17735,6 +17809,18 @@ namespace ts { return type; } + function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type { + if (isInJavaScriptFile(node) && node.jsDoc) { + const typecasts = flatMap(node.jsDoc, doc => filter(doc.tags, tag => tag.kind === SyntaxKind.JSDocTypeTag)); + if (typecasts && typecasts.length) { + // We should have already issued an error if there were multiple type jsdocs + const cast = typecasts[0] as JSDocTypeTag; + return checkAssertionWorker(cast, cast.typeExpression.type, node.expression, checkMode); + } + } + return checkExpression(node.expression, checkMode); + } + function checkExpressionWorker(node: Expression, checkMode: CheckMode): Type { switch (node.kind) { case SyntaxKind.Identifier: @@ -17774,7 +17860,7 @@ namespace ts { case SyntaxKind.TaggedTemplateExpression: return checkTaggedTemplateExpression(node); case SyntaxKind.ParenthesizedExpression: - return checkExpression((node).expression, checkMode); + return checkParenthesizedExpression(node, checkMode); case SyntaxKind.ClassExpression: return checkClassExpression(node); case SyntaxKind.FunctionExpression: @@ -17910,6 +17996,8 @@ namespace ts { return; } + checkSourceElement(node.type); + const { parameterName } = node; if (isThisTypePredicate(typePredicate)) { getTypeFromThisTypeNode(parameterName as ThisTypeNode); @@ -18433,7 +18521,7 @@ namespace ts { checkDecorators(node); } - function checkTypeArgumentConstraints(typeParameters: TypeParameter[], typeArgumentNodes: TypeNode[]): boolean { + function checkTypeArgumentConstraints(typeParameters: TypeParameter[], typeArgumentNodes: ReadonlyArray): boolean { const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); let typeArguments: Type[]; let mapper: TypeMapper; @@ -20879,7 +20967,7 @@ namespace ts { /** * Check each type parameter and check that type parameters have no duplicate type parameter declarations */ - function checkTypeParameters(typeParameterDeclarations: TypeParameterDeclaration[]) { + function checkTypeParameters(typeParameterDeclarations: ReadonlyArray) { if (typeParameterDeclarations) { let seenDefault = false; for (let i = 0; i < typeParameterDeclarations.length; i++) { @@ -22186,8 +22274,8 @@ namespace ts { // Grammar checking checkGrammarSourceFile(node); - potentialThisCollisions.length = 0; - potentialNewTargetCollisions.length = 0; + clear(potentialThisCollisions); + clear(potentialNewTargetCollisions); deferredNodes = []; deferredUnusedIdentifierNodes = produceDiagnostics && noUnusedIdentifiers ? [] : undefined; @@ -22213,12 +22301,12 @@ namespace ts { if (potentialThisCollisions.length) { forEach(potentialThisCollisions, checkIfThisIsCapturedInEnclosingScope); - potentialThisCollisions.length = 0; + clear(potentialThisCollisions); } if (potentialNewTargetCollisions.length) { forEach(potentialNewTargetCollisions, checkIfNewTargetIsCapturedInEnclosingScope); - potentialNewTargetCollisions.length = 0; + clear(potentialNewTargetCollisions); } links.flags |= NodeCheckFlags.TypeChecked; @@ -23466,7 +23554,7 @@ namespace ts { } // Initialize global symbol table - let augmentations: LiteralExpression[][]; + let augmentations: ReadonlyArray[]; for (const file of host.getSourceFiles()) { if (!isExternalOrCommonJsModule(file)) { mergeSymbolTable(globals, file.locals); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 902dd9179d2..a5b5e2c7e21 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2,6 +2,8 @@ /// namespace ts { + // WARNING: The script `configureNightly.ts` uses a regexp to parse out these values. + // If changing the text in this section, be sure to test `configureNightly` too. export const versionMajorMinor = "2.5"; /** The version of the TypeScript compiler release */ export const version = `${versionMajorMinor}.0`; @@ -384,6 +386,10 @@ namespace ts { array.length = outIndex; } + export function clear(array: {}[]): void { + array.length = 0; + } + export function map(array: ReadonlyArray, f: (x: T, i: number) => U): U[] { let result: U[]; if (array) { @@ -592,7 +598,7 @@ namespace ts { return result; } - export function mapEntries(map: Map, f: (key: string, value: T) => [string, U]): Map { + export function mapEntries(map: ReadonlyMap, f: (key: string, value: T) => [string, U]): Map { if (!map) { return undefined; } @@ -1005,9 +1011,9 @@ namespace ts { * Calls `callback` for each entry in the map, returning the first truthy result. * Use `map.forEach` instead for normal iteration. */ - export function forEachEntry(map: UnderscoreEscapedMap, callback: (value: T, key: __String) => U | undefined): U | undefined; - export function forEachEntry(map: Map, callback: (value: T, key: string) => U | undefined): U | undefined; - export function forEachEntry(map: UnderscoreEscapedMap | Map, callback: (value: T, key: (string & __String)) => U | undefined): U | undefined { + export function forEachEntry(map: ReadonlyUnderscoreEscapedMap, callback: (value: T, key: __String) => U | undefined): U | undefined; + export function forEachEntry(map: ReadonlyMap, callback: (value: T, key: string) => U | undefined): U | undefined; + export function forEachEntry(map: ReadonlyUnderscoreEscapedMap | ReadonlyMap, callback: (value: T, key: (string & __String)) => U | undefined): U | undefined { const iterator = map.entries(); for (let { value: pair, done } = iterator.next(); !done; { value: pair, done } = iterator.next()) { const [key, value] = pair; @@ -1020,9 +1026,9 @@ namespace ts { } /** `forEachEntry` for just keys. */ - export function forEachKey(map: UnderscoreEscapedMap<{}>, callback: (key: __String) => T | undefined): T | undefined; - export function forEachKey(map: Map<{}>, callback: (key: string) => T | undefined): T | undefined; - export function forEachKey(map: UnderscoreEscapedMap<{}> | Map<{}>, callback: (key: string & __String) => T | undefined): T | undefined { + export function forEachKey(map: ReadonlyUnderscoreEscapedMap<{}>, callback: (key: __String) => T | undefined): T | undefined; + export function forEachKey(map: ReadonlyMap<{}>, callback: (key: string) => T | undefined): T | undefined; + export function forEachKey(map: ReadonlyUnderscoreEscapedMap<{}> | ReadonlyMap<{}>, callback: (key: string & __String) => T | undefined): T | undefined { const iterator = map.keys(); for (let { value: key, done } = iterator.next(); !done; { value: key, done } = iterator.next()) { const result = callback(key as string & __String); @@ -1034,8 +1040,8 @@ namespace ts { } /** Copy entries from `source` to `target`. */ - export function copyEntries(source: UnderscoreEscapedMap, target: UnderscoreEscapedMap): void; - export function copyEntries(source: Map, target: Map): void; + export function copyEntries(source: ReadonlyUnderscoreEscapedMap, target: UnderscoreEscapedMap): void; + export function copyEntries(source: ReadonlyMap, target: Map): void; export function copyEntries | Map>(source: U, target: U): void { (source as Map).forEach((value, key) => { (target as Map).set(key, value); @@ -1113,8 +1119,8 @@ namespace ts { } export function cloneMap(map: SymbolTable): SymbolTable; - export function cloneMap(map: Map): Map; - export function cloneMap(map: Map | SymbolTable): Map | SymbolTable { + export function cloneMap(map: ReadonlyMap): Map; + export function cloneMap(map: ReadonlyMap | SymbolTable): Map | SymbolTable { const clone = createMap(); copyEntries(map as Map, clone); return clone; diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 753080cc6a0..5f4b3175ca9 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -211,7 +211,7 @@ namespace ts { decreaseIndent = newWriter.decreaseIndent; } - function writeAsynchronousModuleElements(nodes: Node[]) { + function writeAsynchronousModuleElements(nodes: ReadonlyArray) { const oldWriter = writer; forEach(nodes, declaration => { let nodeToCheck: Node; @@ -374,13 +374,13 @@ namespace ts { } } - function emitLines(nodes: Node[]) { + function emitLines(nodes: ReadonlyArray) { for (const node of nodes) { emit(node); } } - function emitSeparatedList(nodes: Node[], separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) { + function emitSeparatedList(nodes: ReadonlyArray, separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) { let currentWriterPos = writer.getTextPos(); for (const node of nodes) { if (!canEmitFn || canEmitFn(node)) { @@ -393,7 +393,7 @@ namespace ts { } } - function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) { + function emitCommaList(nodes: ReadonlyArray, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) { emitSeparatedList(nodes, ", ", eachNodeEmitFn, canEmitFn); } @@ -1007,7 +1007,7 @@ namespace ts { return node.parent.kind === SyntaxKind.MethodDeclaration && hasModifier(node.parent, ModifierFlags.Private); } - function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) { + function emitTypeParameters(typeParameters: ReadonlyArray) { function emitTypeParameter(node: TypeParameterDeclaration) { increaseIndent(); emitJsDocComments(node); @@ -1109,7 +1109,7 @@ namespace ts { } } - function emitHeritageClause(typeReferences: ExpressionWithTypeArguments[], isImplementsList: boolean) { + function emitHeritageClause(typeReferences: ReadonlyArray, isImplementsList: boolean) { if (typeReferences) { write(isImplementsList ? " implements " : " extends "); emitCommaList(typeReferences, emitTypeOfTypeReference); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index f8c3c6a12af..759fe9f0abc 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2228,7 +2228,7 @@ namespace ts { * Emits any prologue directives at the start of a Statement list, returning the * number of prologue directives written to the output. */ - function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean, seenPrologueDirectives?: Map): number { + function emitPrologueDirectives(statements: ReadonlyArray, startWithNewLine?: boolean, seenPrologueDirectives?: Map): number { for (let i = 0; i < statements.length; i++) { const statement = statements[i]; if (isPrologueDirective(statement)) { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index c51ebe9fd58..d6d21254218 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -21,10 +21,12 @@ namespace ts { return updated; } + /* @internal */ export function createNodeArray(elements?: T[], hasTrailingComma?: boolean): MutableNodeArray; + export function createNodeArray(elements?: ReadonlyArray, hasTrailingComma?: boolean): NodeArray; /** * Make `elements` into a `NodeArray`. If `elements` is `undefined`, returns an empty `NodeArray`. */ - export function createNodeArray(elements?: T[], hasTrailingComma?: boolean): NodeArray { + export function createNodeArray(elements?: ReadonlyArray, hasTrailingComma?: boolean): NodeArray { if (elements) { if (isNodeArray(elements)) { return elements; @@ -109,8 +111,8 @@ namespace ts { export function createIdentifier(text: string): Identifier; /* @internal */ - export function createIdentifier(text: string, typeArguments: TypeNode[]): Identifier; - export function createIdentifier(text: string, typeArguments?: TypeNode[]): Identifier { + export function createIdentifier(text: string, typeArguments: ReadonlyArray): Identifier; + export function createIdentifier(text: string, typeArguments?: ReadonlyArray): Identifier { const node = createSynthesizedNode(SyntaxKind.Identifier); node.text = escapeLeadingUnderscores(text); node.originalKeywordKind = text ? stringToToken(text) : SyntaxKind.Unknown; @@ -244,7 +246,14 @@ namespace ts { : node; } - export function createParameter(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression) { + export function createParameter( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken?: QuestionToken, + type?: TypeNode, + initializer?: Expression) { const node = createSynthesizedNode(SyntaxKind.Parameter); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -256,7 +265,15 @@ namespace ts { return node; } - export function updateParameter(node: ParameterDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { + export function updateParameter( + node: ParameterDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.dotDotDotToken !== dotDotDotToken @@ -283,7 +300,12 @@ namespace ts { // Type Elements - export function createPropertySignature(modifiers: Modifier[] | undefined, name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature { + export function createPropertySignature( + modifiers: ReadonlyArray | undefined, + name: PropertyName | string, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined): PropertySignature { const node = createSynthesizedNode(SyntaxKind.PropertySignature) as PropertySignature; node.modifiers = asNodeArray(modifiers); node.name = asName(name); @@ -293,7 +315,13 @@ namespace ts { return node; } - export function updatePropertySignature(node: PropertySignature, modifiers: Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { + export function updatePropertySignature( + node: PropertySignature, + modifiers: ReadonlyArray | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined) { return node.modifiers !== modifiers || node.name !== name || node.questionToken !== questionToken @@ -303,7 +331,13 @@ namespace ts { : node; } - export function createProperty(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { + export function createProperty( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined) { const node = createSynthesizedNode(SyntaxKind.PropertyDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -314,7 +348,14 @@ namespace ts { return node; } - export function updateProperty(node: PropertyDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { + export function updateProperty( + node: PropertyDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name @@ -325,7 +366,12 @@ namespace ts { : node; } - export function createMethodSignature(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined) { + export function createMethodSignature( + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined) { const node = createSignatureDeclaration(SyntaxKind.MethodSignature, typeParameters, parameters, type) as MethodSignature; node.name = asName(name); node.questionToken = questionToken; @@ -342,7 +388,16 @@ namespace ts { : node; } - export function createMethod(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) { + export function createMethod( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: Block | undefined) { const node = createSynthesizedNode(SyntaxKind.MethodDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -356,7 +411,17 @@ namespace ts { return node; } - export function updateMethod(node: MethodDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) { + export function updateMethod( + node: MethodDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + asteriskToken: AsteriskToken | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: Block | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.asteriskToken !== asteriskToken @@ -370,7 +435,7 @@ namespace ts { : node; } - export function createConstructor(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], body: Block | undefined) { + export function createConstructor(decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, parameters: ReadonlyArray, body: Block | undefined) { const node = createSynthesizedNode(SyntaxKind.Constructor); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -381,7 +446,12 @@ namespace ts { return node; } - export function updateConstructor(node: ConstructorDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], body: Block | undefined) { + export function updateConstructor( + node: ConstructorDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + parameters: ReadonlyArray, + body: Block | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.parameters !== parameters @@ -390,7 +460,13 @@ namespace ts { : node; } - export function createGetAccessor(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | PropertyName, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) { + export function createGetAccessor( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: string | PropertyName, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: Block | undefined) { const node = createSynthesizedNode(SyntaxKind.GetAccessor); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -402,7 +478,14 @@ namespace ts { return node; } - export function updateGetAccessor(node: GetAccessorDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: PropertyName, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) { + export function updateGetAccessor( + node: GetAccessorDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: PropertyName, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: Block | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name @@ -413,7 +496,12 @@ namespace ts { : node; } - export function createSetAccessor(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | PropertyName, parameters: ParameterDeclaration[], body: Block | undefined) { + export function createSetAccessor( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: string | PropertyName, + parameters: ReadonlyArray, + body: Block | undefined) { const node = createSynthesizedNode(SyntaxKind.SetAccessor); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -424,7 +512,13 @@ namespace ts { return node; } - export function updateSetAccessor(node: SetAccessorDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: PropertyName, parameters: ParameterDeclaration[], body: Block | undefined) { + export function updateSetAccessor( + node: SetAccessorDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: PropertyName, + parameters: ReadonlyArray, + body: Block | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name @@ -450,7 +544,11 @@ namespace ts { return updateSignatureDeclaration(node, typeParameters, parameters, type); } - export function createIndexSignature(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration { + export function createIndexSignature( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode): IndexSignatureDeclaration { const node = createSynthesizedNode(SyntaxKind.IndexSignature) as IndexSignatureDeclaration; node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -459,7 +557,12 @@ namespace ts { return node; } - export function updateIndexSignature(node: IndexSignatureDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode) { + export function updateIndexSignature( + node: IndexSignatureDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode) { return node.parameters !== parameters || node.type !== type || node.decorators !== decorators @@ -469,7 +572,7 @@ namespace ts { } /* @internal */ - export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) { + export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode | undefined) { const node = createSynthesizedNode(kind) as SignatureDeclaration; node.typeParameters = asNodeArray(typeParameters); node.parameters = asNodeArray(parameters); @@ -505,7 +608,7 @@ namespace ts { : node; } - export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: TypeNode[] | undefined) { + export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: ReadonlyArray | undefined) { const node = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode; node.typeName = asName(typeName); node.typeArguments = typeArguments && parenthesizeTypeParameters(typeArguments); @@ -547,7 +650,7 @@ namespace ts { : node; } - export function createTypeLiteralNode(members: TypeElement[]) { + export function createTypeLiteralNode(members: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.TypeLiteral) as TypeLiteralNode; node.members = createNodeArray(members); return node; @@ -561,7 +664,7 @@ namespace ts { export function createArrayTypeNode(elementType: TypeNode) { const node = createSynthesizedNode(SyntaxKind.ArrayType) as ArrayTypeNode; - node.elementType = parenthesizeElementTypeMember(elementType); + node.elementType = parenthesizeArrayTypeMember(elementType); return node; } @@ -571,13 +674,13 @@ namespace ts { : node; } - export function createTupleTypeNode(elementTypes: TypeNode[]) { + export function createTupleTypeNode(elementTypes: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.TupleType) as TupleTypeNode; node.elementTypes = createNodeArray(elementTypes); return node; } - export function updateTypleTypeNode(node: TupleTypeNode, elementTypes: TypeNode[]) { + export function updateTypleTypeNode(node: TupleTypeNode, elementTypes: ReadonlyArray) { return node.elementTypes !== elementTypes ? updateNode(createTupleTypeNode(elementTypes), node) : node; @@ -599,7 +702,7 @@ namespace ts { return updateUnionOrIntersectionTypeNode(node, types); } - export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: TypeNode[]) { + export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: ReadonlyArray) { const node = createSynthesizedNode(kind) as UnionTypeNode | IntersectionTypeNode; node.types = parenthesizeElementTypeMembers(types); return node; @@ -684,25 +787,25 @@ namespace ts { // Binding Patterns - export function createObjectBindingPattern(elements: BindingElement[]) { + export function createObjectBindingPattern(elements: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.ObjectBindingPattern); node.elements = createNodeArray(elements); return node; } - export function updateObjectBindingPattern(node: ObjectBindingPattern, elements: BindingElement[]) { + export function updateObjectBindingPattern(node: ObjectBindingPattern, elements: ReadonlyArray) { return node.elements !== elements ? updateNode(createObjectBindingPattern(elements), node) : node; } - export function createArrayBindingPattern(elements: ArrayBindingElement[]) { + export function createArrayBindingPattern(elements: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.ArrayBindingPattern); node.elements = createNodeArray(elements); return node; } - export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: ArrayBindingElement[]) { + export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: ReadonlyArray) { return node.elements !== elements ? updateNode(createArrayBindingPattern(elements), node) : node; @@ -728,27 +831,27 @@ namespace ts { // Expression - export function createArrayLiteral(elements?: Expression[], multiLine?: boolean) { + export function createArrayLiteral(elements?: ReadonlyArray, multiLine?: boolean) { const node = createSynthesizedNode(SyntaxKind.ArrayLiteralExpression); node.elements = parenthesizeListElements(createNodeArray(elements)); if (multiLine) node.multiLine = true; return node; } - export function updateArrayLiteral(node: ArrayLiteralExpression, elements: Expression[]) { + export function updateArrayLiteral(node: ArrayLiteralExpression, elements: ReadonlyArray) { return node.elements !== elements ? updateNode(createArrayLiteral(elements, node.multiLine), node) : node; } - export function createObjectLiteral(properties?: ObjectLiteralElementLike[], multiLine?: boolean) { + export function createObjectLiteral(properties?: ReadonlyArray, multiLine?: boolean) { const node = createSynthesizedNode(SyntaxKind.ObjectLiteralExpression); node.properties = createNodeArray(properties); if (multiLine) node.multiLine = true; return node; } - export function updateObjectLiteral(node: ObjectLiteralExpression, properties: ObjectLiteralElementLike[]) { + export function updateObjectLiteral(node: ObjectLiteralExpression, properties: ReadonlyArray) { return node.properties !== properties ? updateNode(createObjectLiteral(properties, node.multiLine), node) : node; @@ -785,7 +888,7 @@ namespace ts { : node; } - export function createCall(expression: Expression, typeArguments: TypeNode[] | undefined, argumentsArray: Expression[]) { + export function createCall(expression: Expression, typeArguments: ReadonlyArray | undefined, argumentsArray: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.CallExpression); node.expression = parenthesizeForAccess(expression); node.typeArguments = asNodeArray(typeArguments); @@ -793,7 +896,7 @@ namespace ts { return node; } - export function updateCall(node: CallExpression, expression: Expression, typeArguments: TypeNode[] | undefined, argumentsArray: Expression[]) { + export function updateCall(node: CallExpression, expression: Expression, typeArguments: ReadonlyArray | undefined, argumentsArray: ReadonlyArray) { return node.expression !== expression || node.typeArguments !== typeArguments || node.arguments !== argumentsArray @@ -801,7 +904,7 @@ namespace ts { : node; } - export function createNew(expression: Expression, typeArguments: TypeNode[] | undefined, argumentsArray: Expression[] | undefined) { + export function createNew(expression: Expression, typeArguments: ReadonlyArray | undefined, argumentsArray: ReadonlyArray | undefined) { const node = createSynthesizedNode(SyntaxKind.NewExpression); node.expression = parenthesizeForNew(expression); node.typeArguments = asNodeArray(typeArguments); @@ -809,7 +912,7 @@ namespace ts { return node; } - export function updateNew(node: NewExpression, expression: Expression, typeArguments: TypeNode[] | undefined, argumentsArray: Expression[] | undefined) { + export function updateNew(node: NewExpression, expression: Expression, typeArguments: ReadonlyArray | undefined, argumentsArray: ReadonlyArray | undefined) { return node.expression !== expression || node.typeArguments !== typeArguments || node.arguments !== argumentsArray @@ -857,7 +960,14 @@ namespace ts { : node; } - export function createFunctionExpression(modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block) { + export function createFunctionExpression( + modifiers: ReadonlyArray | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | Identifier | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: Block) { const node = createSynthesizedNode(SyntaxKind.FunctionExpression); node.modifiers = asNodeArray(modifiers); node.asteriskToken = asteriskToken; @@ -869,7 +979,15 @@ namespace ts { return node; } - export function updateFunctionExpression(node: FunctionExpression, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block) { + export function updateFunctionExpression( + node: FunctionExpression, + modifiers: ReadonlyArray | undefined, + asteriskToken: AsteriskToken | undefined, + name: Identifier | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: Block) { return node.name !== name || node.modifiers !== modifiers || node.asteriskToken !== asteriskToken @@ -881,7 +999,13 @@ namespace ts { : node; } - export function createArrowFunction(modifiers: Modifier[] | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody) { + export function createArrowFunction( + modifiers: ReadonlyArray | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + equalsGreaterThanToken: EqualsGreaterThanToken | undefined, + body: ConciseBody) { const node = createSynthesizedNode(SyntaxKind.ArrowFunction); node.modifiers = asNodeArray(modifiers); node.typeParameters = asNodeArray(typeParameters); @@ -892,7 +1016,13 @@ namespace ts { return node; } - export function updateArrowFunction(node: ArrowFunction, modifiers: Modifier[] | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody) { + export function updateArrowFunction( + node: ArrowFunction, + modifiers: ReadonlyArray | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: ConciseBody) { return node.modifiers !== modifiers || node.typeParameters !== typeParameters || node.parameters !== parameters @@ -1013,14 +1143,14 @@ namespace ts { : node; } - export function createTemplateExpression(head: TemplateHead, templateSpans: TemplateSpan[]) { + export function createTemplateExpression(head: TemplateHead, templateSpans: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.TemplateExpression); node.head = head; node.templateSpans = createNodeArray(templateSpans); return node; } - export function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: TemplateSpan[]) { + export function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: ReadonlyArray) { return node.head !== head || node.templateSpans !== templateSpans ? updateNode(createTemplateExpression(head, templateSpans), node) @@ -1055,7 +1185,12 @@ namespace ts { : node; } - export function createClassExpression(modifiers: Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[], members: ClassElement[]) { + export function createClassExpression( + modifiers: ReadonlyArray | undefined, + name: string | Identifier | undefined, + typeParameters: ReadonlyArray | undefined, + heritageClauses: ReadonlyArray, + members: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.ClassExpression); node.decorators = undefined; node.modifiers = asNodeArray(modifiers); @@ -1066,7 +1201,13 @@ namespace ts { return node; } - export function updateClassExpression(node: ClassExpression, modifiers: Modifier[] | undefined, name: Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[], members: ClassElement[]) { + export function updateClassExpression( + node: ClassExpression, + modifiers: ReadonlyArray | undefined, + name: Identifier | undefined, + typeParameters: ReadonlyArray | undefined, + heritageClauses: ReadonlyArray, + members: ReadonlyArray) { return node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters @@ -1080,14 +1221,14 @@ namespace ts { return createSynthesizedNode(SyntaxKind.OmittedExpression); } - export function createExpressionWithTypeArguments(typeArguments: TypeNode[], expression: Expression) { + export function createExpressionWithTypeArguments(typeArguments: ReadonlyArray, expression: Expression) { const node = createSynthesizedNode(SyntaxKind.ExpressionWithTypeArguments); node.expression = parenthesizeForAccess(expression); node.typeArguments = asNodeArray(typeArguments); return node; } - export function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, typeArguments: TypeNode[], expression: Expression) { + export function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, typeArguments: ReadonlyArray, expression: Expression) { return node.typeArguments !== typeArguments || node.expression !== expression ? updateNode(createExpressionWithTypeArguments(typeArguments, expression), node) @@ -1155,20 +1296,20 @@ namespace ts { // Element - export function createBlock(statements: Statement[], multiLine?: boolean): Block { + export function createBlock(statements: ReadonlyArray, multiLine?: boolean): Block { const block = createSynthesizedNode(SyntaxKind.Block); block.statements = createNodeArray(statements); if (multiLine) block.multiLine = multiLine; return block; } - export function updateBlock(node: Block, statements: Statement[]) { + export function updateBlock(node: Block, statements: ReadonlyArray) { return node.statements !== statements ? updateNode(createBlock(statements, node.multiLine), node) : node; } - export function createVariableStatement(modifiers: Modifier[] | undefined, declarationList: VariableDeclarationList | VariableDeclaration[]) { + export function createVariableStatement(modifiers: ReadonlyArray | undefined, declarationList: VariableDeclarationList | ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.VariableStatement); node.decorators = undefined; node.modifiers = asNodeArray(modifiers); @@ -1176,7 +1317,7 @@ namespace ts { return node; } - export function updateVariableStatement(node: VariableStatement, modifiers: Modifier[] | undefined, declarationList: VariableDeclarationList) { + export function updateVariableStatement(node: VariableStatement, modifiers: ReadonlyArray | undefined, declarationList: VariableDeclarationList) { return node.modifiers !== modifiers || node.declarationList !== declarationList ? updateNode(createVariableStatement(modifiers, declarationList), node) @@ -1421,20 +1562,28 @@ namespace ts { : node; } - export function createVariableDeclarationList(declarations: VariableDeclaration[], flags?: NodeFlags) { + export function createVariableDeclarationList(declarations: ReadonlyArray, flags?: NodeFlags) { const node = createSynthesizedNode(SyntaxKind.VariableDeclarationList); node.flags |= flags & NodeFlags.BlockScoped; node.declarations = createNodeArray(declarations); return node; } - export function updateVariableDeclarationList(node: VariableDeclarationList, declarations: VariableDeclaration[]) { + export function updateVariableDeclarationList(node: VariableDeclarationList, declarations: ReadonlyArray) { return node.declarations !== declarations ? updateNode(createVariableDeclarationList(declarations, node.flags), node) : node; } - export function createFunctionDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) { + export function createFunctionDeclaration( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | Identifier | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: Block | undefined) { const node = createSynthesizedNode(SyntaxKind.FunctionDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -1447,7 +1596,16 @@ namespace ts { return node; } - export function updateFunctionDeclaration(node: FunctionDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) { + export function updateFunctionDeclaration( + node: FunctionDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + asteriskToken: AsteriskToken | undefined, + name: Identifier | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: Block | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.asteriskToken !== asteriskToken @@ -1460,7 +1618,13 @@ namespace ts { : node; } - export function createClassDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[], members: ClassElement[]) { + export function createClassDeclaration( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: string | Identifier | undefined, + typeParameters: ReadonlyArray | undefined, + heritageClauses: ReadonlyArray, + members: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.ClassDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -1471,7 +1635,14 @@ namespace ts { return node; } - export function updateClassDeclaration(node: ClassDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[], members: ClassElement[]) { + export function updateClassDeclaration( + node: ClassDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: Identifier | undefined, + typeParameters: ReadonlyArray | undefined, + heritageClauses: ReadonlyArray, + members: ReadonlyArray) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name @@ -1482,7 +1653,13 @@ namespace ts { : node; } - export function createInterfaceDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | Identifier, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[] | undefined, members: TypeElement[]) { + export function createInterfaceDeclaration( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: string | Identifier, + typeParameters: ReadonlyArray | undefined, + heritageClauses: ReadonlyArray | undefined, + members: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.InterfaceDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -1493,7 +1670,14 @@ namespace ts { return node; } - export function updateInterfaceDeclaration(node: InterfaceDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: Identifier, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[] | undefined, members: TypeElement[]) { + export function updateInterfaceDeclaration( + node: InterfaceDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: Identifier, + typeParameters: ReadonlyArray | undefined, + heritageClauses: ReadonlyArray | undefined, + members: ReadonlyArray) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name @@ -1504,7 +1688,12 @@ namespace ts { : node; } - export function createTypeAliasDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | Identifier, typeParameters: TypeParameterDeclaration[] | undefined, type: TypeNode) { + export function createTypeAliasDeclaration( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: string | Identifier, + typeParameters: ReadonlyArray | undefined, + type: TypeNode) { const node = createSynthesizedNode(SyntaxKind.TypeAliasDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -1514,7 +1703,13 @@ namespace ts { return node; } - export function updateTypeAliasDeclaration(node: TypeAliasDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: Identifier, typeParameters: TypeParameterDeclaration[] | undefined, type: TypeNode) { + export function updateTypeAliasDeclaration( + node: TypeAliasDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: Identifier, + typeParameters: ReadonlyArray | undefined, + type: TypeNode) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name @@ -1524,7 +1719,11 @@ namespace ts { : node; } - export function createEnumDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | Identifier, members: EnumMember[]) { + export function createEnumDeclaration( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: string | Identifier, + members: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.EnumDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -1533,7 +1732,12 @@ namespace ts { return node; } - export function updateEnumDeclaration(node: EnumDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: Identifier, members: EnumMember[]) { + export function updateEnumDeclaration( + node: EnumDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + name: Identifier, + members: ReadonlyArray) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name @@ -1542,7 +1746,7 @@ namespace ts { : node; } - export function createModuleDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags) { + export function createModuleDeclaration(decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags) { const node = createSynthesizedNode(SyntaxKind.ModuleDeclaration); node.flags |= flags & (NodeFlags.Namespace | NodeFlags.NestedNamespace | NodeFlags.GlobalAugmentation); node.decorators = asNodeArray(decorators); @@ -1552,7 +1756,7 @@ namespace ts { return node; } - export function updateModuleDeclaration(node: ModuleDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined) { + export function updateModuleDeclaration(node: ModuleDeclaration, decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, name: ModuleName, body: ModuleBody | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name @@ -1561,25 +1765,25 @@ namespace ts { : node; } - export function createModuleBlock(statements: Statement[]) { + export function createModuleBlock(statements: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.ModuleBlock); node.statements = createNodeArray(statements); return node; } - export function updateModuleBlock(node: ModuleBlock, statements: Statement[]) { + export function updateModuleBlock(node: ModuleBlock, statements: ReadonlyArray) { return node.statements !== statements ? updateNode(createModuleBlock(statements), node) : node; } - export function createCaseBlock(clauses: CaseOrDefaultClause[]): CaseBlock { + export function createCaseBlock(clauses: ReadonlyArray): CaseBlock { const node = createSynthesizedNode(SyntaxKind.CaseBlock); node.clauses = createNodeArray(clauses); return node; } - export function updateCaseBlock(node: CaseBlock, clauses: CaseOrDefaultClause[]) { + export function updateCaseBlock(node: CaseBlock, clauses: ReadonlyArray) { return node.clauses !== clauses ? updateNode(createCaseBlock(clauses), node) : node; @@ -1597,7 +1801,7 @@ namespace ts { : node; } - export function createImportEqualsDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference) { + export function createImportEqualsDeclaration(decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, name: string | Identifier, moduleReference: ModuleReference) { const node = createSynthesizedNode(SyntaxKind.ImportEqualsDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -1606,7 +1810,7 @@ namespace ts { return node; } - export function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference) { + export function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, name: Identifier, moduleReference: ModuleReference) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name @@ -1615,7 +1819,11 @@ namespace ts { : node; } - export function createImportDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier?: Expression): ImportDeclaration { + export function createImportDeclaration( + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + importClause: ImportClause | undefined, + moduleSpecifier?: Expression): ImportDeclaration { const node = createSynthesizedNode(SyntaxKind.ImportDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -1624,7 +1832,12 @@ namespace ts { return node; } - export function updateImportDeclaration(node: ImportDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression | undefined) { + export function updateImportDeclaration( + node: ImportDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.importClause !== importClause @@ -1659,13 +1872,13 @@ namespace ts { : node; } - export function createNamedImports(elements: ImportSpecifier[]): NamedImports { + export function createNamedImports(elements: ReadonlyArray): NamedImports { const node = createSynthesizedNode(SyntaxKind.NamedImports); node.elements = createNodeArray(elements); return node; } - export function updateNamedImports(node: NamedImports, elements: ImportSpecifier[]) { + export function updateNamedImports(node: NamedImports, elements: ReadonlyArray) { return node.elements !== elements ? updateNode(createNamedImports(elements), node) : node; @@ -1685,7 +1898,7 @@ namespace ts { : node; } - export function createExportAssignment(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, isExportEquals: boolean, expression: Expression) { + export function createExportAssignment(decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, isExportEquals: boolean, expression: Expression) { const node = createSynthesizedNode(SyntaxKind.ExportAssignment); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -1694,7 +1907,7 @@ namespace ts { return node; } - export function updateExportAssignment(node: ExportAssignment, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, expression: Expression) { + export function updateExportAssignment(node: ExportAssignment, decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, expression: Expression) { return node.decorators !== decorators || node.modifiers !== modifiers || node.expression !== expression @@ -1702,7 +1915,7 @@ namespace ts { : node; } - export function createExportDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, exportClause: NamedExports | undefined, moduleSpecifier?: Expression) { + export function createExportDeclaration(decorators: ReadonlyArray | undefined, modifiers: ReadonlyArray | undefined, exportClause: NamedExports | undefined, moduleSpecifier?: Expression) { const node = createSynthesizedNode(SyntaxKind.ExportDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -1711,7 +1924,12 @@ namespace ts { return node; } - export function updateExportDeclaration(node: ExportDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, exportClause: NamedExports | undefined, moduleSpecifier: Expression | undefined) { + export function updateExportDeclaration( + node: ExportDeclaration, + decorators: ReadonlyArray | undefined, + modifiers: ReadonlyArray | undefined, + exportClause: NamedExports | undefined, + moduleSpecifier: Expression | undefined) { return node.decorators !== decorators || node.modifiers !== modifiers || node.exportClause !== exportClause @@ -1720,13 +1938,13 @@ namespace ts { : node; } - export function createNamedExports(elements: ExportSpecifier[]) { + export function createNamedExports(elements: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.NamedExports); node.elements = createNodeArray(elements); return node; } - export function updateNamedExports(node: NamedExports, elements: ExportSpecifier[]) { + export function updateNamedExports(node: NamedExports, elements: ReadonlyArray) { return node.elements !== elements ? updateNode(createNamedExports(elements), node) : node; @@ -1762,7 +1980,7 @@ namespace ts { // JSX - export function createJsxElement(openingElement: JsxOpeningElement, children: JsxChild[], closingElement: JsxClosingElement) { + export function createJsxElement(openingElement: JsxOpeningElement, children: ReadonlyArray, closingElement: JsxClosingElement) { const node = createSynthesizedNode(SyntaxKind.JsxElement); node.openingElement = openingElement; node.children = createNodeArray(children); @@ -1770,7 +1988,7 @@ namespace ts { return node; } - export function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: JsxChild[], closingElement: JsxClosingElement) { + export function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: ReadonlyArray, closingElement: JsxClosingElement) { return node.openingElement !== openingElement || node.children !== children || node.closingElement !== closingElement @@ -1832,13 +2050,13 @@ namespace ts { : node; } - export function createJsxAttributes(properties: JsxAttributeLike[]) { + export function createJsxAttributes(properties: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.JsxAttributes); node.properties = createNodeArray(properties); return node; } - export function updateJsxAttributes(node: JsxAttributes, properties: JsxAttributeLike[]) { + export function updateJsxAttributes(node: JsxAttributes, properties: ReadonlyArray) { return node.properties !== properties ? updateNode(createJsxAttributes(properties), node) : node; @@ -1871,40 +2089,40 @@ namespace ts { // Clauses - export function createCaseClause(expression: Expression, statements: Statement[]) { + export function createCaseClause(expression: Expression, statements: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.CaseClause); node.expression = parenthesizeExpressionForList(expression); node.statements = createNodeArray(statements); return node; } - export function updateCaseClause(node: CaseClause, expression: Expression, statements: Statement[]) { + export function updateCaseClause(node: CaseClause, expression: Expression, statements: ReadonlyArray) { return node.expression !== expression || node.statements !== statements ? updateNode(createCaseClause(expression, statements), node) : node; } - export function createDefaultClause(statements: Statement[]) { + export function createDefaultClause(statements: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.DefaultClause); node.statements = createNodeArray(statements); return node; } - export function updateDefaultClause(node: DefaultClause, statements: Statement[]) { + export function updateDefaultClause(node: DefaultClause, statements: ReadonlyArray) { return node.statements !== statements ? updateNode(createDefaultClause(statements), node) : node; } - export function createHeritageClause(token: HeritageClause["token"], types: ExpressionWithTypeArguments[]) { + export function createHeritageClause(token: HeritageClause["token"], types: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.HeritageClause); node.token = token; node.types = createNodeArray(types); return node; } - export function updateHeritageClause(node: HeritageClause, types: ExpressionWithTypeArguments[]) { + export function updateHeritageClause(node: HeritageClause, types: ReadonlyArray) { return node.types !== types ? updateNode(createHeritageClause(node.token, types), node) : node; @@ -1985,7 +2203,7 @@ namespace ts { // Top-level nodes - export function updateSourceFileNode(node: SourceFile, statements: Statement[]) { + export function updateSourceFileNode(node: SourceFile, statements: ReadonlyArray) { if (node.statements !== statements) { const updated = createSynthesizedNode(SyntaxKind.SourceFile); updated.flags |= node.flags; @@ -2097,7 +2315,7 @@ namespace ts { return node; } - function flattenCommaElements(node: Expression): Expression | Expression[] { + function flattenCommaElements(node: Expression): Expression | ReadonlyArray { if (nodeIsSynthesized(node) && !isParseTreeNode(node) && !node.original && !node.emitNode && !node.id) { if (node.kind === SyntaxKind.CommaListExpression) { return (node).elements; @@ -2109,13 +2327,13 @@ namespace ts { return node; } - export function createCommaList(elements: Expression[]) { + export function createCommaList(elements: ReadonlyArray) { const node = createSynthesizedNode(SyntaxKind.CommaListExpression); node.elements = createNodeArray(sameFlatMap(elements, flattenCommaElements)); return node; } - export function updateCommaList(node: CommaListExpression, elements: Expression[]) { + export function updateCommaList(node: CommaListExpression, elements: ReadonlyArray) { return node.elements !== elements ? updateNode(createCommaList(elements), node) : node; @@ -2227,7 +2445,7 @@ namespace ts { return typeof value === "string" || typeof value === "number" ? createLiteral(value) : value; } - function asNodeArray(array: T[] | undefined): NodeArray | undefined { + function asNodeArray(array: ReadonlyArray | undefined): NodeArray | undefined { return array ? createNodeArray(array) : undefined; } @@ -2575,7 +2793,7 @@ namespace ts { } } - export function createFunctionCall(func: Expression, thisArg: Expression, argumentsList: Expression[], location?: TextRange) { + export function createFunctionCall(func: Expression, thisArg: Expression, argumentsList: ReadonlyArray, location?: TextRange) { return setTextRange( createCall( createPropertyAccess(func, "call"), @@ -3273,7 +3491,7 @@ namespace ts { * @param ensureUseStrict: boolean determining whether the function need to add prologue-directives * @param visitor: Optional callback used to visit any custom prologue directives. */ - export function addPrologue(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number { + export function addPrologue(target: Statement[], source: ReadonlyArray, ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number { const offset = addStandardPrologue(target, source, ensureUseStrict); return addCustomPrologue(target, source, offset, visitor); } @@ -3284,7 +3502,7 @@ namespace ts { * This function needs to be called whenever we transform the statement * list of a source file, namespace, or function-like body. */ - export function addStandardPrologue(target: Statement[], source: Statement[], ensureUseStrict?: boolean): number { + export function addStandardPrologue(target: Statement[], source: ReadonlyArray, ensureUseStrict?: boolean): number { Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array"); let foundUseStrict = false; let statementOffset = 0; @@ -3314,7 +3532,7 @@ namespace ts { * This function needs to be called whenever we transform the statement * list of a source file, namespace, or function-like body. */ - export function addCustomPrologue(target: Statement[], source: Statement[], statementOffset: number, visitor?: (node: Node) => VisitResult): number { + export function addCustomPrologue(target: Statement[], source: ReadonlyArray, statementOffset: number, visitor?: (node: Node) => VisitResult): number { const numStatements = source.length; while (statementOffset < numStatements) { const statement = source[statementOffset]; @@ -3329,7 +3547,7 @@ namespace ts { return statementOffset; } - export function startsWithUseStrict(statements: Statement[]) { + export function startsWithUseStrict(statements: ReadonlyArray) { const firstStatement = firstOrUndefined(statements); return firstStatement !== undefined && isPrologueDirective(firstStatement) @@ -3680,21 +3898,30 @@ namespace ts { return member; } - export function parenthesizeElementTypeMembers(members: TypeNode[]) { + export function parenthesizeArrayTypeMember(member: TypeNode) { + switch (member.kind) { + case SyntaxKind.TypeQuery: + case SyntaxKind.TypeOperator: + return createParenthesizedType(member); + } + return parenthesizeElementTypeMember(member); + } + + export function parenthesizeElementTypeMembers(members: ReadonlyArray) { return createNodeArray(sameMap(members, parenthesizeElementTypeMember)); } - export function parenthesizeTypeParameters(typeParameters: TypeNode[]) { + export function parenthesizeTypeParameters(typeParameters: ReadonlyArray) { if (some(typeParameters)) { - const nodeArray = createNodeArray() as NodeArray; + const params: TypeNode[] = []; for (let i = 0; i < typeParameters.length; ++i) { const entry = typeParameters[i]; - nodeArray.push(i === 0 && isFunctionOrConstructorTypeNode(entry) && entry.typeParameters ? + params.push(i === 0 && isFunctionOrConstructorTypeNode(entry) && entry.typeParameters ? createParenthesizedType(entry) : entry); } - return nodeArray; + return createNodeArray(params); } } @@ -4122,18 +4349,18 @@ namespace ts { /** * Gets the elements of a BindingOrAssignmentPattern */ - export function getElementsOfBindingOrAssignmentPattern(name: BindingOrAssignmentPattern): BindingOrAssignmentElement[] { + export function getElementsOfBindingOrAssignmentPattern(name: BindingOrAssignmentPattern): ReadonlyArray { switch (name.kind) { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ArrayLiteralExpression: // `a` in `{a}` // `a` in `[a]` - return name.elements; + return >name.elements; case SyntaxKind.ObjectLiteralExpression: // `a` in `{a}` - return name.properties; + return >name.properties; } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 20c9559a8f4..0be7734968f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1121,8 +1121,8 @@ namespace ts { new TokenConstructor(kind, pos, pos); } - function createNodeArray(elements?: T[], pos?: number): NodeArray { - const array = >(elements || []); + function createNodeArray(elements?: T[], pos?: number): MutableNodeArray { + const array = >(elements || []); if (!(pos >= 0)) { pos = getNodePos(); } @@ -4342,7 +4342,7 @@ namespace ts { parseExpected(SyntaxKind.OpenParenToken); node.expression = allowInAnd(parseExpression); parseExpected(SyntaxKind.CloseParenToken); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parseSpreadElement(): Expression { @@ -5395,7 +5395,7 @@ namespace ts { } function parseDecorators(): NodeArray { - let decorators: NodeArray; + let decorators: NodeArray & Decorator[]; while (true) { const decoratorStart = getNodePos(); if (!parseOptional(SyntaxKind.AtToken)) { @@ -5426,7 +5426,7 @@ namespace ts { * In such situations, 'permitInvalidConstAsModifier' should be set to true. */ function parseModifiers(permitInvalidConstAsModifier?: boolean): NodeArray | undefined { - let modifiers: NodeArray | undefined; + let modifiers: MutableNodeArray | undefined; while (true) { const modifierStart = scanner.getStartPos(); const modifierKind = token(); @@ -6165,7 +6165,7 @@ namespace ts { Debug.assert(start <= end); Debug.assert(end <= content.length); - let tags: NodeArray; + let tags: MutableNodeArray; const comments: string[] = []; let result: JSDoc; @@ -6673,9 +6673,9 @@ namespace ts { const propertyTag = parseParameterOrPropertyTag(atToken, tagName, /*shouldParseParamTag*/ false) as JSDocPropertyTag; if (propertyTag) { if (!parentTag.jsDocPropertyTags) { - parentTag.jsDocPropertyTags = >[]; + parentTag.jsDocPropertyTags = >[]; } - parentTag.jsDocPropertyTags.push(propertyTag); + (parentTag.jsDocPropertyTags as MutableNodeArray).push(propertyTag); return true; } // Error parsing property tag diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 3d63edddac1..f15baeefcdb 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -3,7 +3,6 @@ /// namespace ts { - const emptyArray: any[] = []; const ignoreDiagnosticCommentRegEx = /(^\s*$)|(^\s*\/\/\/?\s*(@ts-ignore)?)/; export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string { @@ -1390,8 +1389,8 @@ namespace ts { const isExternalModuleFile = isExternalModule(file); // file.imports may not be undefined if there exists dynamic import - let imports: LiteralExpression[]; - let moduleAugmentations: LiteralExpression[]; + let imports: StringLiteral[]; + let moduleAugmentations: StringLiteral[]; let ambientModules: string[]; // If we are importing helpers, we need to add a synthetic reference to resolve the @@ -1426,23 +1425,23 @@ namespace ts { case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.ExportDeclaration: const moduleNameExpr = getExternalModuleName(node); - if (!moduleNameExpr || moduleNameExpr.kind !== SyntaxKind.StringLiteral) { + if (!moduleNameExpr || !isStringLiteral(moduleNameExpr)) { break; } - if (!(moduleNameExpr).text) { + if (!moduleNameExpr.text) { break; } // TypeScript 1.0 spec (April 2014): 12.1.6 // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules // only through top - level external module names. Relative external module names are not permitted. - if (!inAmbientModule || !isExternalModuleNameRelative((moduleNameExpr).text)) { - (imports || (imports = [])).push(moduleNameExpr); + if (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text)) { + (imports || (imports = [])).push(moduleNameExpr); } break; case SyntaxKind.ModuleDeclaration: if (isAmbientModule(node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) { - const moduleName = (node).name; + const moduleName = (node).name; // Ambient module declarations can be interpreted as augmentations for some existing external modules. // This will happen in two cases: // - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index eca28ee814b..1f9b179dabb 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -492,7 +492,7 @@ namespace ts { /** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement * `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);` */ - function createRestCall(context: TransformationContext, value: Expression, elements: BindingOrAssignmentElement[], computedTempVariables: Expression[], location: TextRange): Expression { + function createRestCall(context: TransformationContext, value: Expression, elements: ReadonlyArray, computedTempVariables: ReadonlyArray, location: TextRange): Expression { context.requestEmitHelper(restHelper); const propertyNames: Expression[] = []; let computedTempVariableOffset = 0; diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 19f9d00c656..823b133a4cc 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -1963,7 +1963,7 @@ namespace ts { updated, setTextRange( createNodeArray( - prependCaptureNewTargetIfNeeded(updated.statements, node, /*copyOnWrite*/ true) + prependCaptureNewTargetIfNeeded(updated.statements as MutableNodeArray, node, /*copyOnWrite*/ true) ), /*location*/ updated.statements ) @@ -3199,7 +3199,7 @@ namespace ts { function addStatementToStartOfBlock(block: Block, statement: Statement): Block { const transformedStatements = visitNodes(block.statements, visitor, isStatement); - return updateBlock(block, [statement].concat(transformedStatements)); + return updateBlock(block, [statement, ...transformedStatements]); } /** diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 0b332c237f7..732a613f1b4 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -156,7 +156,7 @@ namespace ts { return visitEachChild(node, visitor, context); } - function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] { + function chunkObjectLiteralElements(elements: ReadonlyArray): Expression[] { let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[]; const objects: Expression[] = []; for (const e of elements) { diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index a12a34c9537..b120f5c8227 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -1176,7 +1176,7 @@ namespace ts { return visitEachChild(node, visitor, context); } - function transformAndEmitStatements(statements: Statement[], start = 0) { + function transformAndEmitStatements(statements: ReadonlyArray, start = 0) { const numStatements = statements.length; for (let i = start; i < numStatements; i++) { transformAndEmitStatement(statements[i]); diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index ca22cb701d0..efdf38009e0 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -77,7 +77,7 @@ namespace ts { return visitJsxOpeningLikeElement(node, /*children*/ undefined, isChild, /*location*/ node); } - function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: JsxChild[], isChild: boolean, location: TextRange) { + function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: ReadonlyArray, isChild: boolean, location: TextRange) { const tagName = getTagName(node); let objectProperties: Expression; const attrs = node.attributes.properties; diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 5fd1b7b62da..4c20807fa86 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -522,7 +522,7 @@ namespace ts { return parameter.decorators !== undefined && parameter.decorators.length > 0; } - function getClassFacts(node: ClassDeclaration, staticProperties: PropertyDeclaration[]) { + function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray) { let facts = ClassFacts.None; if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties; if (getClassExtendsHeritageClauseElement(node)) facts |= ClassFacts.HasExtendsClause; @@ -1051,7 +1051,7 @@ namespace ts { * * @param node The constructor node. */ - function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ParameterDeclaration[] { + function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ReadonlyArray { return filter(node.parameters, isParameterWithPropertyAssignment); } @@ -1104,7 +1104,7 @@ namespace ts { * @param node The class node. * @param isStatic A value indicating whether to get properties from the static or instance side of the class. */ - function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): PropertyDeclaration[] { + function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray { return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty); } @@ -1144,7 +1144,7 @@ namespace ts { * @param properties An array of property declarations to transform. * @param receiver The receiver on which each property should be assigned. */ - function addInitializedPropertyStatements(statements: Statement[], properties: PropertyDeclaration[], receiver: LeftHandSideExpression) { + function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray, receiver: LeftHandSideExpression) { for (const property of properties) { const statement = createStatement(transformInitializedProperty(property, receiver)); setSourceMapRange(statement, moveRangePastModifiers(property)); @@ -1159,7 +1159,7 @@ namespace ts { * @param properties An array of property declarations to transform. * @param receiver The receiver on which each property should be assigned. */ - function generateInitializedPropertyExpressions(properties: PropertyDeclaration[], receiver: LeftHandSideExpression) { + function generateInitializedPropertyExpressions(properties: ReadonlyArray, receiver: LeftHandSideExpression) { const expressions: Expression[] = []; for (const property of properties) { const expression = transformInitializedProperty(property, receiver); @@ -1194,7 +1194,7 @@ namespace ts { * @param isStatic A value indicating whether to retrieve static or instance members of * the class. */ - function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): ClassElement[] { + function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray { return filter(node.members, isStatic ? isStaticDecoratedClassElement : isInstanceDecoratedClassElement); } @@ -1233,8 +1233,8 @@ namespace ts { * A structure describing the decorators for a class element. */ interface AllDecorators { - decorators: Decorator[]; - parameters?: Decorator[][]; + decorators: ReadonlyArray; + parameters?: ReadonlyArray>; } /** @@ -1244,7 +1244,7 @@ namespace ts { * @param node The function-like node. */ function getDecoratorsOfParameters(node: FunctionLikeDeclaration) { - let decorators: Decorator[][]; + let decorators: ReadonlyArray[]; if (node) { const parameters = node.parameters; for (let i = 0; i < parameters.length; i++) { @@ -1377,7 +1377,7 @@ namespace ts { const decoratorExpressions: Expression[] = []; addRange(decoratorExpressions, map(allDecorators.decorators, transformDecorator)); - addRange(decoratorExpressions, flatMap(allDecorators.parameters, transformDecoratorsOfParameter)); + addRange(decoratorExpressions, flatMap(allDecorators.parameters, transformDecoratorsOfParameter)); addTypeMetadata(node, container, decoratorExpressions); return decoratorExpressions; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c507d9ee043..c70e7632201 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -8,13 +8,10 @@ namespace ts { [index: string]: T; } - /** ES6 Map interface. */ - export interface Map { + /** ES6 Map interface, only read methods included. */ + export interface ReadonlyMap { get(key: string): T | undefined; has(key: string): boolean; - set(key: string, value: T): this; - delete(key: string): boolean; - clear(): void; forEach(action: (value: T, key: string) => void): void; readonly size: number; keys(): Iterator; @@ -22,6 +19,13 @@ namespace ts { entries(): Iterator<[string, T]>; } + /** ES6 Map interface. */ + export interface Map extends ReadonlyMap { + set(key: string, value: T): this; + delete(key: string): boolean; + clear(): void; + } + /** ES6 Iterator type. */ export interface Iterator { next(): { value: T, done: false } | { value: never, done: true }; @@ -519,7 +523,10 @@ namespace ts { /* @internal */ contextualMapper?: TypeMapper; // Mapper for contextual type } - export interface NodeArray extends Array, TextRange { + /* @internal */ + export type MutableNodeArray = NodeArray & T[]; + + export interface NodeArray extends ReadonlyArray, TextRange { hasTrailingComma?: boolean; /* @internal */ transformFlags?: TransformFlags; } @@ -673,7 +680,7 @@ namespace ts { kind: SyntaxKind.Parameter; parent?: SignatureDeclaration; dotDotDotToken?: DotDotDotToken; // Present on rest parameter - name: BindingName; // Declared parameter name + name?: BindingName; // Declared parameter name. Missing if this is a parameter in a JSDocFunctionType. questionToken?: QuestionToken; // Present on optional parameter type?: TypeNode; // Optional type annotation initializer?: Expression; // Optional initializer @@ -751,7 +758,7 @@ namespace ts { export interface VariableLikeDeclaration extends NamedDeclaration { propertyName?: PropertyName; dotDotDotToken?: DotDotDotToken; - name: DeclarationName; + name?: DeclarationName; // May be missing for ParameterDeclaration, see comment there questionToken?: QuestionToken; type?: TypeNode; initializer?: Expression; @@ -2314,10 +2321,10 @@ namespace ts { // Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead /* @internal */ resolvedModules: Map; /* @internal */ resolvedTypeReferenceDirectiveNames: Map; - /* @internal */ imports: StringLiteral[]; - /* @internal */ moduleAugmentations: StringLiteral[]; + /* @internal */ imports: ReadonlyArray; + /* @internal */ moduleAugmentations: ReadonlyArray; /* @internal */ patternAmbientModules?: PatternAmbientModule[]; - /* @internal */ ambientModuleNames: string[]; + /* @internal */ ambientModuleNames: ReadonlyArray; /* @internal */ checkJsDirective: CheckJsDirective | undefined; } @@ -2520,6 +2527,7 @@ namespace ts { * Returns `any` if the index is not valid. */ /* @internal */ getParameterType(signature: Signature, parameterIndex: number): Type; + getNullableType(type: Type, flags: TypeFlags): Type; getNonNullableType(type: Type): Type; /** Note that the resulting nodes cannot be checked. */ @@ -2677,6 +2685,7 @@ namespace ts { SuppressAnyReturnType = 1 << 12, // If the return type is any-like, don't offer a return type. AddUndefined = 1 << 13, // Add undefined to types of initialized, non-optional parameters WriteClassExpressionAsTypeLiteral = 1 << 14, // Write a type literal instead of (Anonymous class) + InArrayType = 1 << 15, // Writing an array element type } export const enum SymbolFormatFlags { @@ -2982,13 +2991,10 @@ namespace ts { */ export type __String = (string & { __escapedIdentifier: void }) | (void & { __escapedIdentifier: void }) | InternalSymbolName; - /** EscapedStringMap based on ES6 Map interface. */ - export interface UnderscoreEscapedMap { + /** ReadonlyMap where keys are `__String`s. */ + export interface ReadonlyUnderscoreEscapedMap { get(key: __String): T | undefined; has(key: __String): boolean; - set(key: __String, value: T): this; - delete(key: __String): boolean; - clear(): void; forEach(action: (value: T, key: __String) => void): void; readonly size: number; keys(): Iterator<__String>; @@ -2996,6 +3002,13 @@ namespace ts { entries(): Iterator<[__String, T]>; } + /** Map where keys are `__String`s. */ + export interface UnderscoreEscapedMap extends ReadonlyUnderscoreEscapedMap { + set(key: __String, value: T): this; + delete(key: __String): boolean; + clear(): void; + } + /** SymbolTable based on ES6 Map interface. */ export type SymbolTable = UnderscoreEscapedMap; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b7fabdda381..e001ec43f62 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -640,7 +640,8 @@ namespace ts { const commentRanges = (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter || node.kind === SyntaxKind.FunctionExpression || - node.kind === SyntaxKind.ArrowFunction) ? + node.kind === SyntaxKind.ArrowFunction || + node.kind === SyntaxKind.ParenthesizedExpression) ? concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) : getLeadingCommentRangesOfNodeFromText(node, text); // True if the comment starts with '/**' but not if it is '/**/' @@ -1539,27 +1540,9 @@ namespace ts { } export function getJSDocParameterTags(param: ParameterDeclaration): JSDocParameterTag[] | undefined { - const func = param.parent; - const tags = getJSDocTags(func); - if (!tags) return undefined; - - if (!param.name) { - // this is an anonymous jsdoc param from a `function(type1, type2): type3` specification - const paramIndex = func.parameters.indexOf(param); - Debug.assert(paramIndex !== -1); - let curParamIndex = 0; - for (const tag of tags) { - if (isJSDocParameterTag(tag)) { - if (curParamIndex === paramIndex) { - return [tag]; - } - curParamIndex++; - } - } - } - else if (param.name.kind === SyntaxKind.Identifier) { - const name = (param.name as Identifier).text; - return tags.filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && tag.name.text === name) as JSDocParameterTag[]; + if (param.name && isIdentifier(param.name)) { + const name = param.name.text; + return getJSDocTags(param.parent).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && tag.name.text === name) as JSDocParameterTag[]; } else { // TODO: it's a destructured parameter, so it should look up an "object type" series of multiple lines @@ -2748,7 +2731,7 @@ namespace ts { * Gets the effective type parameters. If the node was parsed in a * JavaScript file, gets the type parameters from the `@template` tag from JSDoc. */ - export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): TypeParameterDeclaration[] { + export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray { if (node.typeParameters) { return node.typeParameters; } @@ -4756,7 +4739,7 @@ namespace ts { // Node Arrays /* @internal */ - export function isNodeArray(array: T[]): array is NodeArray { + export function isNodeArray(array: ReadonlyArray): array is NodeArray { return array.hasOwnProperty("pos") && array.hasOwnProperty("end"); } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 4dbfbf72e9f..1ce42199372 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -86,7 +86,7 @@ namespace ts { return nodes; } - let updated: NodeArray; + let updated: MutableNodeArray; // Ensure start and count have valid values const length = nodes.length; @@ -901,7 +901,7 @@ namespace ts { * * @param nodes The NodeArray. */ - function extractSingleNode(nodes: Node[]): Node { + function extractSingleNode(nodes: ReadonlyArray): Node { Debug.assert(nodes.length <= 1, "Too many nodes written to output."); return singleOrUndefined(nodes); } @@ -1421,13 +1421,13 @@ namespace ts { /** * Merges generated lexical declarations into a new statement list. */ - export function mergeLexicalEnvironment(statements: NodeArray, declarations: Statement[]): NodeArray; + export function mergeLexicalEnvironment(statements: NodeArray, declarations: ReadonlyArray): NodeArray; /** * Appends generated lexical declarations to an array of statements. */ - export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]): Statement[]; - export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]) { + export function mergeLexicalEnvironment(statements: Statement[], declarations: ReadonlyArray): Statement[]; + export function mergeLexicalEnvironment(statements: Statement[] | NodeArray, declarations: ReadonlyArray) { if (!some(declarations)) { return statements; } @@ -1442,7 +1442,7 @@ namespace ts { * * @param nodes The NodeArray. */ - export function liftToBlock(nodes: Node[]): Statement { + export function liftToBlock(nodes: ReadonlyArray): Statement { Debug.assert(every(nodes, isStatement), "Cannot lift nodes to a Block."); return singleOrUndefined(nodes) || createBlock(>nodes); } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 5e83c5339c6..d32bf92b007 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -130,7 +130,7 @@ namespace FourSlash { // 0 - cancelled // >0 - not cancelled // <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled - private static NotCanceled: number = -1; + private static readonly NotCanceled: number = -1; private numberOfCallsBeforeCancellation: number = TestCancellationToken.NotCanceled; public isCancellationRequested(): boolean { diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 156a9e08dce..c604b224656 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -108,7 +108,7 @@ namespace Harness.LanguageService { } class DefaultHostCancellationToken implements ts.HostCancellationToken { - public static Instance = new DefaultHostCancellationToken(); + public static readonly Instance = new DefaultHostCancellationToken(); public isCancellationRequested() { return false; diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index 1b7d54595e0..a25a0181511 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -238,10 +238,8 @@ namespace RWC { } class RWCRunner extends RunnerBase { - private static sourcePath = "internal/cases/rwc/"; - public enumerateTestFiles() { - return Harness.IO.listFiles(RWCRunner.sourcePath, /.+\.json$/); + return Harness.IO.listFiles("internal/cases/rwc/", /.+\.json$/); } public kind(): TestRunnerKind { diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index 939a02c7634..6c5b186f2b8 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -4,19 +4,19 @@ /* tslint:disable:no-null-keyword */ class Test262BaselineRunner extends RunnerBase { - private static basePath = "internal/cases/test262"; - private static helpersFilePath = "tests/cases/test262-harness/helpers.d.ts"; - private static helperFile: Harness.Compiler.TestFile = { + private static readonly basePath = "internal/cases/test262"; + private static readonly helpersFilePath = "tests/cases/test262-harness/helpers.d.ts"; + private static readonly helperFile: Harness.Compiler.TestFile = { unitName: Test262BaselineRunner.helpersFilePath, content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath), }; - private static testFileExtensionRegex = /\.js$/; - private static options: ts.CompilerOptions = { + private static readonly testFileExtensionRegex = /\.js$/; + private static readonly options: ts.CompilerOptions = { allowNonTsExtensions: true, target: ts.ScriptTarget.Latest, module: ts.ModuleKind.CommonJS }; - private static baselineOptions: Harness.Baseline.BaselineOptions = { + private static readonly baselineOptions: Harness.Baseline.BaselineOptions = { Subfolder: "test262", Baselinefolder: "internal/baselines" }; diff --git a/src/harness/unittests/textChanges.ts b/src/harness/unittests/textChanges.ts index 8ac74668023..3c9ebff68f9 100644 --- a/src/harness/unittests/textChanges.ts +++ b/src/harness/unittests/textChanges.ts @@ -67,12 +67,12 @@ namespace ts { } function flattenNodes(n: Node) { - const data: (Node | NodeArray)[] = []; + const data: (Node | NodeArray)[] = []; walk(n); return data; - function walk(n: Node | Node[]): void { - data.push(n); + function walk(n: Node | NodeArray): void { + data.push(n); return isArray(n) ? forEach(n, walk) : forEachChild(n, walk, walk); } } diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index a63a8c3daf8..14d174bf6af 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -704,7 +704,7 @@ namespace ts.projectSystem { } clearOutput() { - this.output.length = 0; + clear(this.output); } readonly readFile = (s: string) => (this.fs.get(this.toFullPath(s))).content; diff --git a/src/server/builder.ts b/src/server/builder.ts index bc86780fbbe..8a10682b4cc 100644 --- a/src/server/builder.ts +++ b/src/server/builder.ts @@ -223,7 +223,7 @@ namespace ts.server { for (const reference of this.references) { reference.removeReferencedBy(this); } - this.references = createSortedArray(); + clear(this.references); } } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 5f660defcf2..446a46692ed 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -225,10 +225,7 @@ namespace ts.server { const fileNamePropertyReader: FilePropertyReader = { getFileName: x => x, getScriptKind: _ => undefined, - hasMixedContent: (fileName, extraFileExtensions) => { - const mixedContentExtensions = map(filter(extraFileExtensions, item => item.isMixedContent), item => item.extension); - return forEach(mixedContentExtensions, extension => fileExtensionIs(fileName, extension)); - } + hasMixedContent: (fileName, extraFileExtensions) => some(extraFileExtensions, ext => ext.isMixedContent && fileExtensionIs(fileName, ext.extension)), }; const externalFilePropertyReader: FilePropertyReader = { @@ -725,7 +722,7 @@ namespace ts.server { switch (project.projectKind) { case ProjectKind.External: - removeItemFromSet(this.externalProjects, project); + unorderedRemoveItem(this.externalProjects, project); this.projectToSizeMap.delete((project as ExternalProject).externalProjectName); break; case ProjectKind.Configured: @@ -734,7 +731,7 @@ namespace ts.server { this.setConfigFilePresenceByClosedConfigFile(project); break; case ProjectKind.Inferred: - removeItemFromSet(this.inferredProjects, project); + unorderedRemoveItem(this.inferredProjects, project); break; } } @@ -793,7 +790,7 @@ namespace ts.server { info.close(); this.stopWatchingConfigFilesForClosedScriptInfo(info); - removeItemFromSet(this.openFiles, info); + unorderedRemoveItem(this.openFiles, info); // collect all projects that should be removed let projectsToRemove: Project[]; @@ -1896,7 +1893,7 @@ namespace ts.server { } /** Makes a filename safe to insert in a RegExp */ - private static filenameEscapeRegexp = /[-\/\\^$*+?.()|[\]{}]/g; + private static readonly filenameEscapeRegexp = /[-\/\\^$*+?.()|[\]{}]/g; private static escapeFilenameForRegex(filename: string) { return filename.replace(this.filenameEscapeRegexp, "\\$&"); } diff --git a/src/server/project.ts b/src/server/project.ts index c75cadb642b..6a8e46486ab 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -876,7 +876,7 @@ namespace ts.server { */ export class InferredProject extends Project { - private static newName = (() => { + private static readonly newName = (() => { let nextId = 1; return () => { const id = nextId; diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 902e9d0d97e..388dcd957dc 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -232,7 +232,7 @@ namespace ts.server { } break; default: - removeItemFromSet(this.containingProjects, project); + unorderedRemoveItem(this.containingProjects, project); break; } } @@ -251,7 +251,7 @@ namespace ts.server { p.addMissingFileRoot(this.fileName); } } - this.containingProjects.length = 0; + clear(this.containingProjects); } getDefaultProject() { diff --git a/src/server/session.ts b/src/server/session.ts index 02784145d4c..0df2dd1e399 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -162,19 +162,13 @@ namespace ts.server { * Represents operation that can schedule its next step to be executed later. * Scheduling is done via instance of NextStep. If on current step subsequent step was not scheduled - operation is assumed to be completed. */ - class MultistepOperation { + class MultistepOperation implements NextStep { private requestId: number; private timerHandle: any; private immediateId: any; private completed = true; - private readonly next: NextStep; - constructor(private readonly operationHost: MultistepOperationHost) { - this.next = { - immediate: action => this.immediate(action), - delay: (ms, action) => this.delay(ms, action) - }; - } + constructor(private readonly operationHost: MultistepOperationHost) {} public startNew(action: (next: NextStep) => void) { this.complete(); @@ -194,7 +188,7 @@ namespace ts.server { this.setImmediateId(undefined); } - private immediate(action: () => void) { + public immediate(action: () => void) { const requestId = this.requestId; Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "immediate: incorrect request id"); this.setImmediateId(this.operationHost.getServerHost().setImmediate(() => { @@ -203,7 +197,7 @@ namespace ts.server { })); } - private delay(ms: number, action: () => void) { + public delay(ms: number, action: () => void) { const requestId = this.requestId; Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "delay: incorrect request id"); this.setTimerHandle(this.operationHost.getServerHost().setTimeout(() => { @@ -219,7 +213,7 @@ namespace ts.server { stop = true; } else { - action(this.next); + action(this); } } catch (e) { diff --git a/src/server/utilities.ts b/src/server/utilities.ts index eec62606b9f..15a9fbb8035 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -103,24 +103,6 @@ namespace ts.server { } } - export function removeItemFromSet(items: T[], itemToRemove: T) { - if (items.length === 0) { - return; - } - const index = items.indexOf(itemToRemove); - if (index < 0) { - return; - } - if (index === items.length - 1) { - // last item - pop it - items.pop(); - } - else { - // non-last item - replace it with the last one - items[index] = items.pop(); - } - } - export type NormalizedPath = string & { __normalizedPathTag: any }; export function toNormalizedPath(fileName: string): NormalizedPath { diff --git a/src/services/codefixes/disableJsDiagnostics.ts b/src/services/codefixes/disableJsDiagnostics.ts index b5f9e5587a3..291dc61c32f 100644 --- a/src/services/codefixes/disableJsDiagnostics.ts +++ b/src/services/codefixes/disableJsDiagnostics.ts @@ -32,7 +32,7 @@ namespace ts.codefix { } } - // If all fails, add an extra new line immediatlly before the error span. + // If all fails, add an extra new line immediately before the error span. return { span: { start: position, length: 0 }, newText: `${position === startPosition ? "" : newLineCharacter}// @ts-ignore${newLineCharacter}` @@ -67,4 +67,4 @@ namespace ts.codefix { }] }]; } -} \ No newline at end of file +} diff --git a/src/services/codefixes/fixJSDocTypes.ts b/src/services/codefixes/fixJSDocTypes.ts new file mode 100644 index 00000000000..249bc32dbf7 --- /dev/null +++ b/src/services/codefixes/fixJSDocTypes.ts @@ -0,0 +1,40 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments.code], + getCodeActions: getActionsForJSDocTypes + }); + + function getActionsForJSDocTypes(context: CodeFixContext): CodeAction[] | undefined { + const sourceFile = context.sourceFile; + const node = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false); + const decl = ts.findAncestor(node, n => n.kind === SyntaxKind.VariableDeclaration); + if (!decl) return; + const checker = context.program.getTypeChecker(); + + const jsdocType = (decl as VariableDeclaration).type; + const original = getTextOfNode(jsdocType); + const type = checker.getTypeFromTypeNode(jsdocType); + const actions = [createAction(jsdocType, sourceFile.fileName, original, checker.typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTruncation))]; + if (jsdocType.kind === SyntaxKind.JSDocNullableType) { + // for nullable types, suggest the flow-compatible `T | null | undefined` + // in addition to the jsdoc/closure-compatible `T | null` + const replacementWithUndefined = checker.typeToString(checker.getNullableType(type, TypeFlags.Undefined), /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTruncation); + actions.push(createAction(jsdocType, sourceFile.fileName, original, replacementWithUndefined)); + } + return actions; + } + + function createAction(declaration: TypeNode, fileName: string, original: string, replacement: string): CodeAction { + return { + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Change_0_to_1), [original, replacement]), + changes: [{ + fileName, + textChanges: [{ + span: { start: declaration.getStart(), length: declaration.getWidth() }, + newText: replacement + }] + }], + }; + } +} diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index c38820231b0..ef670c81ba9 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -7,6 +7,7 @@ /// /// /// +/// /// /// /// diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index b45d2448a0a..d1599dc4cac 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -186,7 +186,7 @@ namespace ts.codefix { return parameters; } - function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, optional: boolean, modifiers: Modifier[] | undefined): MethodDeclaration { + function createMethodImplementingSignatures(signatures: ReadonlyArray, name: PropertyName, optional: boolean, modifiers: ReadonlyArray | undefined): MethodDeclaration { /** This is *a* signature with the maximal number of arguments, * such that if there is a "maximal" signature without rest arguments, * this is one of them. @@ -231,7 +231,13 @@ namespace ts.codefix { /*returnType*/ undefined); } - export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, optional: boolean, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) { + export function createStubbedMethod( + modifiers: ReadonlyArray, + name: PropertyName, + optional: boolean, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + returnType: TypeNode | undefined) { return createMethod( /*decorators*/ undefined, modifiers, diff --git a/src/services/completions.ts b/src/services/completions.ts index 12796a9b791..d7f0701caf2 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -963,7 +963,7 @@ namespace ts.Completions { isMemberCompletion = true; let typeMembers: Symbol[]; - let existingMembers: Declaration[]; + let existingMembers: ReadonlyArray; if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) { // We are completing on contextual types, but may also include properties @@ -1093,14 +1093,14 @@ namespace ts.Completions { } } const implementedInterfaceTypePropertySymbols = (classElementModifierFlags & ModifierFlags.Static) ? - undefined : - flatMap(implementsTypeNodes, typeNode => typeChecker.getPropertiesOfType(typeChecker.getTypeAtLocation(typeNode))); + emptyArray : + flatMap(implementsTypeNodes || emptyArray, typeNode => typeChecker.getPropertiesOfType(typeChecker.getTypeAtLocation(typeNode))); // List of property symbols of base type that are not private and already implemented symbols = filterClassMembersList( baseClassTypeToGetPropertiesFrom ? typeChecker.getPropertiesOfType(baseClassTypeToGetPropertiesFrom) : - undefined, + emptyArray, implementedInterfaceTypePropertySymbols, classLikeDeclaration.members, classElementModifierFlags); @@ -1443,7 +1443,7 @@ namespace ts.Completions { * @returns Symbols to be suggested at an import/export clause, barring those whose named imports/exports * do not occur at the current position and have not otherwise been typed. */ - function filterNamedImportOrExportCompletionItems(exportsOfModule: Symbol[], namedImportsOrExports: ImportOrExportSpecifier[]): Symbol[] { + function filterNamedImportOrExportCompletionItems(exportsOfModule: Symbol[], namedImportsOrExports: ReadonlyArray): Symbol[] { const existingImportsOrExports = createUnderscoreEscapedMap(); for (const element of namedImportsOrExports) { @@ -1469,7 +1469,7 @@ namespace ts.Completions { * @returns Symbols to be suggested in an object binding pattern or object literal expression, barring those whose declarations * do not occur at the current position and have not otherwise been typed. */ - function filterObjectMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] { + function filterObjectMembersList(contextualMemberSymbols: Symbol[], existingMembers: ReadonlyArray): Symbol[] { if (!existingMembers || existingMembers.length === 0) { return contextualMemberSymbols; } @@ -1518,7 +1518,11 @@ namespace ts.Completions { * * @returns Symbols to be suggested in an class element depending on existing memebers and symbol flags */ - function filterClassMembersList(baseSymbols: Symbol[], implementingTypeSymbols: Symbol[], existingMembers: ClassElement[], currentClassElementModifierFlags: ModifierFlags): Symbol[] { + function filterClassMembersList( + baseSymbols: ReadonlyArray, + implementingTypeSymbols: ReadonlyArray, + existingMembers: ReadonlyArray, + currentClassElementModifierFlags: ModifierFlags): Symbol[] { const existingMemberNames = createUnderscoreEscapedMap(); for (const m of existingMembers) { // Ignore omitted expressions for missing members @@ -1553,10 +1557,18 @@ namespace ts.Completions { } } - return concatenate( - filter(baseSymbols, baseProperty => isValidProperty(baseProperty, ModifierFlags.Private)), - filter(implementingTypeSymbols, implementingProperty => isValidProperty(implementingProperty, ModifierFlags.NonPublicAccessibilityModifier)) - ); + const result: Symbol[] = []; + addPropertySymbols(baseSymbols, ModifierFlags.Private); + addPropertySymbols(implementingTypeSymbols, ModifierFlags.NonPublicAccessibilityModifier); + return result; + + function addPropertySymbols(properties: ReadonlyArray, inValidModifierFlags: ModifierFlags) { + for (const property of properties) { + if (isValidProperty(property, inValidModifierFlags)) { + result.push(property); + } + } + } function isValidProperty(propertySymbol: Symbol, inValidModifierFlags: ModifierFlags) { return !existingMemberNames.get(propertySymbol.name) && diff --git a/src/services/documentHighlights.ts b/src/services/documentHighlights.ts index 0a2c8e726fc..eb1e2531143 100644 --- a/src/services/documentHighlights.ts +++ b/src/services/documentHighlights.ts @@ -298,21 +298,20 @@ namespace ts.DocumentHighlights { const keywords: Node[] = []; const modifierFlag: ModifierFlags = getFlagFromModifier(modifier); - let nodes: Node[]; + let nodes: ReadonlyArray; switch (container.kind) { case SyntaxKind.ModuleBlock: case SyntaxKind.SourceFile: // Container is either a class declaration or the declaration is a classDeclaration if (modifierFlag & ModifierFlags.Abstract) { - nodes = ((declaration).members).concat(declaration); + nodes = [...(declaration).members, declaration]; } else { nodes = (container).statements; } break; case SyntaxKind.Constructor: - nodes = ((container).parameters).concat( - (container.parent).members); + nodes = [...(container).parameters, ...(container.parent).members]; break; case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: @@ -326,11 +325,11 @@ namespace ts.DocumentHighlights { }); if (constructor) { - nodes = nodes.concat(constructor.parameters); + nodes = [...nodes, ...constructor.parameters]; } } else if (modifierFlag & ModifierFlags.Abstract) { - nodes = nodes.concat(container); + nodes = [...nodes, container]; } break; default: diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index b5ba809ec7d..ad9b2f179aa 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -1152,7 +1152,7 @@ namespace ts.formatting { } } - function getOpenTokenForList(node: Node, list: Node[]) { + function getOpenTokenForList(node: Node, list: ReadonlyArray) { switch (node.kind) { case SyntaxKind.Constructor: case SyntaxKind.FunctionDeclaration: diff --git a/src/services/formatting/ruleOperationContext.ts b/src/services/formatting/ruleOperationContext.ts index 6a19e23d57d..bf96363ad7d 100644 --- a/src/services/formatting/ruleOperationContext.ts +++ b/src/services/formatting/ruleOperationContext.ts @@ -4,13 +4,13 @@ namespace ts.formatting { export class RuleOperationContext { - private customContextChecks: { (context: FormattingContext): boolean; }[]; + private readonly customContextChecks: { (context: FormattingContext): boolean; }[]; constructor(...funcs: { (context: FormattingContext): boolean; }[]) { this.customContextChecks = funcs; } - static Any: RuleOperationContext = new RuleOperationContext(); + static readonly Any: RuleOperationContext = new RuleOperationContext(); public IsAny(): boolean { return this === RuleOperationContext.Any; diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index 18b0479c85a..a98986472f3 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -328,7 +328,7 @@ namespace ts.formatting { const containingList = getContainingList(node, sourceFile); return containingList ? getActualIndentationFromList(containingList) : Value.Unknown; - function getActualIndentationFromList(list: Node[]): number { + function getActualIndentationFromList(list: ReadonlyArray): number { const index = indexOf(list, node); return index !== -1 ? deriveActualIndentationFromList(list, index, sourceFile, options) : Value.Unknown; } @@ -378,7 +378,7 @@ namespace ts.formatting { } } - function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: EditorSettings): number { + function deriveActualIndentationFromList(list: ReadonlyArray, index: number, sourceFile: SourceFile, options: EditorSettings): number { Debug.assert(index >= 0 && index < list.length); const node = list[index]; diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index 0bed84a393b..b388a8551d2 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -191,7 +191,7 @@ namespace ts.GoToDefinition { return false; } - function tryAddSignature(signatureDeclarations: Declaration[] | undefined, selectConstructors: boolean, symbolKind: ScriptElementKind, symbolName: string, containerName: string, result: DefinitionInfo[]) { + function tryAddSignature(signatureDeclarations: ReadonlyArray | undefined, selectConstructors: boolean, symbolKind: ScriptElementKind, symbolName: string, containerName: string, result: DefinitionInfo[]) { if (!signatureDeclarations) { return false; } diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index c5e437f20fc..070b96101e2 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -241,7 +241,7 @@ namespace ts.JsDoc { return { newText: result, caretOffset: preamble.length }; } - function getParametersForJsDocOwningNode(commentOwner: Node): ParameterDeclaration[] { + function getParametersForJsDocOwningNode(commentOwner: Node): ReadonlyArray { if (isFunctionLike(commentOwner)) { return commentOwner.parameters; } @@ -266,7 +266,7 @@ namespace ts.JsDoc { * @param rightHandSide the expression which may contain an appropriate set of parameters * @returns the parameters of a signature found on the RHS if one exists; otherwise 'emptyArray'. */ - function getParametersFromRightHandSideOfAssignment(rightHandSide: Expression): ParameterDeclaration[] { + function getParametersFromRightHandSideOfAssignment(rightHandSide: Expression): ReadonlyArray { while (rightHandSide.kind === SyntaxKind.ParenthesizedExpression) { rightHandSide = (rightHandSide).expression; } diff --git a/src/services/shims.ts b/src/services/shims.ts index 03965cb5d48..e86e9053e57 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -1176,7 +1176,7 @@ namespace ts { public close(): void { // Forget all the registered shims - this._shims = []; + clear(this._shims); this.documentRegistry = undefined; } diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 00ab0165805..71e6bc00b00 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -1,8 +1,6 @@ /// /* @internal */ namespace ts.SignatureHelp { - const emptyArray: any[] = []; - export const enum ArgumentListKind { TypeArguments, CallArguments, diff --git a/tests/baselines/reference/aliasUsageInArray.types b/tests/baselines/reference/aliasUsageInArray.types index 218df8e10ed..ca8f0e61f2f 100644 --- a/tests/baselines/reference/aliasUsageInArray.types +++ b/tests/baselines/reference/aliasUsageInArray.types @@ -18,13 +18,13 @@ interface IHasVisualizationModel { var xs: IHasVisualizationModel[] = [moduleA]; >xs : IHasVisualizationModel[] >IHasVisualizationModel : IHasVisualizationModel ->[moduleA] : typeof moduleA[] +>[moduleA] : (typeof moduleA)[] >moduleA : typeof moduleA var xs2: typeof moduleA[] = [moduleA]; ->xs2 : typeof moduleA[] +>xs2 : (typeof moduleA)[] >moduleA : typeof moduleA ->[moduleA] : typeof moduleA[] +>[moduleA] : (typeof moduleA)[] >moduleA : typeof moduleA === tests/cases/compiler/aliasUsageInArray_backbone.ts === diff --git a/tests/baselines/reference/arrayOfFunctionTypes3.types b/tests/baselines/reference/arrayOfFunctionTypes3.types index 124542f5814..c7251ea45d2 100644 --- a/tests/baselines/reference/arrayOfFunctionTypes3.types +++ b/tests/baselines/reference/arrayOfFunctionTypes3.types @@ -22,8 +22,8 @@ class C { >foo : string } var y = [C, C]; ->y : typeof C[] ->[C, C] : typeof C[] +>y : (typeof C)[] +>[C, C] : (typeof C)[] >C : typeof C >C : typeof C @@ -31,7 +31,7 @@ var r3 = new y[0](); >r3 : C >new y[0]() : C >y[0] : typeof C ->y : typeof C[] +>y : (typeof C)[] >0 : 0 var a: { (x: number): number; (x: string): string; }; diff --git a/tests/baselines/reference/contextualThisTypeInJavascript.symbols b/tests/baselines/reference/contextualThisTypeInJavascript.symbols new file mode 100644 index 00000000000..c1339014a88 --- /dev/null +++ b/tests/baselines/reference/contextualThisTypeInJavascript.symbols @@ -0,0 +1,28 @@ +=== tests/cases/conformance/types/thisType/context.js === +const obj = { +>obj : Symbol(obj, Decl(context.js, 0, 5)) + + prop: 2, +>prop : Symbol(prop, Decl(context.js, 0, 13)) + + method() { +>method : Symbol(method, Decl(context.js, 1, 12)) + + this; +>this : Symbol(obj, Decl(context.js, 0, 11)) + + this.prop; +>this.prop : Symbol(prop, Decl(context.js, 0, 13)) +>this : Symbol(obj, Decl(context.js, 0, 11)) +>prop : Symbol(prop, Decl(context.js, 0, 13)) + + this.method; +>this.method : Symbol(method, Decl(context.js, 1, 12)) +>this : Symbol(obj, Decl(context.js, 0, 11)) +>method : Symbol(method, Decl(context.js, 1, 12)) + + this.unknown; // ok, obj has a string indexer +>this : Symbol(obj, Decl(context.js, 0, 11)) + } +} + diff --git a/tests/baselines/reference/contextualThisTypeInJavascript.types b/tests/baselines/reference/contextualThisTypeInJavascript.types new file mode 100644 index 00000000000..355b7295e6e --- /dev/null +++ b/tests/baselines/reference/contextualThisTypeInJavascript.types @@ -0,0 +1,32 @@ +=== tests/cases/conformance/types/thisType/context.js === +const obj = { +>obj : { [x: string]: any; prop: number; method(): void; } +>{ prop: 2, method() { this; this.prop; this.method; this.unknown; // ok, obj has a string indexer }} : { [x: string]: any; prop: number; method(): void; } + + prop: 2, +>prop : number +>2 : 2 + + method() { +>method : () => void + + this; +>this : { [x: string]: any; prop: number; method(): void; } + + this.prop; +>this.prop : number +>this : { [x: string]: any; prop: number; method(): void; } +>prop : number + + this.method; +>this.method : () => void +>this : { [x: string]: any; prop: number; method(): void; } +>method : () => void + + this.unknown; // ok, obj has a string indexer +>this.unknown : any +>this : { [x: string]: any; prop: number; method(): void; } +>unknown : any + } +} + diff --git a/tests/baselines/reference/declarationEmitIndexTypeArray.types b/tests/baselines/reference/declarationEmitIndexTypeArray.types index 67f8905639e..549c1efe5f3 100644 --- a/tests/baselines/reference/declarationEmitIndexTypeArray.types +++ b/tests/baselines/reference/declarationEmitIndexTypeArray.types @@ -1,16 +1,16 @@ === tests/cases/compiler/declarationEmitIndexTypeArray.ts === function doSomethingWithKeys(...keys: (keyof T)[]) { } ->doSomethingWithKeys : (...keys: keyof T[]) => void +>doSomethingWithKeys : (...keys: (keyof T)[]) => void >T : T ->keys : keyof T[] +>keys : (keyof T)[] >T : T const utilityFunctions = { ->utilityFunctions : { doSomethingWithKeys: (...keys: keyof T[]) => void; } ->{ doSomethingWithKeys} : { doSomethingWithKeys: (...keys: keyof T[]) => void; } +>utilityFunctions : { doSomethingWithKeys: (...keys: (keyof T)[]) => void; } +>{ doSomethingWithKeys} : { doSomethingWithKeys: (...keys: (keyof T)[]) => void; } doSomethingWithKeys ->doSomethingWithKeys : (...keys: keyof T[]) => void +>doSomethingWithKeys : (...keys: (keyof T)[]) => void }; diff --git a/tests/baselines/reference/destructuringTypeGuardFlow.js b/tests/baselines/reference/destructuringTypeGuardFlow.js new file mode 100644 index 00000000000..15997de7b44 --- /dev/null +++ b/tests/baselines/reference/destructuringTypeGuardFlow.js @@ -0,0 +1,57 @@ +//// [destructuringTypeGuardFlow.ts] +type foo = { + bar: number | null; + baz: string; + nested: { + a: number; + b: string | null; + } +}; + +const aFoo: foo = { bar: 3, baz: "b", nested: { a: 1, b: "y" } }; + +if (aFoo.bar && aFoo.nested.b) { + const { bar, baz, nested: {a, b: text} } = aFoo; + const right: number = aFoo.bar; + const wrong: number = bar; + const another: string = baz; + const aAgain: number = a; + const bAgain: string = text; +} + +type bar = { + elem1: number | null; + elem2: foo | null; +}; + +const bBar = { elem1: 7, elem2: aFoo }; + +if (bBar.elem2 && bBar.elem2.bar && bBar.elem2.nested.b) { + const { bar, baz, nested: {a, b: text} } = bBar.elem2; + const right: number = bBar.elem2.bar; + const wrong: number = bar; + const another: string = baz; + const aAgain: number = a; + const bAgain: string = text; +} + + +//// [destructuringTypeGuardFlow.js] +var aFoo = { bar: 3, baz: "b", nested: { a: 1, b: "y" } }; +if (aFoo.bar && aFoo.nested.b) { + var bar = aFoo.bar, baz = aFoo.baz, _a = aFoo.nested, a = _a.a, text = _a.b; + var right = aFoo.bar; + var wrong = bar; + var another = baz; + var aAgain = a; + var bAgain = text; +} +var bBar = { elem1: 7, elem2: aFoo }; +if (bBar.elem2 && bBar.elem2.bar && bBar.elem2.nested.b) { + var _b = bBar.elem2, bar = _b.bar, baz = _b.baz, _c = _b.nested, a = _c.a, text = _c.b; + var right = bBar.elem2.bar; + var wrong = bar; + var another = baz; + var aAgain = a; + var bAgain = text; +} diff --git a/tests/baselines/reference/destructuringTypeGuardFlow.symbols b/tests/baselines/reference/destructuringTypeGuardFlow.symbols new file mode 100644 index 00000000000..4c601acb0ae --- /dev/null +++ b/tests/baselines/reference/destructuringTypeGuardFlow.symbols @@ -0,0 +1,143 @@ +=== tests/cases/compiler/destructuringTypeGuardFlow.ts === +type foo = { +>foo : Symbol(foo, Decl(destructuringTypeGuardFlow.ts, 0, 0)) + + bar: number | null; +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 0, 12)) + + baz: string; +>baz : Symbol(baz, Decl(destructuringTypeGuardFlow.ts, 1, 21)) + + nested: { +>nested : Symbol(nested, Decl(destructuringTypeGuardFlow.ts, 2, 14)) + + a: number; +>a : Symbol(a, Decl(destructuringTypeGuardFlow.ts, 3, 11)) + + b: string | null; +>b : Symbol(b, Decl(destructuringTypeGuardFlow.ts, 4, 14)) + } +}; + +const aFoo: foo = { bar: 3, baz: "b", nested: { a: 1, b: "y" } }; +>aFoo : Symbol(aFoo, Decl(destructuringTypeGuardFlow.ts, 9, 5)) +>foo : Symbol(foo, Decl(destructuringTypeGuardFlow.ts, 0, 0)) +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 9, 19)) +>baz : Symbol(baz, Decl(destructuringTypeGuardFlow.ts, 9, 27)) +>nested : Symbol(nested, Decl(destructuringTypeGuardFlow.ts, 9, 37)) +>a : Symbol(a, Decl(destructuringTypeGuardFlow.ts, 9, 47)) +>b : Symbol(b, Decl(destructuringTypeGuardFlow.ts, 9, 53)) + +if (aFoo.bar && aFoo.nested.b) { +>aFoo.bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 0, 12)) +>aFoo : Symbol(aFoo, Decl(destructuringTypeGuardFlow.ts, 9, 5)) +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 0, 12)) +>aFoo.nested.b : Symbol(b, Decl(destructuringTypeGuardFlow.ts, 4, 14)) +>aFoo.nested : Symbol(nested, Decl(destructuringTypeGuardFlow.ts, 2, 14)) +>aFoo : Symbol(aFoo, Decl(destructuringTypeGuardFlow.ts, 9, 5)) +>nested : Symbol(nested, Decl(destructuringTypeGuardFlow.ts, 2, 14)) +>b : Symbol(b, Decl(destructuringTypeGuardFlow.ts, 4, 14)) + + const { bar, baz, nested: {a, b: text} } = aFoo; +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 12, 9)) +>baz : Symbol(baz, Decl(destructuringTypeGuardFlow.ts, 12, 14)) +>nested : Symbol(nested, Decl(destructuringTypeGuardFlow.ts, 2, 14)) +>a : Symbol(a, Decl(destructuringTypeGuardFlow.ts, 12, 29)) +>b : Symbol(b, Decl(destructuringTypeGuardFlow.ts, 4, 14)) +>text : Symbol(text, Decl(destructuringTypeGuardFlow.ts, 12, 31)) +>aFoo : Symbol(aFoo, Decl(destructuringTypeGuardFlow.ts, 9, 5)) + + const right: number = aFoo.bar; +>right : Symbol(right, Decl(destructuringTypeGuardFlow.ts, 13, 7)) +>aFoo.bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 0, 12)) +>aFoo : Symbol(aFoo, Decl(destructuringTypeGuardFlow.ts, 9, 5)) +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 0, 12)) + + const wrong: number = bar; +>wrong : Symbol(wrong, Decl(destructuringTypeGuardFlow.ts, 14, 7)) +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 12, 9)) + + const another: string = baz; +>another : Symbol(another, Decl(destructuringTypeGuardFlow.ts, 15, 7)) +>baz : Symbol(baz, Decl(destructuringTypeGuardFlow.ts, 12, 14)) + + const aAgain: number = a; +>aAgain : Symbol(aAgain, Decl(destructuringTypeGuardFlow.ts, 16, 7)) +>a : Symbol(a, Decl(destructuringTypeGuardFlow.ts, 12, 29)) + + const bAgain: string = text; +>bAgain : Symbol(bAgain, Decl(destructuringTypeGuardFlow.ts, 17, 7)) +>text : Symbol(text, Decl(destructuringTypeGuardFlow.ts, 12, 31)) +} + +type bar = { +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 18, 1)) + + elem1: number | null; +>elem1 : Symbol(elem1, Decl(destructuringTypeGuardFlow.ts, 20, 12)) + + elem2: foo | null; +>elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 21, 23)) +>foo : Symbol(foo, Decl(destructuringTypeGuardFlow.ts, 0, 0)) + +}; + +const bBar = { elem1: 7, elem2: aFoo }; +>bBar : Symbol(bBar, Decl(destructuringTypeGuardFlow.ts, 25, 5)) +>elem1 : Symbol(elem1, Decl(destructuringTypeGuardFlow.ts, 25, 14)) +>elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>aFoo : Symbol(aFoo, Decl(destructuringTypeGuardFlow.ts, 9, 5)) + +if (bBar.elem2 && bBar.elem2.bar && bBar.elem2.nested.b) { +>bBar.elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>bBar : Symbol(bBar, Decl(destructuringTypeGuardFlow.ts, 25, 5)) +>elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>bBar.elem2.bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 0, 12)) +>bBar.elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>bBar : Symbol(bBar, Decl(destructuringTypeGuardFlow.ts, 25, 5)) +>elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 0, 12)) +>bBar.elem2.nested.b : Symbol(b, Decl(destructuringTypeGuardFlow.ts, 4, 14)) +>bBar.elem2.nested : Symbol(nested, Decl(destructuringTypeGuardFlow.ts, 2, 14)) +>bBar.elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>bBar : Symbol(bBar, Decl(destructuringTypeGuardFlow.ts, 25, 5)) +>elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>nested : Symbol(nested, Decl(destructuringTypeGuardFlow.ts, 2, 14)) +>b : Symbol(b, Decl(destructuringTypeGuardFlow.ts, 4, 14)) + + const { bar, baz, nested: {a, b: text} } = bBar.elem2; +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 28, 9)) +>baz : Symbol(baz, Decl(destructuringTypeGuardFlow.ts, 28, 14)) +>nested : Symbol(nested, Decl(destructuringTypeGuardFlow.ts, 2, 14)) +>a : Symbol(a, Decl(destructuringTypeGuardFlow.ts, 28, 29)) +>b : Symbol(b, Decl(destructuringTypeGuardFlow.ts, 4, 14)) +>text : Symbol(text, Decl(destructuringTypeGuardFlow.ts, 28, 31)) +>bBar.elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>bBar : Symbol(bBar, Decl(destructuringTypeGuardFlow.ts, 25, 5)) +>elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) + + const right: number = bBar.elem2.bar; +>right : Symbol(right, Decl(destructuringTypeGuardFlow.ts, 29, 7)) +>bBar.elem2.bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 0, 12)) +>bBar.elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>bBar : Symbol(bBar, Decl(destructuringTypeGuardFlow.ts, 25, 5)) +>elem2 : Symbol(elem2, Decl(destructuringTypeGuardFlow.ts, 25, 24)) +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 0, 12)) + + const wrong: number = bar; +>wrong : Symbol(wrong, Decl(destructuringTypeGuardFlow.ts, 30, 7)) +>bar : Symbol(bar, Decl(destructuringTypeGuardFlow.ts, 28, 9)) + + const another: string = baz; +>another : Symbol(another, Decl(destructuringTypeGuardFlow.ts, 31, 7)) +>baz : Symbol(baz, Decl(destructuringTypeGuardFlow.ts, 28, 14)) + + const aAgain: number = a; +>aAgain : Symbol(aAgain, Decl(destructuringTypeGuardFlow.ts, 32, 7)) +>a : Symbol(a, Decl(destructuringTypeGuardFlow.ts, 28, 29)) + + const bAgain: string = text; +>bAgain : Symbol(bAgain, Decl(destructuringTypeGuardFlow.ts, 33, 7)) +>text : Symbol(text, Decl(destructuringTypeGuardFlow.ts, 28, 31)) +} + diff --git a/tests/baselines/reference/destructuringTypeGuardFlow.types b/tests/baselines/reference/destructuringTypeGuardFlow.types new file mode 100644 index 00000000000..e04dfa645c9 --- /dev/null +++ b/tests/baselines/reference/destructuringTypeGuardFlow.types @@ -0,0 +1,158 @@ +=== tests/cases/compiler/destructuringTypeGuardFlow.ts === +type foo = { +>foo : foo + + bar: number | null; +>bar : number | null +>null : null + + baz: string; +>baz : string + + nested: { +>nested : { a: number; b: string | null; } + + a: number; +>a : number + + b: string | null; +>b : string | null +>null : null + } +}; + +const aFoo: foo = { bar: 3, baz: "b", nested: { a: 1, b: "y" } }; +>aFoo : foo +>foo : foo +>{ bar: 3, baz: "b", nested: { a: 1, b: "y" } } : { bar: number; baz: string; nested: { a: number; b: string; }; } +>bar : number +>3 : 3 +>baz : string +>"b" : "b" +>nested : { a: number; b: string; } +>{ a: 1, b: "y" } : { a: number; b: string; } +>a : number +>1 : 1 +>b : string +>"y" : "y" + +if (aFoo.bar && aFoo.nested.b) { +>aFoo.bar && aFoo.nested.b : string | 0 | null +>aFoo.bar : number | null +>aFoo : foo +>bar : number | null +>aFoo.nested.b : string | null +>aFoo.nested : { a: number; b: string | null; } +>aFoo : foo +>nested : { a: number; b: string | null; } +>b : string | null + + const { bar, baz, nested: {a, b: text} } = aFoo; +>bar : number +>baz : string +>nested : any +>a : number +>b : any +>text : string +>aFoo : foo + + const right: number = aFoo.bar; +>right : number +>aFoo.bar : number +>aFoo : foo +>bar : number + + const wrong: number = bar; +>wrong : number +>bar : number + + const another: string = baz; +>another : string +>baz : string + + const aAgain: number = a; +>aAgain : number +>a : number + + const bAgain: string = text; +>bAgain : string +>text : string +} + +type bar = { +>bar : bar + + elem1: number | null; +>elem1 : number | null +>null : null + + elem2: foo | null; +>elem2 : foo | null +>foo : foo +>null : null + +}; + +const bBar = { elem1: 7, elem2: aFoo }; +>bBar : { elem1: number; elem2: foo; } +>{ elem1: 7, elem2: aFoo } : { elem1: number; elem2: foo; } +>elem1 : number +>7 : 7 +>elem2 : foo +>aFoo : foo + +if (bBar.elem2 && bBar.elem2.bar && bBar.elem2.nested.b) { +>bBar.elem2 && bBar.elem2.bar && bBar.elem2.nested.b : string | 0 | null +>bBar.elem2 && bBar.elem2.bar : number | null +>bBar.elem2 : foo +>bBar : { elem1: number; elem2: foo; } +>elem2 : foo +>bBar.elem2.bar : number | null +>bBar.elem2 : foo +>bBar : { elem1: number; elem2: foo; } +>elem2 : foo +>bar : number | null +>bBar.elem2.nested.b : string | null +>bBar.elem2.nested : { a: number; b: string | null; } +>bBar.elem2 : foo +>bBar : { elem1: number; elem2: foo; } +>elem2 : foo +>nested : { a: number; b: string | null; } +>b : string | null + + const { bar, baz, nested: {a, b: text} } = bBar.elem2; +>bar : number +>baz : string +>nested : any +>a : number +>b : any +>text : string +>bBar.elem2 : foo +>bBar : { elem1: number; elem2: foo; } +>elem2 : foo + + const right: number = bBar.elem2.bar; +>right : number +>bBar.elem2.bar : number +>bBar.elem2 : foo +>bBar : { elem1: number; elem2: foo; } +>elem2 : foo +>bar : number + + const wrong: number = bar; +>wrong : number +>bar : number + + const another: string = baz; +>another : string +>baz : string + + const aAgain: number = a; +>aAgain : number +>a : number + + const bAgain: string = text; +>bAgain : string +>text : string +} + diff --git a/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration.errors.txt b/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration.errors.txt new file mode 100644 index 00000000000..a2e0dd12d31 --- /dev/null +++ b/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration.errors.txt @@ -0,0 +1,13 @@ +/a.js(4,9): error TS2322: Type '0' is not assignable to type '() => void'. + + +==== /a.js (1 errors) ==== + const o = { + a() { + // Should not be treated as a declaration. Should be an error. + this.a = 0; + ~~~~~~ +!!! error TS2322: Type '0' is not assignable to type '() => void'. + } + }; + \ No newline at end of file diff --git a/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration.txt b/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration.txt new file mode 100644 index 00000000000..a774e45ff66 --- /dev/null +++ b/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration.txt @@ -0,0 +1,16 @@ +/a.js(4,9): error TS2322: Type '0' is not assignable to type '() => void'. + + +==== /a.js (1 errors) ==== + const o = { + a() { + // Should not be treated as a declaration. Should be an error. + this.a = 0; + ~~~~~~ +!!! error TS2322: Type '0' is not assignable to type '() => void'. + }, + b() { + this.b = () => {}; // OK + } + }; + \ No newline at end of file diff --git a/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration_nonError.symbols b/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration_nonError.symbols new file mode 100644 index 00000000000..af84dd7d5de --- /dev/null +++ b/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration_nonError.symbols @@ -0,0 +1,15 @@ +=== /a.js === +const o = { +>o : Symbol(o, Decl(a.js, 0, 5)) + + a() { +>a : Symbol(a, Decl(a.js, 0, 11)) + + // Should not be treated as a declaration. + this.a = () => {}; +>this.a : Symbol(a, Decl(a.js, 0, 11)) +>this : Symbol(o, Decl(a.js, 0, 9)) +>a : Symbol(a, Decl(a.js, 0, 11)) + } +}; + diff --git a/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration_nonError.types b/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration_nonError.types new file mode 100644 index 00000000000..8fed2b36797 --- /dev/null +++ b/tests/baselines/reference/jsPropertyAssignedAfterMethodDeclaration_nonError.types @@ -0,0 +1,18 @@ +=== /a.js === +const o = { +>o : { [x: string]: any; a(): void; } +>{ a() { // Should not be treated as a declaration. this.a = () => {}; }} : { [x: string]: any; a(): void; } + + a() { +>a : () => void + + // Should not be treated as a declaration. + this.a = () => {}; +>this.a = () => {} : () => void +>this.a : () => void +>this : { [x: string]: any; a(): void; } +>a : () => void +>() => {} : () => void + } +}; + diff --git a/tests/baselines/reference/jsdocIndexSignature.symbols b/tests/baselines/reference/jsdocIndexSignature.symbols new file mode 100644 index 00000000000..8814fc18b6f --- /dev/null +++ b/tests/baselines/reference/jsdocIndexSignature.symbols @@ -0,0 +1,13 @@ +=== tests/cases/conformance/jsdoc/indices.js === +/** @type {Object.} */ +var o1; +>o1 : Symbol(o1, Decl(indices.js, 1, 3)) + +/** @type {Object.} */ +var o2; +>o2 : Symbol(o2, Decl(indices.js, 3, 3)) + +/** @type {Object.} */ +var o3; +>o3 : Symbol(o3, Decl(indices.js, 5, 3)) + diff --git a/tests/baselines/reference/jsdocIndexSignature.types b/tests/baselines/reference/jsdocIndexSignature.types new file mode 100644 index 00000000000..4c1feaa2721 --- /dev/null +++ b/tests/baselines/reference/jsdocIndexSignature.types @@ -0,0 +1,13 @@ +=== tests/cases/conformance/jsdoc/indices.js === +/** @type {Object.} */ +var o1; +>o1 : { [x: string]: number; } + +/** @type {Object.} */ +var o2; +>o2 : { [x: number]: boolean; } + +/** @type {Object.} */ +var o3; +>o3 : any + diff --git a/tests/baselines/reference/jsdocTypeTagCast.errors.txt b/tests/baselines/reference/jsdocTypeTagCast.errors.txt new file mode 100644 index 00000000000..f1f53ec1ecb --- /dev/null +++ b/tests/baselines/reference/jsdocTypeTagCast.errors.txt @@ -0,0 +1,129 @@ +tests/cases/conformance/jsdoc/b.js(4,13): error TS2352: Type 'number' cannot be converted to type 'string'. +tests/cases/conformance/jsdoc/b.js(45,16): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. + Property 'p' is missing in type 'SomeOther'. +tests/cases/conformance/jsdoc/b.js(49,19): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. + Property 'x' is missing in type 'SomeOther'. +tests/cases/conformance/jsdoc/b.js(51,17): error TS2352: Type 'SomeDerived' cannot be converted to type 'SomeOther'. + Property 'q' is missing in type 'SomeDerived'. +tests/cases/conformance/jsdoc/b.js(52,17): error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. + Property 'q' is missing in type 'SomeBase'. +tests/cases/conformance/jsdoc/b.js(58,1): error TS2322: Type '{ p: string | number | undefined; }' is not assignable to type 'SomeBase'. + Types of property 'p' are incompatible. + Type 'string | number | undefined' is not assignable to type 'number'. + Type 'undefined' is not assignable to type 'number'. +tests/cases/conformance/jsdoc/b.js(66,8): error TS2352: Type 'boolean' cannot be converted to type 'string | number'. +tests/cases/conformance/jsdoc/b.js(66,15): error TS2304: Cannot find name 'numOrStr'. +tests/cases/conformance/jsdoc/b.js(66,24): error TS1005: '}' expected. +tests/cases/conformance/jsdoc/b.js(66,38): error TS2454: Variable 'numOrStr' is used before being assigned. +tests/cases/conformance/jsdoc/b.js(67,2): error TS2322: Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/jsdoc/b.js(67,8): error TS2454: Variable 'numOrStr' is used before being assigned. + + +==== tests/cases/conformance/jsdoc/a.ts (0 errors) ==== + var W: string; + +==== tests/cases/conformance/jsdoc/b.js (12 errors) ==== + // @ts-check + var W = /** @type {string} */(/** @type {*} */ (4)); + + var W = /** @type {string} */(4); // Error + ~~~~~~~~~~~~~~ +!!! error TS2352: Type 'number' cannot be converted to type 'string'. + + /** @type {*} */ + var a; + + /** @type {string} */ + var s; + + var a = /** @type {*} */("" + 4); + var s = "" + /** @type {*} */(4); + + class SomeBase { + constructor() { + this.p = 42; + } + } + class SomeDerived extends SomeBase { + constructor() { + super(); + this.x = 42; + } + } + class SomeOther { + constructor() { + this.q = 42; + } + } + + function SomeFakeClass() { + /** @type {string|number} */ + this.p = "bar"; + } + + // Type assertion should check for assignability in either direction + var someBase = new SomeBase(); + var someDerived = new SomeDerived(); + var someOther = new SomeOther(); + var someFakeClass = new SomeFakeClass(); + + someBase = /** @type {SomeBase} */(someDerived); + someBase = /** @type {SomeBase} */(someBase); + someBase = /** @type {SomeBase} */(someOther); // Error + ~~~~~~~~~~~~~~~~ +!!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'. +!!! error TS2352: Property 'p' is missing in type 'SomeOther'. + + someDerived = /** @type {SomeDerived} */(someDerived); + someDerived = /** @type {SomeDerived} */(someBase); + someDerived = /** @type {SomeDerived} */(someOther); // Error + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'. +!!! error TS2352: Property 'x' is missing in type 'SomeOther'. + + someOther = /** @type {SomeOther} */(someDerived); // Error + ~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type 'SomeDerived' cannot be converted to type 'SomeOther'. +!!! error TS2352: Property 'q' is missing in type 'SomeDerived'. + someOther = /** @type {SomeOther} */(someBase); // Error + ~~~~~~~~~~~~~~~~~ +!!! error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'. +!!! error TS2352: Property 'q' is missing in type 'SomeBase'. + someOther = /** @type {SomeOther} */(someOther); + + someFakeClass = someBase; + someFakeClass = someDerived; + + someBase = someFakeClass; // Error + ~~~~~~~~ +!!! error TS2322: Type '{ p: string | number | undefined; }' is not assignable to type 'SomeBase'. +!!! error TS2322: Types of property 'p' are incompatible. +!!! error TS2322: Type 'string | number | undefined' is not assignable to type 'number'. +!!! error TS2322: Type 'undefined' is not assignable to type 'number'. + someBase = /** @type {SomeBase} */(someFakeClass); + + // Type assertion cannot be a type-predicate type + /** @type {number | string} */ + var numOrStr; + /** @type {string} */ + var str; + if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error + ~~~~~~~~~~~~~~~ +!!! error TS2352: Type 'boolean' cannot be converted to type 'string | number'. + ~~~~~~~~ +!!! error TS2304: Cannot find name 'numOrStr'. + ~~ +!!! error TS1005: '}' expected. + ~~~~~~~~ +!!! error TS2454: Variable 'numOrStr' is used before being assigned. + str = numOrStr; // Error, no narrowing occurred + ~~~ +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + ~~~~~~~~ +!!! error TS2454: Variable 'numOrStr' is used before being assigned. + } + + + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocTypeTagCast.js b/tests/baselines/reference/jsdocTypeTagCast.js new file mode 100644 index 00000000000..c2df50cd6dd --- /dev/null +++ b/tests/baselines/reference/jsdocTypeTagCast.js @@ -0,0 +1,151 @@ +//// [tests/cases/conformance/jsdoc/jsdocTypeTagCast.ts] //// + +//// [a.ts] +var W: string; + +//// [b.js] +// @ts-check +var W = /** @type {string} */(/** @type {*} */ (4)); + +var W = /** @type {string} */(4); // Error + +/** @type {*} */ +var a; + +/** @type {string} */ +var s; + +var a = /** @type {*} */("" + 4); +var s = "" + /** @type {*} */(4); + +class SomeBase { + constructor() { + this.p = 42; + } +} +class SomeDerived extends SomeBase { + constructor() { + super(); + this.x = 42; + } +} +class SomeOther { + constructor() { + this.q = 42; + } +} + +function SomeFakeClass() { + /** @type {string|number} */ + this.p = "bar"; +} + +// Type assertion should check for assignability in either direction +var someBase = new SomeBase(); +var someDerived = new SomeDerived(); +var someOther = new SomeOther(); +var someFakeClass = new SomeFakeClass(); + +someBase = /** @type {SomeBase} */(someDerived); +someBase = /** @type {SomeBase} */(someBase); +someBase = /** @type {SomeBase} */(someOther); // Error + +someDerived = /** @type {SomeDerived} */(someDerived); +someDerived = /** @type {SomeDerived} */(someBase); +someDerived = /** @type {SomeDerived} */(someOther); // Error + +someOther = /** @type {SomeOther} */(someDerived); // Error +someOther = /** @type {SomeOther} */(someBase); // Error +someOther = /** @type {SomeOther} */(someOther); + +someFakeClass = someBase; +someFakeClass = someDerived; + +someBase = someFakeClass; // Error +someBase = /** @type {SomeBase} */(someFakeClass); + +// Type assertion cannot be a type-predicate type +/** @type {number | string} */ +var numOrStr; +/** @type {string} */ +var str; +if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error + str = numOrStr; // Error, no narrowing occurred +} + + + + +//// [a.js] +var W; +//// [b.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +// @ts-check +var W = ((4)); +var W = (4); // Error +/** @type {*} */ +var a; +/** @type {string} */ +var s; +var a = ("" + 4); +var s = "" + (4); +var SomeBase = (function () { + function SomeBase() { + this.p = 42; + } + return SomeBase; +}()); +var SomeDerived = (function (_super) { + __extends(SomeDerived, _super); + function SomeDerived() { + var _this = _super.call(this) || this; + _this.x = 42; + return _this; + } + return SomeDerived; +}(SomeBase)); +var SomeOther = (function () { + function SomeOther() { + this.q = 42; + } + return SomeOther; +}()); +function SomeFakeClass() { + /** @type {string|number} */ + this.p = "bar"; +} +// Type assertion should check for assignability in either direction +var someBase = new SomeBase(); +var someDerived = new SomeDerived(); +var someOther = new SomeOther(); +var someFakeClass = new SomeFakeClass(); +someBase = (someDerived); +someBase = (someBase); +someBase = (someOther); // Error +someDerived = (someDerived); +someDerived = (someBase); +someDerived = (someOther); // Error +someOther = (someDerived); // Error +someOther = (someBase); // Error +someOther = (someOther); +someFakeClass = someBase; +someFakeClass = someDerived; +someBase = someFakeClass; // Error +someBase = (someFakeClass); +// Type assertion cannot be a type-predicate type +/** @type {number | string} */ +var numOrStr; +/** @type {string} */ +var str; +if ((numOrStr === undefined)) { + str = numOrStr; // Error, no narrowing occurred +} diff --git a/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt b/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt index c19a13209c9..b578d002e05 100644 --- a/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt +++ b/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/keyofIsLiteralContexualType.ts(5,9): error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type 'keyof T[]'. +tests/cases/compiler/keyofIsLiteralContexualType.ts(5,9): error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type '(keyof T)[]'. Type '"a" | "b" | "c"' is not assignable to type 'keyof T'. Type '"c"' is not assignable to type 'keyof T'. Type '"c"' is not assignable to type '"a" | "b"'. @@ -12,7 +12,7 @@ tests/cases/compiler/keyofIsLiteralContexualType.ts(13,11): error TS2339: Proper let a: (keyof T)[] = ["a", "b"]; let b: (keyof T)[] = ["a", "b", "c"]; ~ -!!! error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type 'keyof T[]'. +!!! error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type '(keyof T)[]'. !!! error TS2322: Type '"a" | "b" | "c"' is not assignable to type 'keyof T'. !!! error TS2322: Type '"c"' is not assignable to type 'keyof T'. !!! error TS2322: Type '"c"' is not assignable to type '"a" | "b"'. diff --git a/tests/baselines/reference/multipleDeclarations.symbols b/tests/baselines/reference/multipleDeclarations.symbols index 4fc8f8a5f28..3133d77056b 100644 --- a/tests/baselines/reference/multipleDeclarations.symbols +++ b/tests/baselines/reference/multipleDeclarations.symbols @@ -66,45 +66,47 @@ class Y { >Y : Symbol(Y, Decl(input.js, 19, 10)) mistake() { ->mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) +>mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 29, 1)) } m() { ->m : Symbol(Y.m, Decl(input.js, 22, 5), Decl(input.js, 25, 19)) +>m : Symbol(Y.m, Decl(input.js, 22, 5)) } constructor() { this.m = this.m.bind(this); ->this.m : Symbol(Y.m, Decl(input.js, 22, 5), Decl(input.js, 25, 19)) +>this.m : Symbol(Y.m, Decl(input.js, 22, 5)) >this : Symbol(Y, Decl(input.js, 19, 10)) ->m : Symbol(Y.m, Decl(input.js, 22, 5), Decl(input.js, 25, 19)) ->this.m : Symbol(Y.m, Decl(input.js, 22, 5), Decl(input.js, 25, 19)) +>m : Symbol(Y.m, Decl(input.js, 22, 5)) +>this.m.bind : Symbol(Function.bind, Decl(lib.d.ts, --, --)) +>this.m : Symbol(Y.m, Decl(input.js, 22, 5)) >this : Symbol(Y, Decl(input.js, 19, 10)) ->m : Symbol(Y.m, Decl(input.js, 22, 5), Decl(input.js, 25, 19)) +>m : Symbol(Y.m, Decl(input.js, 22, 5)) +>bind : Symbol(Function.bind, Decl(lib.d.ts, --, --)) >this : Symbol(Y, Decl(input.js, 19, 10)) this.mistake = 'even more nonsense'; ->this.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) +>this.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 29, 1)) >this : Symbol(Y, Decl(input.js, 19, 10)) ->mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) +>mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 29, 1)) } } Y.prototype.mistake = true; ->Y.prototype.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) ->Y.prototype : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) +>Y.prototype.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 29, 1)) +>Y.prototype : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 29, 1)) >Y : Symbol(Y, Decl(input.js, 19, 10)) >prototype : Symbol(Y.prototype) ->mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) +>mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 29, 1)) let y = new Y(); >y : Symbol(y, Decl(input.js, 31, 3)) >Y : Symbol(Y, Decl(input.js, 19, 10)) y.m(); ->y.m : Symbol(Y.m, Decl(input.js, 22, 5), Decl(input.js, 25, 19)) +>y.m : Symbol(Y.m, Decl(input.js, 22, 5)) >y : Symbol(y, Decl(input.js, 31, 3)) ->m : Symbol(Y.m, Decl(input.js, 22, 5), Decl(input.js, 25, 19)) +>m : Symbol(Y.m, Decl(input.js, 22, 5)) y.mistake(); ->y.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) +>y.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 29, 1)) >y : Symbol(y, Decl(input.js, 31, 3)) ->mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) +>mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 29, 1)) diff --git a/tests/baselines/reference/multipleDeclarations.types b/tests/baselines/reference/multipleDeclarations.types index b82cdbe05ed..39aa8035b26 100644 --- a/tests/baselines/reference/multipleDeclarations.types +++ b/tests/baselines/reference/multipleDeclarations.types @@ -87,20 +87,20 @@ class Y { >mistake : any } m() { ->m : any +>m : () => void } constructor() { this.m = this.m.bind(this); >this.m = this.m.bind(this) : any ->this.m : any +>this.m : () => void >this : this ->m : any +>m : () => void >this.m.bind(this) : any ->this.m.bind : any ->this.m : any +>this.m.bind : (this: Function, thisArg: any, ...argArray: any[]) => any +>this.m : () => void >this : this ->m : any ->bind : any +>m : () => void +>bind : (this: Function, thisArg: any, ...argArray: any[]) => any >this : this this.mistake = 'even more nonsense'; @@ -126,10 +126,10 @@ let y = new Y(); >Y : typeof Y y.m(); ->y.m() : any ->y.m : any +>y.m() : void +>y.m : () => void >y : Y ->m : any +>m : () => void y.mistake(); >y.mistake() : any diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 63442a93b6b..46455687af2 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -62,9 +62,21 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(123,20 tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(128,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(132,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(136,39): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(152,68): error TS2344: Type 'T | "d"' does not satisfy the constraint 'Keys'. + Type '"d"' is not assignable to type 'Keys'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(159,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'. + Types of property ''a'' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(162,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(163,35): error TS2344: Type 'number' does not satisfy the constraint 'Foo'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(164,51): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(165,51): error TS2344: Type 'number' does not satisfy the constraint 'Foo'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,45): error TS2677: A type predicate's type must be assignable to its parameter's type. + Type 'NeedsFoo' is not assignable to type 'number'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,54): error TS2344: Type 'number' does not satisfy the constraint 'Foo'. -==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (54 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (62 errors) ==== class A { ~ !!! error TS2300: Duplicate identifier 'A'. @@ -175,7 +187,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(136,39 // No type guard in if statement if (hasNoTypeGuard(a)) { - a.propB; + a.propB; ~~~~~ !!! error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'? } @@ -208,7 +220,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(136,39 return true; }; - // No matching signature + // No matching signature var assign3: (p1, p2) => p1 is A; assign3 = function(p1, p2, p3): p1 is A { ~~~~~~~ @@ -326,4 +338,47 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(136,39 var x: A; if (hasMissingParameter()) { x.propA; - } \ No newline at end of file + } + + // repro #17297 + + type Keys = 'a'|'b'|'c' + type KeySet = { [k in T]: true } + + // expected an error, since Keys doesn't have a 'd' + declare function hasKey(x: KeySet): x is KeySet; + ~~~~~ +!!! error TS2344: Type 'T | "d"' does not satisfy the constraint 'Keys'. +!!! error TS2344: Type '"d"' is not assignable to type 'Keys'. + + type Foo = { 'a': string; } + type Bar = { 'a': number; } + + interface NeedsFoo { + foo: T; + isFoo(): this is NeedsFoo; // should error + ~~~ +!!! error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'. +!!! error TS2344: Types of property ''a'' are incompatible. +!!! error TS2344: Type 'number' is not assignable to type 'string'. + }; + + declare var anError: NeedsFoo; // error, as expected + ~~~ +!!! error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'. + declare var alsoAnError: NeedsFoo; // also error, as expected + ~~~~~~ +!!! error TS2344: Type 'number' does not satisfy the constraint 'Foo'. + declare function newError1(x: any): x is NeedsFoo; // should error + ~~~ +!!! error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'. + declare function newError2(x: any): x is NeedsFoo; // should error + ~~~~~~ +!!! error TS2344: Type 'number' does not satisfy the constraint 'Foo'. + declare function newError3(x: number): x is NeedsFoo; // should error + ~~~~~~~~~~~~~~~~ +!!! error TS2677: A type predicate's type must be assignable to its parameter's type. +!!! error TS2677: Type 'NeedsFoo' is not assignable to type 'number'. + ~~~~~~ +!!! error TS2344: Type 'number' does not satisfy the constraint 'Foo'. + \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js index cc773ae11b1..12ffab852d8 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.js +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -67,7 +67,7 @@ if (funA(0, a)) { // No type guard in if statement if (hasNoTypeGuard(a)) { - a.propB; + a.propB; } // Type predicate type is not assignable @@ -86,7 +86,7 @@ assign2 = function(p1, p2): p2 is A { return true; }; -// No matching signature +// No matching signature var assign3: (p1, p2) => p1 is A; assign3 = function(p1, p2, p3): p1 is A { return true; @@ -142,7 +142,30 @@ function b7({a, b, c: {p1}}, p2, p3): p1 is A { var x: A; if (hasMissingParameter()) { x.propA; -} +} + +// repro #17297 + +type Keys = 'a'|'b'|'c' +type KeySet = { [k in T]: true } + +// expected an error, since Keys doesn't have a 'd' +declare function hasKey(x: KeySet): x is KeySet; + +type Foo = { 'a': string; } +type Bar = { 'a': number; } + +interface NeedsFoo { + foo: T; + isFoo(): this is NeedsFoo; // should error +}; + +declare var anError: NeedsFoo; // error, as expected +declare var alsoAnError: NeedsFoo; // also error, as expected +declare function newError1(x: any): x is NeedsFoo; // should error +declare function newError2(x: any): x is NeedsFoo; // should error +declare function newError3(x: number): x is NeedsFoo; // should error + //// [typeGuardFunctionErrors.js] var __extends = (this && this.__extends) || (function () { @@ -224,7 +247,7 @@ var assign2; assign2 = function (p1, p2) { return true; }; -// No matching signature +// No matching signature var assign3; assign3 = function (p1, p2, p3) { return true; @@ -290,3 +313,4 @@ var x; if (hasMissingParameter()) { x.propA; } +; diff --git a/tests/cases/compiler/destructuringTypeGuardFlow.ts b/tests/cases/compiler/destructuringTypeGuardFlow.ts new file mode 100644 index 00000000000..b0a0b18948d --- /dev/null +++ b/tests/cases/compiler/destructuringTypeGuardFlow.ts @@ -0,0 +1,36 @@ +// @strictNullChecks: true +type foo = { + bar: number | null; + baz: string; + nested: { + a: number; + b: string | null; + } +}; + +const aFoo: foo = { bar: 3, baz: "b", nested: { a: 1, b: "y" } }; + +if (aFoo.bar && aFoo.nested.b) { + const { bar, baz, nested: {a, b: text} } = aFoo; + const right: number = aFoo.bar; + const wrong: number = bar; + const another: string = baz; + const aAgain: number = a; + const bAgain: string = text; +} + +type bar = { + elem1: number | null; + elem2: foo | null; +}; + +const bBar = { elem1: 7, elem2: aFoo }; + +if (bBar.elem2 && bBar.elem2.bar && bBar.elem2.nested.b) { + const { bar, baz, nested: {a, b: text} } = bBar.elem2; + const right: number = bBar.elem2.bar; + const wrong: number = bar; + const another: string = baz; + const aAgain: number = a; + const bAgain: string = text; +} diff --git a/tests/cases/compiler/jsPropertyAssignedAfterMethodDeclaration.ts b/tests/cases/compiler/jsPropertyAssignedAfterMethodDeclaration.ts new file mode 100644 index 00000000000..62a92c692b8 --- /dev/null +++ b/tests/cases/compiler/jsPropertyAssignedAfterMethodDeclaration.ts @@ -0,0 +1,12 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @noImplicitThis: true + +// @Filename: /a.js +const o = { + a() { + // Should not be treated as a declaration. Should be an error. + this.a = 0; + } +}; diff --git a/tests/cases/compiler/jsPropertyAssignedAfterMethodDeclaration_nonError.ts b/tests/cases/compiler/jsPropertyAssignedAfterMethodDeclaration_nonError.ts new file mode 100644 index 00000000000..8e3c23db09a --- /dev/null +++ b/tests/cases/compiler/jsPropertyAssignedAfterMethodDeclaration_nonError.ts @@ -0,0 +1,12 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @noImplicitThis: true + +// @Filename: /a.js +const o = { + a() { + // Should not be treated as a declaration. + this.a = () => {}; + } +}; diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts index 688099280c5..eb61473c5cc 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts @@ -67,7 +67,7 @@ if (funA(0, a)) { // No type guard in if statement if (hasNoTypeGuard(a)) { - a.propB; + a.propB; } // Type predicate type is not assignable @@ -86,7 +86,7 @@ assign2 = function(p1, p2): p2 is A { return true; }; -// No matching signature +// No matching signature var assign3: (p1, p2) => p1 is A; assign3 = function(p1, p2, p3): p1 is A { return true; @@ -142,4 +142,26 @@ function b7({a, b, c: {p1}}, p2, p3): p1 is A { var x: A; if (hasMissingParameter()) { x.propA; -} \ No newline at end of file +} + +// repro #17297 + +type Keys = 'a'|'b'|'c' +type KeySet = { [k in T]: true } + +// expected an error, since Keys doesn't have a 'd' +declare function hasKey(x: KeySet): x is KeySet; + +type Foo = { 'a': string; } +type Bar = { 'a': number; } + +interface NeedsFoo { + foo: T; + isFoo(): this is NeedsFoo; // should error +}; + +declare var anError: NeedsFoo; // error, as expected +declare var alsoAnError: NeedsFoo; // also error, as expected +declare function newError1(x: any): x is NeedsFoo; // should error +declare function newError2(x: any): x is NeedsFoo; // should error +declare function newError3(x: number): x is NeedsFoo; // should error diff --git a/tests/cases/conformance/jsdoc/jsdocIndexSignature.ts b/tests/cases/conformance/jsdoc/jsdocIndexSignature.ts new file mode 100644 index 00000000000..fdf9e06e61e --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocIndexSignature.ts @@ -0,0 +1,10 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @Filename: indices.js +/** @type {Object.} */ +var o1; +/** @type {Object.} */ +var o2; +/** @type {Object.} */ +var o3; diff --git a/tests/cases/conformance/jsdoc/jsdocTypeTagCast.ts b/tests/cases/conformance/jsdoc/jsdocTypeTagCast.ts new file mode 100644 index 00000000000..60ca43b0533 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocTypeTagCast.ts @@ -0,0 +1,78 @@ +// @allowJS: true +// @suppressOutputPathCheck: true +// @strictNullChecks: true + +// @filename: a.ts +var W: string; + +// @filename: b.js +// @ts-check +var W = /** @type {string} */(/** @type {*} */ (4)); + +var W = /** @type {string} */(4); // Error + +/** @type {*} */ +var a; + +/** @type {string} */ +var s; + +var a = /** @type {*} */("" + 4); +var s = "" + /** @type {*} */(4); + +class SomeBase { + constructor() { + this.p = 42; + } +} +class SomeDerived extends SomeBase { + constructor() { + super(); + this.x = 42; + } +} +class SomeOther { + constructor() { + this.q = 42; + } +} + +function SomeFakeClass() { + /** @type {string|number} */ + this.p = "bar"; +} + +// Type assertion should check for assignability in either direction +var someBase = new SomeBase(); +var someDerived = new SomeDerived(); +var someOther = new SomeOther(); +var someFakeClass = new SomeFakeClass(); + +someBase = /** @type {SomeBase} */(someDerived); +someBase = /** @type {SomeBase} */(someBase); +someBase = /** @type {SomeBase} */(someOther); // Error + +someDerived = /** @type {SomeDerived} */(someDerived); +someDerived = /** @type {SomeDerived} */(someBase); +someDerived = /** @type {SomeDerived} */(someOther); // Error + +someOther = /** @type {SomeOther} */(someDerived); // Error +someOther = /** @type {SomeOther} */(someBase); // Error +someOther = /** @type {SomeOther} */(someOther); + +someFakeClass = someBase; +someFakeClass = someDerived; + +someBase = someFakeClass; // Error +someBase = /** @type {SomeBase} */(someFakeClass); + +// Type assertion cannot be a type-predicate type +/** @type {number | string} */ +var numOrStr; +/** @type {string} */ +var str; +if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error + str = numOrStr; // Error, no narrowing occurred +} + + diff --git a/tests/cases/conformance/types/thisType/contextualThisTypeInJavascript.ts b/tests/cases/conformance/types/thisType/contextualThisTypeInJavascript.ts new file mode 100644 index 00000000000..53e6c1bae7e --- /dev/null +++ b/tests/cases/conformance/types/thisType/contextualThisTypeInJavascript.ts @@ -0,0 +1,13 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @Filename: context.js +const obj = { + prop: 2, + method() { + this; + this.prop; + this.method; + this.unknown; // ok, obj has a string indexer + } +} diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax1.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax1.ts new file mode 100644 index 00000000000..93107ef669b --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax1.ts @@ -0,0 +1,4 @@ +/// +//// var x: [|?|] = 12; + +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax2.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax2.ts new file mode 100644 index 00000000000..333b108538f --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax2.ts @@ -0,0 +1,4 @@ +/// +//// var x: [|*|] = 12; + +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax3.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax3.ts new file mode 100644 index 00000000000..f3b02cb84f1 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax3.ts @@ -0,0 +1,4 @@ +/// +//// var x: [|......number[][]|] = 12; + +verify.rangeAfterCodeFix("number[][][][]"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax4.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax4.ts new file mode 100644 index 00000000000..e9522331d38 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax4.ts @@ -0,0 +1,4 @@ +/// +//// var x: [|Array.|] = 12; + +verify.rangeAfterCodeFix("number[]"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax5.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax5.ts new file mode 100644 index 00000000000..6f46f3082e1 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax5.ts @@ -0,0 +1,5 @@ +// @strict: true +/// +//// var x: [|?number|] = 12; + +verify.rangeAfterCodeFix("number | null", /*includeWhiteSpace*/ false, /*errorCode*/ 8020, 0); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax6.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax6.ts new file mode 100644 index 00000000000..8af9f09d99d --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax6.ts @@ -0,0 +1,5 @@ +// @strict: true +/// +//// var x: [|number?|] = 12; + +verify.rangeAfterCodeFix("number | null | undefined", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, 1); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax7.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax7.ts new file mode 100644 index 00000000000..c80d08b3bac --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax7.ts @@ -0,0 +1,4 @@ +/// +//// var x: [|!number|] = 12; + +verify.rangeAfterCodeFix("number"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax8.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax8.ts new file mode 100644 index 00000000000..0fa7ddf229c --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax8.ts @@ -0,0 +1,4 @@ +/// +//// var x: [|function(this: number, number): string|] = 12; + +verify.rangeAfterCodeFix("(this: number, arg1: number) => string"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax9.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax9.ts new file mode 100644 index 00000000000..061ded158ea --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax9.ts @@ -0,0 +1,4 @@ +/// +//// var x: [|function(new: number)|] = 12; + +verify.rangeAfterCodeFix("new () => number"); diff --git a/tests/cases/fourslash/quickInfoJsPropertyAssignedAfterMethodDeclaration.ts b/tests/cases/fourslash/quickInfoJsPropertyAssignedAfterMethodDeclaration.ts new file mode 100644 index 00000000000..a1d3ae2d9e6 --- /dev/null +++ b/tests/cases/fourslash/quickInfoJsPropertyAssignedAfterMethodDeclaration.ts @@ -0,0 +1,17 @@ +/// + +// See also `jsPropertyAssignedAfterMethodDeclaration.ts` + +// @noLib: true +// @allowJs: true +// @noImplicitThis: true + +// @Filename: /a.js +////const o = { +//// test/*1*/() { +//// this./*2*/test = 0; +//// } +////}; + +verify.quickInfoAt("1", "(method) test(): void"); +verify.quickInfoAt("2", "(method) test(): void"); diff --git a/tests/cases/fourslash/typeOperatorNodeBuilding.ts b/tests/cases/fourslash/typeOperatorNodeBuilding.ts new file mode 100644 index 00000000000..dea274c03b0 --- /dev/null +++ b/tests/cases/fourslash/typeOperatorNodeBuilding.ts @@ -0,0 +1,21 @@ +/// + +// @Filename: keyof.ts +//// function doSomethingWithKeys(...keys: (keyof T)[]) { } +//// +//// const /*1*/utilityFunctions = { +//// doSomethingWithKeys +//// }; + +// @Filename: typeof.ts +//// class Foo { static a: number; } +//// function doSomethingWithTypes(...statics: (typeof Foo)[]) {} +//// +//// const /*2*/utilityFunctions = { +//// doSomethingWithTypes +//// }; + +verify.quickInfos({ + 1: "const utilityFunctions: {\n doSomethingWithKeys: (...keys: (keyof T)[]) => void;\n}", + 2: "const utilityFunctions: {\n doSomethingWithTypes: (...statics: (typeof Foo)[]) => void;\n}" +});