Merge branch 'master' into use-type-param-constraints-for-computed-prop-types

This commit is contained in:
Nathan Shively-Sanders 2017-08-08 13:26:24 -07:00
commit e494d73b29
105 changed files with 2390 additions and 498 deletions

View file

@ -34,6 +34,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
switch (methodName) {
case "apply":
case "assert":
case "assertEqual":
case "call":
case "equal":
case "fail":
@ -69,7 +70,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
const ranges = ts.getTrailingCommentRanges(sourceFile.text, arg.pos) || ts.getLeadingCommentRanges(sourceFile.text, arg.pos);
if (ranges === undefined || ranges.length !== 1 || ranges[0].kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
ctx.addFailureAtNode(arg, "Tag boolean argument with parameter name");
ctx.addFailureAtNode(arg, "Tag argument with parameter name");
return;
}

View file

@ -0,0 +1,45 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, ctx => walk(ctx));
}
}
function walk(ctx: Lint.WalkContext<void>): void {
ts.forEachChild(ctx.sourceFile, function recur(node) {
if (ts.isCallExpression(node)) {
checkCall(node);
}
ts.forEachChild(node, recur);
});
function checkCall(node: ts.CallExpression) {
if (!isDebugAssert(node.expression) || node.arguments.length < 2) {
return;
}
const message = node.arguments[1];
if (!ts.isStringLiteral(message)) {
ctx.addFailureAtNode(message, "Second argument to 'Debug.assert' should be a string literal.");
}
if (node.arguments.length < 3) {
return;
}
const message2 = node.arguments[2];
if (!ts.isStringLiteral(message2) && !ts.isArrowFunction(message2)) {
ctx.addFailureAtNode(message, "Third argument to 'Debug.assert' should be a string literal or arrow function.");
}
}
function isDebugAssert(expr: ts.Node): boolean {
return ts.isPropertyAccessExpression(expr) && isName(expr.expression, "Debug") && isName(expr.name, "assert");
}
function isName(expr: ts.Node, text: string): boolean {
return ts.isIdentifier(expr) && expr.text === text;
}
}

View file

@ -1086,7 +1086,10 @@ namespace ts {
location = location.parent;
}
if (result && nameNotFoundMessage && noUnusedIdentifiers) {
// We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`.
// If `result === lastLocation.symbol`, that means that we are somewhere inside `lastLocation` looking up a name, and resolving to `lastLocation` itself.
// That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used.
if (result && nameNotFoundMessage && noUnusedIdentifiers && result !== lastLocation.symbol) {
result.isReferenced = true;
}
@ -2583,10 +2586,8 @@ namespace ts {
}
function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
if (type.objectFlags & ObjectFlags.Mapped) {
if (getConstraintTypeFromMappedType(<MappedType>type).flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
return createMappedTypeNodeFromType(<MappedType>type);
}
if (isGenericMappedType(type)) {
return createMappedTypeNodeFromType(<MappedType>type);
}
const resolved = resolveStructuredTypeMembers(type);
@ -3489,11 +3490,9 @@ namespace ts {
}
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
if (type.objectFlags & ObjectFlags.Mapped) {
if (getConstraintTypeFromMappedType(<MappedType>type).flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
writeMappedType(<MappedType>type);
return;
}
if (isGenericMappedType(type)) {
writeMappedType(<MappedType>type);
return;
}
const resolved = resolveStructuredTypeMembers(type);
@ -5792,8 +5791,7 @@ namespace ts {
}
function isGenericMappedType(type: Type) {
return getObjectFlags(type) & ObjectFlags.Mapped &&
maybeTypeOfKind(getConstraintTypeFromMappedType(<MappedType>type), TypeFlags.TypeVariable | TypeFlags.Index);
return getObjectFlags(type) & ObjectFlags.Mapped && isGenericIndexType(getConstraintTypeFromMappedType(<MappedType>type));
}
function resolveStructuredTypeMembers(type: StructuredType): ResolvedType {
@ -5905,6 +5903,10 @@ namespace ts {
}
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
const transformed = getTransformedIndexedAccessType(type);
if (transformed) {
return transformed;
}
const baseObjectType = getBaseConstraintOfType(type.objectType);
const baseIndexType = getBaseConstraintOfType(type.indexType);
return baseObjectType || baseIndexType ? getIndexedAccessType(baseObjectType || type.objectType, baseIndexType || type.indexType) : undefined;
@ -5976,11 +5978,18 @@ namespace ts {
return stringType;
}
if (t.flags & TypeFlags.IndexedAccess) {
const transformed = getTransformedIndexedAccessType(<IndexedAccessType>t);
if (transformed) {
return getBaseConstraint(transformed);
}
const baseObjectType = getBaseConstraint((<IndexedAccessType>t).objectType);
const baseIndexType = getBaseConstraint((<IndexedAccessType>t).indexType);
const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined;
return baseIndexedAccess && baseIndexedAccess !== unknownType ? getBaseConstraint(baseIndexedAccess) : undefined;
}
if (isGenericMappedType(t)) {
return emptyObjectType;
}
return t;
}
}
@ -7592,36 +7601,89 @@ namespace ts {
}
function getIndexedAccessForMappedType(type: MappedType, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
if (accessExpression && isAssignmentTarget(accessExpression) && type.declaration.readonlyToken) {
error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(type));
return unknownType;
if (accessNode) {
// Check if the index type is assignable to 'keyof T' for the object type.
if (!isTypeAssignableTo(indexType, getIndexType(type))) {
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(type));
return unknownType;
}
if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && type.declaration.readonlyToken) {
error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(type));
return unknownType;
}
}
const mapper = createTypeMapper([getTypeParameterFromMappedType(type)], [indexType]);
const templateMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper;
return instantiateType(getTemplateTypeFromMappedType(type), templateMapper);
}
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
// If the index type is generic, if the object type is generic and doesn't originate in an expression,
// or if the object type is a mapped type with a generic constraint, we are performing a higher-order
// index access where we cannot meaningfully access the properties of the object type. Note that for a
// generic T and a non-generic K, we eagerly resolve T[K] if it originates in an expression. This is to
// preserve backwards compatibility. For example, an element access 'this["foo"]' has always been resolved
// eagerly using the constraint type of 'this' at the given location.
if (maybeTypeOfKind(indexType, TypeFlags.TypeVariable | TypeFlags.Index) ||
maybeTypeOfKind(objectType, TypeFlags.TypeVariable) && !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) ||
isGenericMappedType(objectType)) {
function isGenericObjectType(type: Type): boolean {
return type.flags & TypeFlags.TypeVariable ? true :
getObjectFlags(type) & ObjectFlags.Mapped ? isGenericIndexType(getConstraintTypeFromMappedType(<MappedType>type)) :
type.flags & TypeFlags.UnionOrIntersection ? forEach((<UnionOrIntersectionType>type).types, isGenericObjectType) :
false;
}
function isGenericIndexType(type: Type): boolean {
return type.flags & (TypeFlags.TypeVariable | TypeFlags.Index) ? true :
type.flags & TypeFlags.UnionOrIntersection ? forEach((<UnionOrIntersectionType>type).types, isGenericIndexType) :
false;
}
// Return true if the given type is a non-generic object type with a string index signature and no
// other members.
function isStringIndexOnlyType(type: Type) {
if (type.flags & TypeFlags.Object && !isGenericMappedType(type)) {
const t = resolveStructuredTypeMembers(<ObjectType>type);
return t.properties.length === 0 &&
t.callSignatures.length === 0 && t.constructSignatures.length === 0 &&
t.stringIndexInfo && !t.numberIndexInfo;
}
return false;
}
// Given an indexed access type T[K], if T is an intersection containing one or more generic types and one or
// more object types with only a string index signature, e.g. '(U & V & { [x: string]: D })[K]', return a
// transformed type of the form '(U & V)[K] | D'. This allows us to properly reason about higher order indexed
// access types with default property values as expressed by D.
function getTransformedIndexedAccessType(type: IndexedAccessType): Type {
const objectType = type.objectType;
if (objectType.flags & TypeFlags.Intersection && isGenericObjectType(objectType) && some((<IntersectionType>objectType).types, isStringIndexOnlyType)) {
const regularTypes: Type[] = [];
const stringIndexTypes: Type[] = [];
for (const t of (<IntersectionType>objectType).types) {
if (isStringIndexOnlyType(t)) {
stringIndexTypes.push(getIndexTypeOfType(t, IndexKind.String));
}
else {
regularTypes.push(t);
}
}
return getUnionType([
getIndexedAccessType(getIntersectionType(regularTypes), type.indexType),
getIntersectionType(stringIndexTypes)
]);
}
return undefined;
}
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode): Type {
// If the object type is a mapped type { [P in K]: E }, where K is generic, we instantiate E using a mapper
// that substitutes the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we
// construct the type Box<T[X]>.
if (isGenericMappedType(objectType)) {
return getIndexedAccessForMappedType(<MappedType>objectType, indexType, accessNode);
}
// Otherwise, if the index type is generic, or if the object type is generic and doesn't originate in an
// expression, we are performing a higher-order index access where we cannot meaningfully access the properties
// of the object type. Note that for a generic T and a non-generic K, we eagerly resolve T[K] if it originates
// in an expression. This is to preserve backwards compatibility. For example, an element access 'this["foo"]'
// has always been resolved eagerly using the constraint type of 'this' at the given location.
if (isGenericIndexType(indexType) || !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) && isGenericObjectType(objectType)) {
if (objectType.flags & TypeFlags.Any) {
return objectType;
}
// If the object type is a mapped type { [P in K]: E }, we instantiate E using a mapper that substitutes
// the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we construct the
// type Box<T[X]>.
if (isGenericMappedType(objectType)) {
return getIndexedAccessForMappedType(<MappedType>objectType, indexType, accessNode);
}
// Otherwise we defer the operation by creating an indexed access type.
// Defer the operation by creating an indexed access type.
const id = objectType.id + "," + indexType.id;
let type = indexedAccessTypes.get(id);
if (!type) {
@ -8015,7 +8077,7 @@ namespace ts {
function cloneTypeMapper(mapper: TypeMapper): TypeMapper {
return mapper && isInferenceContext(mapper) ?
createInferenceContext(mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.inferences) :
createInferenceContext(mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.compareTypes, mapper.inferences) :
mapper;
}
@ -8456,7 +8518,7 @@ namespace ts {
ignoreReturnTypes: boolean,
reportErrors: boolean,
errorReporter: ErrorReporter,
compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary {
compareTypes: TypeComparer): Ternary {
// TODO (drosen): De-duplicate code between related functions.
if (source === target) {
return Ternary.True;
@ -8466,7 +8528,7 @@ namespace ts {
}
if (source.typeParameters) {
source = instantiateSignatureInContextOf(source, target);
source = instantiateSignatureInContextOf(source, target, /*contextualMapper*/ undefined, compareTypes);
}
let result = Ternary.True;
@ -8879,11 +8941,21 @@ namespace ts {
!(target.flags & TypeFlags.Union) &&
!isIntersectionConstituent &&
source !== globalObjectType &&
getPropertiesOfType(source).length > 0 &&
(getPropertiesOfType(source).length > 0 ||
getSignaturesOfType(source, SignatureKind.Call).length > 0 ||
getSignaturesOfType(source, SignatureKind.Construct).length > 0) &&
isWeakType(target) &&
!hasCommonProperties(source, target)) {
if (reportErrors) {
reportError(Diagnostics.Type_0_has_no_properties_in_common_with_type_1, typeToString(source), typeToString(target));
const calls = getSignaturesOfType(source, SignatureKind.Call);
const constructs = getSignaturesOfType(source, SignatureKind.Construct);
if (calls.length > 0 && isRelatedTo(getReturnTypeOfSignature(calls[0]), target, /*reportErrors*/ false) ||
constructs.length > 0 && isRelatedTo(getReturnTypeOfSignature(constructs[0]), target, /*reportErrors*/ false)) {
reportError(Diagnostics.Value_of_type_0_has_no_properties_in_common_with_type_1_Did_you_mean_to_call_it, typeToString(source), typeToString(target));
}
else {
reportError(Diagnostics.Type_0_has_no_properties_in_common_with_type_1, typeToString(source), typeToString(target));
}
}
return Ternary.False;
}
@ -9612,6 +9684,11 @@ namespace ts {
if (sourceInfo) {
return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors);
}
if (isGenericMappedType(source)) {
// A generic mapped type { [P in K]: T } is related to an index signature { [x: string]: U }
// if T is related to U.
return kind === IndexKind.String && isRelatedTo(getTemplateTypeFromMappedType(<MappedType>source), targetInfo.type, reportErrors);
}
if (isObjectLiteralType(source)) {
let related = Ternary.True;
if (kind === IndexKind.String) {
@ -10214,13 +10291,14 @@ namespace ts {
}
}
function createInferenceContext(signature: Signature, flags: InferenceFlags, baseInferences?: InferenceInfo[]): InferenceContext {
function createInferenceContext(signature: Signature, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext {
const inferences = baseInferences ? map(baseInferences, cloneInferenceInfo) : map(signature.typeParameters, createInferenceInfo);
const context = mapper as InferenceContext;
context.mappedTypes = signature.typeParameters;
context.signature = signature;
context.inferences = inferences;
context.flags = flags;
context.compareTypes = compareTypes || compareTypesAssignable;
return context;
function mapper(t: Type): Type {
@ -10323,6 +10401,19 @@ namespace ts {
}
}
function isPossiblyAssignableTo(source: Type, target: Type) {
const properties = getPropertiesOfObjectType(target);
for (const targetProp of properties) {
if (!(targetProp.flags & (SymbolFlags.Optional | SymbolFlags.Prototype))) {
const sourceProp = getPropertyOfObjectType(source, targetProp.escapedName);
if (!sourceProp) {
return false;
}
}
}
return true;
}
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) {
let symbolStack: Symbol[];
let visited: Map<boolean>;
@ -10516,10 +10607,14 @@ namespace ts {
return;
}
}
inferFromProperties(source, target);
inferFromSignatures(source, target, SignatureKind.Call);
inferFromSignatures(source, target, SignatureKind.Construct);
inferFromIndexTypes(source, target);
// Infer from the members of source and target only if the two types are possibly related. We check
// in both directions because we may be inferring for a co-variant or a contra-variant position.
if (isPossiblyAssignableTo(source, target) || isPossiblyAssignableTo(target, source)) {
inferFromProperties(source, target);
inferFromSignatures(source, target, SignatureKind.Call);
inferFromSignatures(source, target, SignatureKind.Construct);
inferFromIndexTypes(source, target);
}
}
function inferFromProperties(source: Type, target: Type) {
@ -10651,7 +10746,7 @@ namespace ts {
const constraint = getConstraintOfTypeParameter(context.signature.typeParameters[index]);
if (constraint) {
const instantiatedConstraint = instantiateType(constraint, context);
if (!isTypeAssignableTo(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
if (!context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
inference.inferredType = inferredType = instantiatedConstraint;
}
}
@ -10718,17 +10813,6 @@ namespace ts {
return undefined;
}
function getLeftmostIdentifierOrThis(node: Node): Node {
switch (node.kind) {
case SyntaxKind.Identifier:
case SyntaxKind.ThisKeyword:
return node;
case SyntaxKind.PropertyAccessExpression:
return getLeftmostIdentifierOrThis((<PropertyAccessExpression>node).expression);
}
return undefined;
}
function getBindingElementNameText(element: BindingElement): string | undefined {
if (element.parent.kind === SyntaxKind.ObjectBindingPattern) {
const name = element.propertyName || element.name;
@ -14020,11 +14104,8 @@ namespace ts {
*/
function resolveCustomJsxElementAttributesType(openingLikeElement: JsxOpeningLikeElement,
shouldIncludeAllStatelessAttributesType: boolean,
elementType?: Type,
elementType: Type = checkExpression(openingLikeElement.tagName),
elementClassType?: Type): Type {
if (!elementType) {
elementType = checkExpression(openingLikeElement.tagName);
}
if (elementType.flags & TypeFlags.Union) {
const types = (elementType as UnionType).types;
@ -14158,11 +14239,12 @@ namespace ts {
*/
function getCustomJsxElementAttributesType(node: JsxOpeningLikeElement, shouldIncludeAllStatelessAttributesType: boolean): Type {
const links = getNodeLinks(node);
if (!links.resolvedJsxElementAttributesType) {
const linkLocation = shouldIncludeAllStatelessAttributesType ? "resolvedJsxElementAllAttributesType" : "resolvedJsxElementAttributesType";
if (!links[linkLocation]) {
const elemClassType = getJsxGlobalElementClassType();
return links.resolvedJsxElementAttributesType = resolveCustomJsxElementAttributesType(node, shouldIncludeAllStatelessAttributesType, /*elementType*/ undefined, elemClassType);
return links[linkLocation] = resolveCustomJsxElementAttributesType(node, shouldIncludeAllStatelessAttributesType, /*elementType*/ undefined, elemClassType);
}
return links.resolvedJsxElementAttributesType;
return links[linkLocation];
}
/**
@ -15049,8 +15131,8 @@ namespace ts {
}
// Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec)
function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper?: TypeMapper): Signature {
const context = createInferenceContext(signature, InferenceFlags.InferUnionTypes);
function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper?: TypeMapper, compareTypes?: TypeComparer): Signature {
const context = createInferenceContext(signature, InferenceFlags.InferUnionTypes, compareTypes);
forEachMatchingParameterType(contextualSignature, signature, (source, target) => {
// Type parameters from outer context referenced by source type are fixed by instantiation of the source type
inferTypes(context.inferences, instantiateType(source, contextualMapper || identityMapper), target);
@ -16965,8 +17047,13 @@ namespace ts {
if (operandType === silentNeverType) {
return silentNeverType;
}
if (node.operator === SyntaxKind.MinusToken && node.operand.kind === SyntaxKind.NumericLiteral) {
return getFreshTypeOfLiteralType(getLiteralType(-(<LiteralExpression>node.operand).text));
if (node.operand.kind === SyntaxKind.NumericLiteral) {
if (node.operator === SyntaxKind.MinusToken) {
return getFreshTypeOfLiteralType(getLiteralType(-(<LiteralExpression>node.operand).text));
}
else if (node.operator === SyntaxKind.PlusToken) {
return getFreshTypeOfLiteralType(getLiteralType(+(<LiteralExpression>node.operand).text));
}
}
switch (node.operator) {
case SyntaxKind.PlusToken:
@ -18419,15 +18506,6 @@ namespace ts {
return forEachChild(n, containsSuperCall);
}
function markThisReferencesAsErrors(n: Node): void {
if (n.kind === SyntaxKind.ThisKeyword) {
error(n, Diagnostics.this_cannot_be_referenced_in_current_location);
}
else if (n.kind !== SyntaxKind.FunctionExpression && n.kind !== SyntaxKind.FunctionDeclaration) {
forEachChild(n, markThisReferencesAsErrors);
}
}
function isInstancePropertyWithInitializer(n: Node): boolean {
return n.kind === SyntaxKind.PropertyDeclaration &&
!(getModifierFlags(n) & ModifierFlags.Static) &&
@ -18578,7 +18656,17 @@ namespace ts {
forEach(node.typeArguments, checkSourceElement);
if (produceDiagnostics) {
const symbol = getNodeLinks(node).resolvedSymbol;
const typeParameters = symbol.flags & SymbolFlags.TypeAlias ? getSymbolLinks(symbol).typeParameters : (<TypeReference>type).target.localTypeParameters;
if (!symbol) {
// There is no resolved symbol cached if the type resolved to a builtin
// via JSDoc type reference resolution (eg, Boolean became boolean), none
// of which are generic when they have no associated symbol
error(node, Diagnostics.Type_0_is_not_generic, typeToString(type));
return;
}
let typeParameters = symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters;
if (!typeParameters && getObjectFlags(type) & ObjectFlags.Reference) {
typeParameters = (<TypeReference>type).target.localTypeParameters;
}
checkTypeArgumentConstraints(typeParameters, node.typeArguments);
}
}
@ -18643,6 +18731,8 @@ namespace ts {
}
function checkIndexedAccessType(node: IndexedAccessTypeNode) {
checkSourceElement(node.objectType);
checkSourceElement(node.indexType);
checkIndexedAccessIndexType(getTypeFromIndexedAccessTypeNode(node), node);
}

View file

@ -1446,14 +1446,10 @@ namespace ts {
}
}
else {
// If no includes were specified, exclude common package folders and the outDir
const specs = includeSpecs ? [] : ["node_modules", "bower_components", "jspm_packages"];
const outDir = raw["compilerOptions"] && raw["compilerOptions"]["outDir"];
if (outDir) {
specs.push(outDir);
excludeSpecs = [outDir];
}
excludeSpecs = specs;
}
if (fileNames === undefined && includeSpecs === undefined) {
@ -2015,23 +2011,13 @@ namespace ts {
}
function validateSpecs(specs: ReadonlyArray<string>, errors: Push<Diagnostic>, allowTrailingRecursion: boolean, jsonSourceFile: JsonSourceFile, specKey: string) {
const validSpecs: string[] = [];
for (const spec of specs) {
if (!allowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) {
errors.push(createDiagnostic(Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec));
return specs.filter(spec => {
const diag = specToDiagnostic(spec, allowTrailingRecursion);
if (diag !== undefined) {
errors.push(createDiagnostic(diag, spec));
}
else if (invalidMultipleRecursionPatterns.test(spec)) {
errors.push(createDiagnostic(Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, spec));
}
else if (invalidDotDotAfterRecursiveWildcardPattern.test(spec)) {
errors.push(createDiagnostic(Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec));
}
else {
validSpecs.push(spec);
}
}
return validSpecs;
return diag === undefined;
});
function createDiagnostic(message: DiagnosticMessage, spec: string): Diagnostic {
if (jsonSourceFile && jsonSourceFile.jsonObject) {
@ -2049,6 +2035,18 @@ namespace ts {
}
}
function specToDiagnostic(spec: string, allowTrailingRecursion: boolean): ts.DiagnosticMessage | undefined {
if (!allowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) {
return Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0;
}
else if (invalidMultipleRecursionPatterns.test(spec)) {
return Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0;
}
else if (invalidDotDotAfterRecursiveWildcardPattern.test(spec)) {
return Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0;
}
}
/**
* Gets directories in a set of include patterns that should be watched for changes.
*/

View file

@ -11,20 +11,6 @@ namespace ts {
/* @internal */
namespace ts {
/**
* Ternary values are defined such that
* x & y is False if either x or y is False.
* x & y is Maybe if either x or y is Maybe, but neither x or y is False.
* x & y is True if both x and y are True.
* x | y is False if both x and y are False.
* x | y is Maybe if either x or y is Maybe, but neither x or y is True.
* x | y is True if either x or y is True.
*/
export const enum Ternary {
False = 0,
Maybe = 1,
True = -1
}
// More efficient to create a collator once and use its `compare` than to call `a.localeCompare(b)` many times.
export const collator: { compare(a: string, b: string): number } = typeof Intl === "object" && typeof Intl.Collator === "function" ? new Intl.Collator(/*locales*/ undefined, { usage: "sort", sensitivity: "accent" }) : undefined;
@ -375,11 +361,11 @@ namespace ts {
return false;
}
export function filterMutate<T>(array: T[], f: (x: T) => boolean): void {
export function filterMutate<T>(array: T[], f: (x: T, i: number, array: T[]) => boolean): void {
let outIndex = 0;
for (const item of array) {
if (f(item)) {
array[outIndex] = item;
for (let i = 0; i < array.length; i++) {
if (f(array[i], i, array)) {
array[outIndex] = array[i];
outIndex++;
}
}
@ -1304,12 +1290,12 @@ namespace ts {
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): Diagnostic {
const end = start + length;
Debug.assert(start >= 0, "start must be non-negative, is " + start);
Debug.assert(length >= 0, "length must be non-negative, is " + length);
Debug.assertGreaterThanOrEqual(start, 0);
Debug.assertGreaterThanOrEqual(length, 0);
if (file) {
Debug.assert(start <= file.text.length, `start must be within the bounds of the file. ${start} > ${file.text.length}`);
Debug.assert(end <= file.text.length, `end must be the bounds of the file. ${end} > ${file.text.length}`);
Debug.assertLessThanOrEqual(start, file.text.length);
Debug.assertLessThanOrEqual(end, file.text.length);
}
let text = getLocaleSpecificMessage(message);
@ -1889,14 +1875,54 @@ namespace ts {
const reservedCharacterPattern = /[^\w\s\/]/g;
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
/**
* Matches any single directory segment unless it is the last segment and a .min.js file
* Breakdown:
* [^./] # matches everything up to the first . character (excluding directory seperators)
* (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
*/
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
const singleAsteriskRegexFragmentOther = "[^/]*";
/* @internal */
export const commonPackageFolders: ReadonlyArray<string> = ["node_modules", "bower_components", "jspm_packages"];
const implicitExcludePathRegexPattern = `(?!(${commonPackageFolders.join("|")})(/|$))`;
interface WildcardMatcher {
singleAsteriskRegexFragment: string;
doubleAsteriskRegexFragment: string;
replaceWildcardCharacter: (match: string) => string;
}
const filesMatcher: WildcardMatcher = {
/**
* Matches any single directory segment unless it is the last segment and a .min.js file
* Breakdown:
* [^./] # matches everything up to the first . character (excluding directory seperators)
* (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
*/
singleAsteriskRegexFragment: "([^./]|(\\.(?!min\\.js$))?)*",
/**
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
* files or directories, does not match subdirectories that start with a . character
*/
doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`,
replaceWildcardCharacter: match => replaceWildcardCharacter(match, filesMatcher.singleAsteriskRegexFragment)
};
const directoriesMatcher: WildcardMatcher = {
singleAsteriskRegexFragment: "[^/]*",
/**
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
* files or directories, does not match subdirectories that start with a . character
*/
doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`,
replaceWildcardCharacter: match => replaceWildcardCharacter(match, directoriesMatcher.singleAsteriskRegexFragment)
};
const excludeMatcher: WildcardMatcher = {
singleAsteriskRegexFragment: "[^/]*",
doubleAsteriskRegexFragment: "(/.+?)?",
replaceWildcardCharacter: match => replaceWildcardCharacter(match, excludeMatcher.singleAsteriskRegexFragment)
};
const wildcardMatchers = {
files: filesMatcher,
directories: directoriesMatcher,
exclude: excludeMatcher
};
export function getRegularExpressionForWildcard(specs: ReadonlyArray<string>, basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
const patterns = getRegularExpressionsForWildcards(specs, basePath, usage);
@ -1915,17 +1941,8 @@ namespace ts {
return undefined;
}
const replaceWildcardCharacter = usage === "files" ? replaceWildCardCharacterFiles : replaceWildCardCharacterOther;
const singleAsteriskRegexFragment = usage === "files" ? singleAsteriskRegexFragmentFiles : singleAsteriskRegexFragmentOther;
/**
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
* files or directories, does not match subdirectories that start with a . character
*/
const doubleAsteriskRegexFragment = usage === "exclude" ? "(/.+?)?" : "(/[^/.][^/]*)*?";
return flatMap(specs, spec =>
spec && getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter));
spec && getSubPatternFromSpec(spec, basePath, usage, wildcardMatchers[usage]));
}
/**
@ -1936,7 +1953,7 @@ namespace ts {
return !/[.*?]/.test(lastPathComponent);
}
function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", singleAsteriskRegexFragment: string, doubleAsteriskRegexFragment: string, replaceWildcardCharacter: (match: string) => string): string | undefined {
function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }: WildcardMatcher): string | undefined {
let subpattern = "";
let hasRecursiveDirectoryWildcard = false;
let hasWrittenComponent = false;
@ -1975,20 +1992,36 @@ namespace ts {
}
if (usage !== "exclude") {
let componentPattern = "";
// The * and ? wildcards should not match directories or files that start with . if they
// appear first in a component. Dotted directories and files can be included explicitly
// like so: **/.*/.*
if (component.charCodeAt(0) === CharacterCodes.asterisk) {
subpattern += "([^./]" + singleAsteriskRegexFragment + ")?";
componentPattern += "([^./]" + singleAsteriskRegexFragment + ")?";
component = component.substr(1);
}
else if (component.charCodeAt(0) === CharacterCodes.question) {
subpattern += "[^./]";
componentPattern += "[^./]";
component = component.substr(1);
}
}
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
componentPattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
// Patterns should not include subfolders like node_modules unless they are
// explicitly included as part of the path.
//
// As an optimization, if the component pattern is the same as the component,
// then there definitely were no wildcard characters and we do not need to
// add the exclusion pattern.
if (componentPattern !== component) {
subpattern += implicitExcludePathRegexPattern;
}
subpattern += componentPattern;
}
else {
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
}
}
hasWrittenComponent = true;
@ -2002,14 +2035,6 @@ namespace ts {
return subpattern;
}
function replaceWildCardCharacterFiles(match: string) {
return replaceWildcardCharacter(match, singleAsteriskRegexFragmentFiles);
}
function replaceWildCardCharacterOther(match: string) {
return replaceWildcardCharacter(match, singleAsteriskRegexFragmentOther);
}
function replaceWildcardCharacter(match: string, singleAsteriskRegexFragment: string) {
return match === "*" ? singleAsteriskRegexFragment : match === "?" ? "[^/]" : "\\" + match;
}
@ -2364,15 +2389,40 @@ namespace ts {
return currentAssertionLevel >= level;
}
export function assert(expression: boolean, message?: string, verboseDebugInfo?: () => string, stackCrawlMark?: Function): void {
export function assert(expression: boolean, message?: string, verboseDebugInfo?: string | (() => string), stackCrawlMark?: Function): void {
if (!expression) {
if (verboseDebugInfo) {
message += "\r\nVerbose Debug Information: " + verboseDebugInfo();
message += "\r\nVerbose Debug Information: " + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo());
}
fail(message ? "False expression: " + message : "False expression.", stackCrawlMark || assert);
}
}
export function assertEqual<T>(a: T, b: T, msg?: string, msg2?: string): void {
if (a !== b) {
const message = msg ? msg2 ? `${msg} ${msg2}` : msg : "";
fail(`Expected ${a} === ${b}. ${message}`);
}
}
export function assertLessThan(a: number, b: number, msg?: string): void {
if (a >= b) {
fail(`Expected ${a} < ${b}. ${msg || ""}`);
}
}
export function assertLessThanOrEqual(a: number, b: number): void {
if (a > b) {
fail(`Expected ${a} <= ${b}`);
}
}
export function assertGreaterThanOrEqual(a: number, b: number): void {
if (a < b) {
fail(`Expected ${a} >= ${b}`);
}
}
export function fail(message?: string, stackCrawlMark?: Function): void {
debugger;
const e = new Error(message ? `Debug Failure. ${message}` : "Debug Failure.");

View file

@ -1908,6 +1908,10 @@
"category": "Error",
"code": 2559
},
"Value of type '{0}' has no properties in common with type '{1}'. Did you mean to call it?": {
"category": "Error",
"code": 2560
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600

View file

@ -1346,7 +1346,9 @@ namespace ts {
emitExpression(node.left);
increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined);
emitLeadingCommentsOfPosition(node.operatorToken.pos);
writeTokenNode(node.operatorToken);
emitTrailingCommentsOfPosition(node.operatorToken.end);
increaseIndentIf(indentAfterOperator, " ");
emitExpression(node.right);
decreaseIndentIf(indentBeforeOperator, indentAfterOperator);

View file

@ -678,7 +678,7 @@ namespace ts {
const { resolvedModule, failedLookupLocations } =
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ts.ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
if (!resolvedModule) {
throw new Error(`Could not resolve JS module ${moduleName} starting at ${initialDir}. Looked in: ${failedLookupLocations.join(", ")}`);
throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`);
}
return resolvedModule.resolvedFileName;
}

View file

@ -2061,7 +2061,7 @@ namespace ts {
return <TemplateMiddle | TemplateTail>fragment;
}
function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode {
function parseLiteralLikeNode(kind: SyntaxKind): LiteralExpression | LiteralLikeNode {
const node = <LiteralExpression>createNode(kind);
const text = scanner.getTokenValue();
node.text = text;
@ -2611,11 +2611,31 @@ namespace ts {
return token() === SyntaxKind.DotToken ? undefined : node;
}
function parseLiteralTypeNode(): LiteralTypeNode {
const node = <LiteralTypeNode>createNode(SyntaxKind.LiteralType);
node.literal = parseSimpleUnaryExpression();
finishNode(node);
return node;
function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode {
const node = createNode(SyntaxKind.LiteralType) as LiteralTypeNode;
let unaryMinusExpression: PrefixUnaryExpression;
if (negative) {
unaryMinusExpression = createNode(SyntaxKind.PrefixUnaryExpression) as PrefixUnaryExpression;
unaryMinusExpression.operator = SyntaxKind.MinusToken;
nextToken();
}
let expression: UnaryExpression;
switch (token()) {
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
expression = parseLiteralLikeNode(token()) as LiteralExpression;
break;
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
expression = parseTokenNode();
}
if (negative) {
unaryMinusExpression.operand = expression;
finishNode(unaryMinusExpression);
expression = unaryMinusExpression;
}
node.literal = expression;
return finishNode(node);
}
function nextTokenIsNumericLiteral() {
@ -2650,7 +2670,7 @@ namespace ts {
case SyntaxKind.FalseKeyword:
return parseLiteralTypeNode();
case SyntaxKind.MinusToken:
return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode() : parseTypeReference();
return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
case SyntaxKind.VoidKeyword:
case SyntaxKind.NullKeyword:
return parseTokenNode<TypeNode>();
@ -2700,6 +2720,7 @@ namespace ts {
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
case SyntaxKind.ObjectKeyword:
case SyntaxKind.AsteriskToken:
return true;
case SyntaxKind.MinusToken:
return lookAhead(nextTokenIsNumericLiteral);

View file

@ -4,6 +4,18 @@ declare function setTimeout(handler: (...args: any[]) => void, timeout: number):
declare function clearTimeout(handle: any): void;
namespace ts {
/**
* Set a high stack trace limit to provide more information in case of an error.
* Called for command-line and server use cases.
* Not called if TypeScript is used as a library.
*/
/* @internal */
export function setStackTraceLimit() {
if ((Error as any).stackTraceLimit < 100) { // Also tests that we won't set the property if it doesn't exist.
(Error as any).stackTraceLimit = 100;
}
}
export enum FileWatcherEventKind {
Created,
Changed,

View file

@ -2448,7 +2448,7 @@ namespace ts {
* @param location An optional source map location for the statement.
*/
function createInlineBreak(label: Label, location?: TextRange): ReturnStatement {
Debug.assert(label > 0, `Invalid label: ${label}`);
Debug.assertLessThan(0, label, "Invalid label");
return setTextRange(
createReturn(
createArrayLiteral([

View file

@ -665,6 +665,8 @@ namespace ts {
}
}
ts.setStackTraceLimit();
if (ts.Debug.isDebugging) {
ts.Debug.enableDebugInfo();
}

View file

@ -3067,6 +3067,7 @@ namespace ts {
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
jsxFlags?: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with
resolvedJsxElementAttributesType?: Type; // resolved element attributes type of a JSX openinglike element
resolvedJsxElementAllAttributesType?: Type; // resolved all element attributes type of a JSX openinglike element
hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt.
superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
switchTypes?: Type[]; // Cached array of switch case expression types
@ -3425,11 +3426,29 @@ namespace ts {
AnyDefault = 1 << 2, // Infer anyType for no inferences (otherwise emptyObjectType)
}
/**
* Ternary values are defined such that
* x & y is False if either x or y is False.
* x & y is Maybe if either x or y is Maybe, but neither x or y is False.
* x & y is True if both x and y are True.
* x | y is False if both x and y are False.
* x | y is Maybe if either x or y is Maybe, but neither x or y is True.
* x | y is True if either x or y is True.
*/
export const enum Ternary {
False = 0,
Maybe = 1,
True = -1
}
export type TypeComparer = (s: Type, t: Type, reportErrors?: boolean) => Ternary;
/* @internal */
export interface InferenceContext extends TypeMapper {
signature: Signature; // Generic signature for which inferences are made
inferences: InferenceInfo[]; // Inferences made for each type parameter
flags: InferenceFlags; // Inference flags
compareTypes: TypeComparer; // Type comparer function
}
/* @internal */

View file

@ -922,21 +922,11 @@ namespace ts {
}
export function getContainingFunction(node: Node): FunctionLike {
while (true) {
node = node.parent;
if (!node || isFunctionLike(node)) {
return <FunctionLike>node;
}
}
return findAncestor(node.parent, isFunctionLike);
}
export function getContainingClass(node: Node): ClassLikeDeclaration {
while (true) {
node = node.parent;
if (!node || isClassLike(node)) {
return <ClassLikeDeclaration>node;
}
}
return findAncestor(node.parent, isClassLike);
}
export function getThisContainer(node: Node, includeArrowFunctions: boolean): Node {

View file

@ -420,7 +420,7 @@ namespace Utils {
const maxHarnessFrames = 1;
export function filterStack(error: Error, stackTraceLimit: number = Infinity) {
export function filterStack(error: Error, stackTraceLimit = Infinity) {
const stack = <string>(<any>error).stack;
if (stack) {
const lines = stack.split(/\r\n?|\n/g);

View file

@ -681,11 +681,11 @@ namespace Harness.LanguageService {
}
info(message: string): void {
return this.host.log(message);
this.host.log(message);
}
msg(message: string) {
return this.host.log(message);
err(message: string): void {
this.host.log(message);
}
loggingEnabled() {
@ -700,17 +700,12 @@ namespace Harness.LanguageService {
return false;
}
endGroup(): void {
}
group() { throw ts.notImplemented(); }
perftrc(message: string): void {
return this.host.log(message);
}
startGroup(): void {
}
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any {
return setTimeout(callback, ms, args);
}
@ -795,7 +790,7 @@ namespace Harness.LanguageService {
default:
return {
module: undefined,
error: "Could not resolve module"
error: new Error("Could not resolve module")
};
}

View file

@ -52,21 +52,9 @@ namespace ts {
}
function createProject(rootFile: string, serverHost: server.ServerHost): { project: server.Project, rootScriptInfo: server.ScriptInfo } {
const logger: server.Logger = {
close: noop,
hasLevel: () => false,
loggingEnabled: () => false,
perftrc: noop,
info: noop,
startGroup: noop,
endGroup: noop,
msg: noop,
getLogFileName: (): string => undefined
};
const svcOpts: server.ProjectServiceOptions = {
host: serverHost,
logger,
logger: projectSystem.nullLogger,
cancellationToken: { isCancellationRequested: () => false },
useSingleInferredProject: false,
typingsInstaller: undefined

View file

@ -73,6 +73,7 @@ namespace ts {
"c:/dev/a.d.ts",
"c:/dev/a.js",
"c:/dev/b.ts",
"c:/dev/x/a.ts",
"c:/dev/node_modules/a.ts",
"c:/dev/bower_components/a.ts",
"c:/dev/jspm_packages/a.ts"
@ -141,7 +142,8 @@ namespace ts {
errors: [],
fileNames: [
"c:/dev/a.ts",
"c:/dev/b.ts"
"c:/dev/b.ts",
"c:/dev/x/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
@ -462,7 +464,6 @@ namespace ts {
};
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("same named declarations are excluded", () => {
const json = {
include: [
@ -651,71 +652,127 @@ namespace ts {
};
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with common package folders and no exclusions", () => {
const json = {
include: [
"**/a.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/a.ts",
"c:/dev/bower_components/a.ts",
"c:/dev/jspm_packages/a.ts",
"c:/dev/node_modules/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and exclusions", () => {
const json = {
include: [
"**/a.ts"
],
exclude: [
"a.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/bower_components/a.ts",
"c:/dev/jspm_packages/a.ts",
"c:/dev/node_modules/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and empty exclude", () => {
const json = {
include: [
"**/a.ts"
],
exclude: <string[]>[]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/a.ts",
"c:/dev/bower_components/a.ts",
"c:/dev/jspm_packages/a.ts",
"c:/dev/node_modules/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
describe("with common package folders", () => {
it("and no exclusions", () => {
const json = {
include: [
"**/a.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/a.ts",
"c:/dev/x/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("and exclusions", () => {
const json = {
include: [
"**/?.ts"
],
exclude: [
"a.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/b.ts",
"c:/dev/x/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("and empty exclude", () => {
const json = {
include: [
"**/a.ts"
],
exclude: <string[]>[]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/a.ts",
"c:/dev/x/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("and explicit recursive include", () => {
const json = {
include: [
"**/a.ts",
"**/node_modules/a.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/a.ts",
"c:/dev/x/a.ts",
"c:/dev/node_modules/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("and wildcard include", () => {
const json = {
include: [
"*/a.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/x/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("and explicit wildcard include", () => {
const json = {
include: [
"*/a.ts",
"node_modules/a.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/x/a.ts",
"c:/dev/node_modules/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
});
it("exclude .js files when allowJs=false", () => {
const json = {
@ -1066,6 +1123,7 @@ namespace ts {
};
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
describe("with trailing recursive directory", () => {
it("in includes", () => {
const json = {
@ -1264,6 +1322,7 @@ namespace ts {
});
});
});
describe("with files or folders that begin with a .", () => {
it("that are not explicitly included", () => {
const json = {

View file

@ -28,18 +28,6 @@ namespace ts.server {
createHash: Harness.LanguageService.mockHash,
};
const mockLogger: Logger = {
close: noop,
hasLevel(): boolean { return false; },
loggingEnabled(): boolean { return false; },
perftrc: noop,
info: noop,
startGroup: noop,
endGroup: noop,
msg: noop,
getLogFileName: (): string => undefined
};
class TestSession extends Session {
getProjectService() {
return this.projectService;
@ -58,7 +46,7 @@ namespace ts.server {
typingsInstaller: undefined,
byteLength: Utils.byteLength,
hrtime: process.hrtime,
logger: mockLogger,
logger: projectSystem.nullLogger,
canUseEvents: true
};
return new TestSession(opts);
@ -408,7 +396,7 @@ namespace ts.server {
typingsInstaller: undefined,
byteLength: Utils.byteLength,
hrtime: process.hrtime,
logger: mockLogger,
logger: projectSystem.nullLogger,
canUseEvents: true
});
this.addProtocolHandler(this.customHandler, () => {
@ -475,7 +463,7 @@ namespace ts.server {
typingsInstaller: undefined,
byteLength: Utils.byteLength,
hrtime: process.hrtime,
logger: mockLogger,
logger: projectSystem.nullLogger,
canUseEvents: true
});
this.addProtocolHandler("echo", (req: protocol.Request) => ({

View file

@ -34,18 +34,17 @@ namespace ts.projectSystem {
}
export const nullLogger: server.Logger = {
close: () => void 0,
hasLevel: () => void 0,
close: noop,
hasLevel: () => false,
loggingEnabled: () => false,
perftrc: () => void 0,
info: () => void 0,
startGroup: () => void 0,
endGroup: () => void 0,
msg: () => void 0,
perftrc: noop,
info: noop,
err: noop,
group: noop,
getLogFileName: (): string => undefined
};
export const { content: libFileContent } = Harness.getDefaultLibraryFile(Harness.IO);
const { content: libFileContent } = Harness.getDefaultLibraryFile(Harness.IO);
export const libFile: FileOrFolder = {
path: "/a/lib/lib.d.ts",
content: libFileContent
@ -118,7 +117,7 @@ namespace ts.projectSystem {
return JSON.stringify({ dependencies });
}
export function getExecutingFilePathFromLibFile(): string {
function getExecutingFilePathFromLibFile(): string {
return combinePaths(getDirectoryPath(libFile.path), "tsc.js");
}
@ -130,7 +129,7 @@ namespace ts.projectSystem {
return map(fileNames, toExternalFile);
}
export class TestServerEventManager {
class TestServerEventManager {
public events: server.ProjectServiceEvent[] = [];
handler: server.ProjectServiceEventHandler = (event: server.ProjectServiceEvent) => {
@ -143,7 +142,7 @@ namespace ts.projectSystem {
}
}
export interface TestServerHostCreationParameters {
interface TestServerHostCreationParameters {
useCaseSensitiveFileNames?: boolean;
executingFilePath?: string;
currentDirectory?: string;
@ -205,7 +204,7 @@ namespace ts.projectSystem {
return new TestSession(opts);
}
export interface CreateProjectServiceParameters {
interface CreateProjectServiceParameters {
cancellationToken?: HostCancellationToken;
logger?: server.Logger;
useSingleInferredProject?: boolean;
@ -253,15 +252,15 @@ namespace ts.projectSystem {
entries: FSEntry[];
}
export function isFolder(s: FSEntry): s is Folder {
function isFolder(s: FSEntry): s is Folder {
return isArray((<Folder>s).entries);
}
export function isFile(s: FSEntry): s is File {
function isFile(s: FSEntry): s is File {
return typeof (<File>s).content === "string";
}
export function addFolder(fullPath: string, toPath: (s: string) => Path, fs: Map<FSEntry>): Folder {
function addFolder(fullPath: string, toPath: (s: string) => Path, fs: Map<FSEntry>): Folder {
const path = toPath(fullPath);
if (fs.has(path)) {
Debug.assert(isFolder(fs.get(path)));
@ -279,29 +278,29 @@ namespace ts.projectSystem {
return entry;
}
export function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
assert.equal(map.size, expectedKeys.length, `${caption}: incorrect size of map`);
for (const name of expectedKeys) {
assert.isTrue(map.has(name), `${caption} is expected to contain ${name}, actual keys: ${arrayFrom(map.keys())}`);
}
}
export function checkFileNames(caption: string, actualFileNames: string[], expectedFileNames: string[]) {
function checkFileNames(caption: string, actualFileNames: string[], expectedFileNames: string[]) {
assert.equal(actualFileNames.length, expectedFileNames.length, `${caption}: incorrect actual number of files, expected ${JSON.stringify(expectedFileNames)}, got ${actualFileNames}`);
for (const f of expectedFileNames) {
assert.isTrue(contains(actualFileNames, f), `${caption}: expected to find ${f} in ${JSON.stringify(actualFileNames)}`);
}
}
export function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) {
function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) {
assert.equal(projectService.configuredProjects.length, expected, `expected ${expected} configured project(s)`);
}
export function checkNumberOfExternalProjects(projectService: server.ProjectService, expected: number) {
function checkNumberOfExternalProjects(projectService: server.ProjectService, expected: number) {
assert.equal(projectService.externalProjects.length, expected, `expected ${expected} external project(s)`);
}
export function checkNumberOfInferredProjects(projectService: server.ProjectService, expected: number) {
function checkNumberOfInferredProjects(projectService: server.ProjectService, expected: number) {
assert.equal(projectService.inferredProjects.length, expected, `expected ${expected} inferred project(s)`);
}
@ -315,7 +314,7 @@ namespace ts.projectSystem {
checkMapKeys("watchedFiles", host.watchedFiles, expectedFiles);
}
export function checkWatchedDirectories(host: TestServerHost, expectedDirectories: string[]) {
function checkWatchedDirectories(host: TestServerHost, expectedDirectories: string[]) {
checkMapKeys("watchedDirectories", host.watchedDirectories, expectedDirectories);
}
@ -323,11 +322,11 @@ namespace ts.projectSystem {
checkFileNames(`${server.ProjectKind[project.projectKind]} project, actual files`, project.getFileNames(), expectedFiles);
}
export function checkProjectRootFiles(project: server.Project, expectedFiles: string[]) {
function checkProjectRootFiles(project: server.Project, expectedFiles: string[]) {
checkFileNames(`${server.ProjectKind[project.projectKind]} project, rootFileNames`, project.getRootFiles(), expectedFiles);
}
export class Callbacks {
class Callbacks {
private map: TimeOutCallback[] = [];
private nextId = 1;
@ -363,7 +362,7 @@ namespace ts.projectSystem {
}
}
export type TimeOutCallback = () => any;
type TimeOutCallback = () => any;
export class TestServerHost implements server.ServerHost {
args: string[] = [];
@ -2332,6 +2331,50 @@ namespace ts.projectSystem {
const navbar = projectService.externalProjects[0].getLanguageService(/*ensureSynchronized*/ false).getNavigationBarItems(f1.path);
assert.equal(navbar[0].spans[0].length, f1.content.length);
});
it("deleting config file opened from the external project works", () => {
const site = {
path: "/user/someuser/project/js/site.js",
content: ""
};
const configFile = {
path: "/user/someuser/project/tsconfig.json",
content: "{}"
};
const projectFileName = "/user/someuser/project/WebApplication6.csproj";
const host = createServerHost([libFile, site, configFile]);
const projectService = createProjectService(host);
const externalProject: protocol.ExternalProject = {
projectFileName,
rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)],
options: { allowJs: false },
typeAcquisition: { "include": [] }
};
projectService.openExternalProjects([externalProject]);
let knownProjects = projectService.synchronizeProjectList([]);
checkNumberOfProjects(projectService, { configuredProjects: 1, externalProjects: 0, inferredProjects: 0 });
const configProject = projectService.configuredProjects[0];
checkProjectActualFiles(configProject, [libFile.path]);
const diagnostics = configProject.getAllProjectErrors();
assert.equal(diagnostics[0].code, Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
host.reloadFS([libFile, site]);
host.triggerFileWatcherCallback(configFile.path, FileWatcherEventKind.Deleted);
knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info));
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 });
externalProject.rootFiles.length = 1;
projectService.openExternalProjects([externalProject]);
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 1, inferredProjects: 0 });
checkProjectActualFiles(projectService.externalProjects[0], [site.path, libFile.path]);
});
});
describe("Proper errors", () => {

View file

@ -110,7 +110,7 @@ interface Map<K, V> {
readonly [Symbol.toStringTag]: "Map";
}
interface WeakMap<K extends object, V>{
interface WeakMap<K extends object, V> {
readonly [Symbol.toStringTag]: "WeakMap";
}

View file

@ -326,8 +326,8 @@ namespace ts.server {
typingsInstaller: ITypingsInstaller;
eventHandler?: ProjectServiceEventHandler;
throttleWaitMilliseconds?: number;
globalPlugins?: string[];
pluginProbeLocations?: string[];
globalPlugins?: ReadonlyArray<string>;
pluginProbeLocations?: ReadonlyArray<string>;
allowLocalPluginLoads?: boolean;
}
@ -928,26 +928,24 @@ namespace ts.server {
return;
}
this.logger.startGroup();
this.logger.group(info => {
let counter = 0;
counter = printProjects(this.externalProjects, info, counter);
counter = printProjects(this.configuredProjects, info, counter);
printProjects(this.inferredProjects, info, counter);
let counter = 0;
counter = printProjects(this.logger, this.externalProjects, counter);
counter = printProjects(this.logger, this.configuredProjects, counter);
counter = printProjects(this.logger, this.inferredProjects, counter);
info("Open files: ");
for (const rootFile of this.openFiles) {
info(`\t${rootFile.fileName}`);
}
});
this.logger.info("Open files: ");
for (const rootFile of this.openFiles) {
this.logger.info(`\t${rootFile.fileName}`);
}
this.logger.endGroup();
function printProjects(logger: Logger, projects: Project[], counter: number) {
function printProjects(projects: Project[], info: (msg: string) => void, counter: number): number {
for (const project of projects) {
project.updateGraph();
logger.info(`Project '${project.getProjectName()}' (${ProjectKind[project.projectKind]}) ${counter}`);
logger.info(project.filesToString());
logger.info("-----------------------------------------------");
info(`Project '${project.getProjectName()}' (${ProjectKind[project.projectKind]}) ${counter}`);
info(project.filesToString());
info("-----------------------------------------------");
counter++;
}
return counter;

View file

@ -170,7 +170,8 @@ namespace ts.server {
log(`Loading ${moduleName} from ${initialDir} (resolved to ${resolvedPath})`);
const result = host.require(resolvedPath, moduleName);
if (result.error) {
log(`Failed to load module: ${JSON.stringify(result.error)}`);
const err = result.error.stack || result.error.message || JSON.stringify(result.error);
log(`Failed to load module '${moduleName}': ${err}`);
return undefined;
}
return result.module;
@ -362,7 +363,7 @@ namespace ts.server {
return map(this.program.getSourceFiles(), sourceFile => {
const scriptInfo = this.projectService.getScriptInfoForPath(sourceFile.path);
if (!scriptInfo) {
Debug.assert(false, `scriptInfo for a file '${sourceFile.fileName}' is missing.`);
Debug.fail(`scriptInfo for a file '${sourceFile.fileName}' is missing.`);
}
return scriptInfo;
});
@ -494,7 +495,7 @@ namespace ts.server {
this.projectStateVersion++;
}
private extractUnresolvedImportsFromSourceFile(file: SourceFile, result: string[]) {
private extractUnresolvedImportsFromSourceFile(file: SourceFile, result: Push<string>) {
const cached = this.cachedUnresolvedImportsPerFile.get(file.path);
if (cached) {
// found cached result - use it and return
@ -554,7 +555,7 @@ namespace ts.server {
for (const sourceFile of this.program.getSourceFiles()) {
this.extractUnresolvedImportsFromSourceFile(sourceFile, result);
}
this.lastCachedUnresolvedImportsList = toSortedArray(result);
this.lastCachedUnresolvedImportsList = toDeduplicatedSortedArray(result);
}
unresolvedImports = this.lastCachedUnresolvedImportsList;
@ -936,9 +937,9 @@ namespace ts.server {
export class ConfiguredProject extends Project {
private typeAcquisition: TypeAcquisition;
private projectFileWatcher: FileWatcher;
private directoryWatcher: FileWatcher;
private directoriesWatchedForWildcards: Map<FileWatcher>;
private typeRootsWatchers: FileWatcher[];
private directoryWatcher: FileWatcher | undefined;
private directoriesWatchedForWildcards: Map<FileWatcher> | undefined;
private typeRootsWatchers: FileWatcher[] | undefined;
readonly canonicalConfigFilePath: NormalizedPath;
private plugins: PluginModule[] = [];
@ -1134,10 +1135,12 @@ namespace ts.server {
this.typeRootsWatchers = undefined;
}
this.directoriesWatchedForWildcards.forEach(watcher => {
watcher.close();
});
this.directoriesWatchedForWildcards = undefined;
if (this.directoriesWatchedForWildcards) {
this.directoriesWatchedForWildcards.forEach(watcher => {
watcher.close();
});
this.directoriesWatchedForWildcards = undefined;
}
this.stopWatchingDirectory();
}

View file

@ -15,8 +15,8 @@ namespace ts.server {
typingSafeListLocation: string;
npmLocation: string | undefined;
telemetryEnabled: boolean;
globalPlugins: string[];
pluginProbeLocations: string[];
globalPlugins: ReadonlyArray<string>;
pluginProbeLocations: ReadonlyArray<string>;
allowLocalPluginLoads: boolean;
}
@ -116,8 +116,6 @@ namespace ts.server {
birthtime: Date;
}
type RequireResult = { module: {}, error: undefined } | { module: undefined, error: {} };
const readline: {
createInterface(options: ReadLineOptions): NodeJS.EventEmitter;
} = require("readline");
@ -141,8 +139,6 @@ namespace ts.server {
class Logger implements server.Logger {
private fd = -1;
private seq = 0;
private inGroup = false;
private firstInGroup = true;
constructor(private readonly logFilename: string,
private readonly traceToConsole: boolean,
@ -172,22 +168,24 @@ namespace ts.server {
}
perftrc(s: string) {
this.msg(s, Msg.Perf);
this.msg(s, "Perf");
}
info(s: string) {
this.msg(s, Msg.Info);
this.msg(s, "Info");
}
startGroup() {
this.inGroup = true;
this.firstInGroup = true;
err(s: string) {
this.msg(s, "Err");
}
endGroup() {
this.inGroup = false;
group(logGroupEntries: (log: (msg: string) => void) => void) {
let firstInGroup = false;
logGroupEntries(s => {
this.msg(s, "Info", /*inGroup*/ true, firstInGroup);
firstInGroup = false;
});
this.seq++;
this.firstInGroup = true;
}
loggingEnabled() {
@ -198,26 +196,32 @@ namespace ts.server {
return this.loggingEnabled() && this.level >= level;
}
msg(s: string, type: Msg.Types = Msg.Err) {
if (this.fd >= 0 || this.traceToConsole) {
s = `[${nowString()}] ${s}\n`;
private msg(s: string, type: string, inGroup = false, firstInGroup = false) {
if (!this.canWrite) return;
s = `[${nowString()}] ${s}\n`;
if (!inGroup || firstInGroup) {
const prefix = Logger.padStringRight(type + " " + this.seq.toString(), " ");
if (this.firstInGroup) {
s = prefix + s;
this.firstInGroup = false;
}
if (!this.inGroup) {
this.seq++;
this.firstInGroup = true;
}
if (this.fd >= 0) {
const buf = new Buffer(s);
// tslint:disable-next-line no-null-keyword
fs.writeSync(this.fd, buf, 0, buf.length, /*position*/ null);
}
if (this.traceToConsole) {
console.warn(s);
}
s = prefix + s;
}
this.write(s);
if (!inGroup) {
this.seq++;
}
}
private get canWrite() {
return this.fd >= 0 || this.traceToConsole;
}
private write(s: string) {
if (this.fd >= 0) {
const buf = new Buffer(s);
// tslint:disable-next-line no-null-keyword
fs.writeSync(this.fd, buf, 0, buf.length, /*position*/ null);
}
if (this.traceToConsole) {
console.warn(s);
}
}
}
@ -757,11 +761,21 @@ namespace ts.server {
validateLocaleAndSetLanguage(localeStr, sys);
}
setStackTraceLimit();
const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation);
const npmLocation = findArgument(Arguments.NpmLocation);
const globalPlugins = (findArgument("--globalPlugins") || "").split(",");
const pluginProbeLocations = (findArgument("--pluginProbeLocations") || "").split(",");
function parseStringArray(argName: string): ReadonlyArray<string> {
const arg = findArgument(argName);
if (arg === undefined) {
return emptyArray;
}
return arg.split(",").filter(name => name !== "");
}
const globalPlugins = parseStringArray("--globalPlugins");
const pluginProbeLocations = parseStringArray("--pluginProbeLocations");
const allowLocalPluginLoads = hasArgument("--allowLocalPluginLoads");
const useSingleInferredProject = hasArgument("--useSingleInferredProject");

View file

@ -163,26 +163,22 @@ namespace ts.server {
* Scheduling is done via instance of NextStep. If on current step subsequent step was not scheduled - operation is assumed to be completed.
*/
class MultistepOperation implements NextStep {
private requestId: number;
private requestId: number | undefined;
private timerHandle: any;
private immediateId: any;
private completed = true;
private immediateId: number | undefined;
constructor(private readonly operationHost: MultistepOperationHost) {}
public startNew(action: (next: NextStep) => void) {
this.complete();
this.requestId = this.operationHost.getCurrentRequestId();
this.completed = false;
this.executeAction(action);
}
private complete() {
if (!this.completed) {
if (this.requestId) {
this.operationHost.sendRequestCompletedEvent(this.requestId);
}
this.completed = true;
if (this.requestId !== undefined) {
this.operationHost.sendRequestCompletedEvent(this.requestId);
this.requestId = undefined;
}
this.setTimerHandle(undefined);
this.setImmediateId(undefined);
@ -259,8 +255,8 @@ namespace ts.server {
eventHandler?: ProjectServiceEventHandler;
throttleWaitMilliseconds?: number;
globalPlugins?: string[];
pluginProbeLocations?: string[];
globalPlugins?: ReadonlyArray<string>;
pluginProbeLocations?: ReadonlyArray<string>;
allowLocalPluginLoads?: boolean;
}
@ -337,7 +333,7 @@ namespace ts.server {
case ContextEvent:
const { project, fileName } = event.data;
this.projectService.logger.info(`got context event, updating diagnostics for ${fileName}`);
this.errorCheck.startNew(next => this.updateErrorCheck(next, [{ fileName, project }], this.changeSeq, (n) => n === this.changeSeq, 100));
this.errorCheck.startNew(next => this.updateErrorCheck(next, [{ fileName, project }], 100));
break;
case ConfigFileDiagEvent:
const { triggerFile, configFileName, diagnostics } = event.data;
@ -370,7 +366,7 @@ namespace ts.server {
msg += "\n" + (<StackTraceError>err).stack;
}
}
this.logger.msg(msg, Msg.Err);
this.logger.err(msg);
}
public send(msg: protocol.Message) {
@ -453,22 +449,23 @@ namespace ts.server {
}
}
private updateProjectStructure(seq: number, matchSeq: (seq: number) => boolean, ms = 1500) {
private updateProjectStructure() {
const ms = 1500;
const seq = this.changeSeq;
this.host.setTimeout(() => {
if (matchSeq(seq)) {
if (this.changeSeq === seq) {
this.projectService.refreshInferredProjects();
}
}, ms);
}
private updateErrorCheck(next: NextStep, checkList: PendingErrorCheck[], seq: number, matchSeq: (seq: number) => boolean, ms = 1500, followMs = 200, requireOpen = true) {
if (followMs > ms) {
followMs = ms;
}
private updateErrorCheck(next: NextStep, checkList: PendingErrorCheck[], ms: number, requireOpen = true) {
const seq = this.changeSeq;
const followMs = Math.min(ms, 200);
let index = 0;
const checkOne = () => {
if (matchSeq(seq)) {
if (this.changeSeq === seq) {
const checkSpec = checkList[index];
index++;
if (checkSpec.project.containsFile(checkSpec.fileName, requireOpen)) {
@ -483,7 +480,7 @@ namespace ts.server {
}
};
if ((checkList.length > index) && (matchSeq(seq))) {
if (checkList.length > index && this.changeSeq === seq) {
next.delay(ms, checkOne);
}
}
@ -1262,14 +1259,14 @@ namespace ts.server {
}
private getDiagnostics(next: NextStep, delay: number, fileNames: string[]): void {
const checkList = mapDefined(fileNames, uncheckedFileName => {
const checkList = mapDefined<string, PendingErrorCheck>(fileNames, uncheckedFileName => {
const fileName = toNormalizedPath(uncheckedFileName);
const project = this.projectService.getDefaultProjectForFile(fileName, /*refreshInferredProjects*/ true);
return project && { fileName, project };
});
if (checkList.length > 0) {
this.updateErrorCheck(next, checkList, this.changeSeq, (n) => n === this.changeSeq, delay);
this.updateErrorCheck(next, checkList, delay);
}
}
@ -1283,7 +1280,7 @@ namespace ts.server {
scriptInfo.editContent(start, end, args.insertString);
this.changeSeq++;
}
this.updateProjectStructure(this.changeSeq, n => n === this.changeSeq);
this.updateProjectStructure();
}
}
@ -1638,7 +1635,7 @@ namespace ts.server {
const checkList = fileNamesInProject.map(fileName => ({ fileName, project }));
// Project level error analysis runs on background files too, therefore
// doesn't require the file to be opened
this.updateErrorCheck(next, checkList, this.changeSeq, (n) => n === this.changeSeq, delay, 200, /*requireOpen*/ false);
this.updateErrorCheck(next, checkList, delay, /*requireOpen*/ false);
}
}
@ -1949,7 +1946,7 @@ namespace ts.server {
return this.executeWithRequestId(request.seq, () => handler(request));
}
else {
this.logger.msg(`Unrecognized JSON command: ${JSON.stringify(request)}`, Msg.Err);
this.logger.err(`Unrecognized JSON command: ${JSON.stringify(request)}`);
this.output(undefined, CommandNames.Unknown, request.seq, `Unrecognized JSON command: ${request.command}`);
return { responseRequired: false };
}

View file

@ -9,7 +9,7 @@ declare namespace ts.server {
data: any;
}
type RequireResult = { module: {}, error: undefined } | { module: undefined, error: {} };
type RequireResult = { module: {}, error: undefined } | { module: undefined, error: { stack?: string, message?: string } };
export interface ServerHost extends System {
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
clearTimeout(timeoutId: any): void;

View file

@ -17,22 +17,11 @@ namespace ts.server {
loggingEnabled(): boolean;
perftrc(s: string): void;
info(s: string): void;
startGroup(): void;
endGroup(): void;
msg(s: string, type?: Msg.Types): void;
err(s: string): void;
group(logGroupEntries: (log: (msg: string) => void) => void): void;
getLogFileName(): string;
}
export namespace Msg {
export type Err = "Err";
export const Err: Err = "Err";
export type Info = "Info";
export const Info: Info = "Info";
export type Perf = "Perf";
export const Perf: Perf = "Perf";
export type Types = Err | Info | Perf;
}
function getProjectRootPath(project: Project): Path {
switch (project.projectKind) {
case ProjectKind.Configured:
@ -262,6 +251,15 @@ namespace ts.server {
return arr as SortedArray<T>;
}
export function toDeduplicatedSortedArray(arr: string[]): SortedArray<string> {
arr.sort();
filterMutate(arr, isNonDuplicateInSortedArray);
return arr as SortedArray<string>;
}
function isNonDuplicateInSortedArray<T>(value: T, index: number, array: T[]) {
return index === 0 || value !== array[index - 1];
}
export function enumerateInsertsAndDeletes<T>(newItems: SortedReadonlyArray<T>, oldItems: SortedReadonlyArray<T>, inserted: (newItem: T) => void, deleted: (oldItem: T) => void, compare?: Comparer<T>) {
compare = compare || compareValues;
let newIndex = 0;

View file

@ -260,11 +260,11 @@ namespace ts {
templateStack.pop();
}
else {
Debug.assert(token === SyntaxKind.TemplateMiddle, "Should have been a template middle. Was " + token);
Debug.assertEqual(token, SyntaxKind.TemplateMiddle, "Should have been a template middle.");
}
}
else {
Debug.assert(lastTemplateStackToken === SyntaxKind.OpenBraceToken, "Should have been an open brace. Was: " + token);
Debug.assertEqual(lastTemplateStackToken, SyntaxKind.OpenBraceToken, "Should have been an open brace");
templateStack.pop();
}
}

View file

@ -1000,7 +1000,7 @@ namespace ts.Completions {
const typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
if (!typeForObject) return false;
// In a binding pattern, get only known properties. Everywhere else we will get all possible properties.
typeMembers = typeChecker.getPropertiesOfType(typeForObject);
typeMembers = typeChecker.getPropertiesOfType(typeForObject).filter((symbol) => !(getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.NonPublicAccessibilityModifier));
existingMembers = (<ObjectBindingPattern>objectLikeContainer).elements;
}
}

View file

@ -195,6 +195,7 @@ namespace ts.formatting {
// Insert space after opening and before closing nonempty parenthesis
public SpaceAfterOpenParen: Rule;
public SpaceBeforeCloseParen: Rule;
public SpaceBetweenOpenParens: Rule;
public NoSpaceBetweenParens: Rule;
public NoSpaceAfterOpenParen: Rule;
public NoSpaceBeforeCloseParen: Rule;
@ -457,6 +458,7 @@ namespace ts.formatting {
// Insert space after opening and before closing nonempty parenthesis
this.SpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.SpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.SpaceBetweenOpenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.NoSpaceBetweenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
@ -544,7 +546,7 @@ namespace ts.formatting {
this.SpaceAfterComma, this.NoSpaceAfterComma,
this.SpaceAfterAnonymousFunctionKeyword, this.NoSpaceAfterAnonymousFunctionKeyword,
this.SpaceAfterKeywordInControl, this.NoSpaceAfterKeywordInControl,
this.SpaceAfterOpenParen, this.SpaceBeforeCloseParen, this.NoSpaceBetweenParens, this.NoSpaceAfterOpenParen, this.NoSpaceBeforeCloseParen,
this.SpaceAfterOpenParen, this.SpaceBeforeCloseParen, this.SpaceBetweenOpenParens, this.NoSpaceBetweenParens, this.NoSpaceAfterOpenParen, this.NoSpaceBeforeCloseParen,
this.SpaceAfterOpenBracket, this.SpaceBeforeCloseBracket, this.NoSpaceBetweenBrackets, this.NoSpaceAfterOpenBracket, this.NoSpaceBeforeCloseBracket,
this.SpaceAfterOpenBrace, this.SpaceBeforeCloseBrace, this.NoSpaceBetweenEmptyBraceBrackets, this.NoSpaceAfterOpenBrace, this.NoSpaceBeforeCloseBrace,
this.SpaceAfterTemplateHeadAndMiddle, this.SpaceBeforeTemplateMiddleAndTail, this.NoSpaceAfterTemplateHeadAndMiddle, this.NoSpaceBeforeTemplateMiddleAndTail,

View file

@ -35,7 +35,7 @@ namespace ts.JsTyping {
"crypto", "stream", "util", "assert", "tty", "domain",
"constants", "process", "v8", "timers", "console"];
const nodeCoreModules = arrayToMap(<string[]>nodeCoreModuleList, x => x);
const nodeCoreModules = arrayToSet(nodeCoreModuleList);
/**
* A map of loose file names to library names that we are confident require typings

View file

@ -1258,7 +1258,7 @@ namespace ts {
// We do not support the scenario where a host can modify a registered
// file's script kind, i.e. in one project some file is treated as ".ts"
// and in another as ".js"
Debug.assert(hostFileInformation.scriptKind === oldSourceFile.scriptKind, "Registered script kind (" + oldSourceFile.scriptKind + ") should match new script kind (" + hostFileInformation.scriptKind + ") for file: " + path);
Debug.assertEqual(hostFileInformation.scriptKind, oldSourceFile.scriptKind, "Registered script kind should match new script kind.", path);
return documentRegistry.updateDocumentWithKey(fileName, path, newSettings, documentRegistryBucketKey, hostFileInformation.scriptSnapshot, hostFileInformation.version, hostFileInformation.scriptKind);
}

View file

@ -136,7 +136,9 @@ namespace ts.SignatureHelp {
const kind = invocation.typeArguments && invocation.typeArguments.pos === list.pos ? ArgumentListKind.TypeArguments : ArgumentListKind.CallArguments;
const argumentCount = getArgumentCount(list);
Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`);
if (argumentIndex !== 0) {
Debug.assertLessThan(argumentIndex, argumentCount);
}
const argumentsSpan = getApplicableSpanForArguments(list, sourceFile);
return { kind, invocation, argumentsSpan, argumentIndex, argumentCount };
}
@ -270,7 +272,9 @@ namespace ts.SignatureHelp {
? 1
: (<TemplateExpression>tagExpression.template).templateSpans.length + 1;
Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`);
if (argumentIndex !== 0) {
Debug.assertLessThan(argumentIndex, argumentCount);
}
return {
kind: ArgumentListKind.TaggedTemplateArguments,
invocation: tagExpression,
@ -402,7 +406,9 @@ namespace ts.SignatureHelp {
};
});
Debug.assert(argumentIndex === 0 || argumentIndex < argumentCount, `argumentCount < argumentIndex, ${argumentCount} < ${argumentIndex}`);
if (argumentIndex !== 0) {
Debug.assertLessThan(argumentIndex, argumentCount);
}
const selectedItemIndex = candidates.indexOf(resolvedSignature);
Debug.assert(selectedItemIndex !== -1); // If candidates is non-empty it should always include bestSignature. We check for an empty candidates before calling this function.

View file

@ -78,11 +78,11 @@ namespace ts {
getSourceFile: (fileName) => fileName === normalizePath(inputFileName) ? sourceFile : undefined,
writeFile: (name, text) => {
if (fileExtensionIs(name, ".map")) {
Debug.assert(sourceMapText === undefined, `Unexpected multiple source map outputs for the file '${name}'`);
Debug.assertEqual(sourceMapText, undefined, "Unexpected multiple source map outputs, file:", name);
sourceMapText = text;
}
else {
Debug.assert(outputText === undefined, `Unexpected multiple outputs for the file: '${name}'`);
Debug.assertEqual(outputText, undefined, "Unexpected multiple outputs, file:", name);
outputText = text;
}
},

View file

@ -1,8 +1,11 @@
tests/cases/compiler/anyIndexedAccessArrayNoException.ts(1,12): error TS1122: A tuple type element list cannot be empty.
tests/cases/compiler/anyIndexedAccessArrayNoException.ts(1,12): error TS2538: Type '[]' cannot be used as an index type.
==== tests/cases/compiler/anyIndexedAccessArrayNoException.ts (1 errors) ====
==== tests/cases/compiler/anyIndexedAccessArrayNoException.ts (2 errors) ====
var x: any[[]];
~~
!!! error TS1122: A tuple type element list cannot be empty.
~~
!!! error TS2538: Type '[]' cannot be used as an index type.

View file

@ -0,0 +1,13 @@
tests/cases/compiler/checkTypePredicateForRedundantProperties.ts(1,35): error TS2300: Duplicate identifier 'a'.
tests/cases/compiler/checkTypePredicateForRedundantProperties.ts(1,46): error TS2300: Duplicate identifier 'a'.
==== tests/cases/compiler/checkTypePredicateForRedundantProperties.ts (2 errors) ====
function addProp2(x: any): x is { a: string; a: string; } {
~
!!! error TS2300: Duplicate identifier 'a'.
~
!!! error TS2300: Duplicate identifier 'a'.
return true;
}

View file

@ -0,0 +1,10 @@
//// [checkTypePredicateForRedundantProperties.ts]
function addProp2(x: any): x is { a: string; a: string; } {
return true;
}
//// [checkTypePredicateForRedundantProperties.js]
function addProp2(x) {
return true;
}

View file

@ -0,0 +1,25 @@
//// [commentOnBinaryOperator1.ts]
var a = 'some'
// comment
+ 'text';
var b = 'some'
/* comment */
+ 'text';
var c = 'some'
/* comment */
+ /*comment1*/
'text';
//// [commentOnBinaryOperator1.js]
var a = 'some'
// comment
+ 'text';
var b = 'some'
/* comment */
+ 'text';
var c = 'some'
/* comment */
+/*comment1*/
'text';

View file

@ -0,0 +1,19 @@
=== tests/cases/compiler/commentOnBinaryOperator1.ts ===
var a = 'some'
>a : Symbol(a, Decl(commentOnBinaryOperator1.ts, 0, 3))
// comment
+ 'text';
var b = 'some'
>b : Symbol(b, Decl(commentOnBinaryOperator1.ts, 4, 3))
/* comment */
+ 'text';
var c = 'some'
>c : Symbol(c, Decl(commentOnBinaryOperator1.ts, 8, 3))
/* comment */
+ /*comment1*/
'text';

View file

@ -0,0 +1,29 @@
=== tests/cases/compiler/commentOnBinaryOperator1.ts ===
var a = 'some'
>a : string
>'some' // comment + 'text' : string
>'some' : "some"
// comment
+ 'text';
>'text' : "text"
var b = 'some'
>b : string
>'some' /* comment */ + 'text' : string
>'some' : "some"
/* comment */
+ 'text';
>'text' : "text"
var c = 'some'
>c : string
>'some' /* comment */ + /*comment1*/ 'text' : string
>'some' : "some"
/* comment */
+ /*comment1*/
'text';
>'text' : "text"

View file

@ -0,0 +1,22 @@
//// [commentOnBinaryOperator2.ts]
var a = 'some'
// comment
+ 'text';
var b = 'some'
/* comment */
+ 'text';
var c = 'some'
/* comment */
+ /*comment1*/
'text';
//// [commentOnBinaryOperator2.js]
var a = 'some'
+ 'text';
var b = 'some'
+ 'text';
var c = 'some'
+
'text';

View file

@ -0,0 +1,19 @@
=== tests/cases/compiler/commentOnBinaryOperator2.ts ===
var a = 'some'
>a : Symbol(a, Decl(commentOnBinaryOperator2.ts, 0, 3))
// comment
+ 'text';
var b = 'some'
>b : Symbol(b, Decl(commentOnBinaryOperator2.ts, 4, 3))
/* comment */
+ 'text';
var c = 'some'
>c : Symbol(c, Decl(commentOnBinaryOperator2.ts, 8, 3))
/* comment */
+ /*comment1*/
'text';

View file

@ -0,0 +1,29 @@
=== tests/cases/compiler/commentOnBinaryOperator2.ts ===
var a = 'some'
>a : string
>'some' // comment + 'text' : string
>'some' : "some"
// comment
+ 'text';
>'text' : "text"
var b = 'some'
>b : string
>'some' /* comment */ + 'text' : string
>'some' : "some"
/* comment */
+ 'text';
>'text' : "text"
var c = 'some'
>c : string
>'some' /* comment */ + /*comment1*/ 'text' : string
>'some' : "some"
/* comment */
+ /*comment1*/
'text';
>'text' : "text"

View file

@ -14,7 +14,7 @@ foo(
function foo(/*c1*/ x, /*d1*/ y, /*e1*/ w) { }
var a, b;
foo(/*c2*/ 1, /*d2*/ 1 + 2, /*e1*/ a + b);
foo(/*c3*/ function () { }, /*d2*/ function () { }, /*e2*/ a + b);
foo(/*c3*/ function () { }, /*d2*/ function () { }, /*e2*/ a +/*e3*/ b);
foo(/*c3*/ function () { }, /*d3*/ function () { }, /*e3*/ (a + b));
foo(
/*c4*/ function () { },

View file

@ -0,0 +1,64 @@
//// [deferredLookupTypeResolution.ts]
// Repro from #17456
type StringContains<S extends string, L extends string> = (
{ [K in S]: 'true' } &
{ [key: string]: 'false' }
)[L]
type ObjectHasKey<O, L extends string> = StringContains<keyof O, L>
type First<T> = ObjectHasKey<T, '0'>; // Should be deferred
type T1 = ObjectHasKey<{ a: string }, 'a'>; // 'true'
type T2 = ObjectHasKey<{ a: string }, 'b'>; // 'false'
// Verify that mapped type isn't eagerly resolved in type-to-string operation
declare function f1<A extends string, B extends string>(a: A, b: B): { [P in A | B]: any };
function f2<A extends string>(a: A) {
return f1(a, 'x');
}
function f3(x: 'a' | 'b') {
return f2(x);
}
//// [deferredLookupTypeResolution.js]
"use strict";
// Repro from #17456
function f2(a) {
return f1(a, 'x');
}
function f3(x) {
return f2(x);
}
//// [deferredLookupTypeResolution.d.ts]
declare type StringContains<S extends string, L extends string> = ({
[K in S]: 'true';
} & {
[key: string]: 'false';
})[L];
declare type ObjectHasKey<O, L extends string> = StringContains<keyof O, L>;
declare type First<T> = ObjectHasKey<T, '0'>;
declare type T1 = ObjectHasKey<{
a: string;
}, 'a'>;
declare type T2 = ObjectHasKey<{
a: string;
}, 'b'>;
declare function f1<A extends string, B extends string>(a: A, b: B): {
[P in A | B]: any;
};
declare function f2<A extends string>(a: A): {
[P in A | "x"]: any;
};
declare function f3(x: 'a' | 'b'): {
a: any;
b: any;
x: any;
};

View file

@ -0,0 +1,76 @@
=== tests/cases/compiler/deferredLookupTypeResolution.ts ===
// Repro from #17456
type StringContains<S extends string, L extends string> = (
>StringContains : Symbol(StringContains, Decl(deferredLookupTypeResolution.ts, 0, 0))
>S : Symbol(S, Decl(deferredLookupTypeResolution.ts, 2, 20))
>L : Symbol(L, Decl(deferredLookupTypeResolution.ts, 2, 37))
{ [K in S]: 'true' } &
>K : Symbol(K, Decl(deferredLookupTypeResolution.ts, 3, 7))
>S : Symbol(S, Decl(deferredLookupTypeResolution.ts, 2, 20))
{ [key: string]: 'false' }
>key : Symbol(key, Decl(deferredLookupTypeResolution.ts, 4, 7))
)[L]
>L : Symbol(L, Decl(deferredLookupTypeResolution.ts, 2, 37))
type ObjectHasKey<O, L extends string> = StringContains<keyof O, L>
>ObjectHasKey : Symbol(ObjectHasKey, Decl(deferredLookupTypeResolution.ts, 5, 6))
>O : Symbol(O, Decl(deferredLookupTypeResolution.ts, 7, 18))
>L : Symbol(L, Decl(deferredLookupTypeResolution.ts, 7, 20))
>StringContains : Symbol(StringContains, Decl(deferredLookupTypeResolution.ts, 0, 0))
>O : Symbol(O, Decl(deferredLookupTypeResolution.ts, 7, 18))
>L : Symbol(L, Decl(deferredLookupTypeResolution.ts, 7, 20))
type First<T> = ObjectHasKey<T, '0'>; // Should be deferred
>First : Symbol(First, Decl(deferredLookupTypeResolution.ts, 7, 67))
>T : Symbol(T, Decl(deferredLookupTypeResolution.ts, 9, 11))
>ObjectHasKey : Symbol(ObjectHasKey, Decl(deferredLookupTypeResolution.ts, 5, 6))
>T : Symbol(T, Decl(deferredLookupTypeResolution.ts, 9, 11))
type T1 = ObjectHasKey<{ a: string }, 'a'>; // 'true'
>T1 : Symbol(T1, Decl(deferredLookupTypeResolution.ts, 9, 37))
>ObjectHasKey : Symbol(ObjectHasKey, Decl(deferredLookupTypeResolution.ts, 5, 6))
>a : Symbol(a, Decl(deferredLookupTypeResolution.ts, 11, 24))
type T2 = ObjectHasKey<{ a: string }, 'b'>; // 'false'
>T2 : Symbol(T2, Decl(deferredLookupTypeResolution.ts, 11, 43))
>ObjectHasKey : Symbol(ObjectHasKey, Decl(deferredLookupTypeResolution.ts, 5, 6))
>a : Symbol(a, Decl(deferredLookupTypeResolution.ts, 12, 24))
// Verify that mapped type isn't eagerly resolved in type-to-string operation
declare function f1<A extends string, B extends string>(a: A, b: B): { [P in A | B]: any };
>f1 : Symbol(f1, Decl(deferredLookupTypeResolution.ts, 12, 43))
>A : Symbol(A, Decl(deferredLookupTypeResolution.ts, 16, 20))
>B : Symbol(B, Decl(deferredLookupTypeResolution.ts, 16, 37))
>a : Symbol(a, Decl(deferredLookupTypeResolution.ts, 16, 56))
>A : Symbol(A, Decl(deferredLookupTypeResolution.ts, 16, 20))
>b : Symbol(b, Decl(deferredLookupTypeResolution.ts, 16, 61))
>B : Symbol(B, Decl(deferredLookupTypeResolution.ts, 16, 37))
>P : Symbol(P, Decl(deferredLookupTypeResolution.ts, 16, 72))
>A : Symbol(A, Decl(deferredLookupTypeResolution.ts, 16, 20))
>B : Symbol(B, Decl(deferredLookupTypeResolution.ts, 16, 37))
function f2<A extends string>(a: A) {
>f2 : Symbol(f2, Decl(deferredLookupTypeResolution.ts, 16, 91))
>A : Symbol(A, Decl(deferredLookupTypeResolution.ts, 18, 12))
>a : Symbol(a, Decl(deferredLookupTypeResolution.ts, 18, 30))
>A : Symbol(A, Decl(deferredLookupTypeResolution.ts, 18, 12))
return f1(a, 'x');
>f1 : Symbol(f1, Decl(deferredLookupTypeResolution.ts, 12, 43))
>a : Symbol(a, Decl(deferredLookupTypeResolution.ts, 18, 30))
}
function f3(x: 'a' | 'b') {
>f3 : Symbol(f3, Decl(deferredLookupTypeResolution.ts, 20, 1))
>x : Symbol(x, Decl(deferredLookupTypeResolution.ts, 22, 12))
return f2(x);
>f2 : Symbol(f2, Decl(deferredLookupTypeResolution.ts, 16, 91))
>x : Symbol(x, Decl(deferredLookupTypeResolution.ts, 22, 12))
}

View file

@ -0,0 +1,79 @@
=== tests/cases/compiler/deferredLookupTypeResolution.ts ===
// Repro from #17456
type StringContains<S extends string, L extends string> = (
>StringContains : ({ [K in S]: "true"; } & { [key: string]: "false"; })[L]
>S : S
>L : L
{ [K in S]: 'true' } &
>K : K
>S : S
{ [key: string]: 'false' }
>key : string
)[L]
>L : L
type ObjectHasKey<O, L extends string> = StringContains<keyof O, L>
>ObjectHasKey : ({ [K in S]: "true"; } & { [key: string]: "false"; })[L]
>O : O
>L : L
>StringContains : ({ [K in S]: "true"; } & { [key: string]: "false"; })[L]
>O : O
>L : L
type First<T> = ObjectHasKey<T, '0'>; // Should be deferred
>First : ({ [K in S]: "true"; } & { [key: string]: "false"; })["0"]
>T : T
>ObjectHasKey : ({ [K in S]: "true"; } & { [key: string]: "false"; })[L]
>T : T
type T1 = ObjectHasKey<{ a: string }, 'a'>; // 'true'
>T1 : "true"
>ObjectHasKey : ({ [K in S]: "true"; } & { [key: string]: "false"; })[L]
>a : string
type T2 = ObjectHasKey<{ a: string }, 'b'>; // 'false'
>T2 : "false"
>ObjectHasKey : ({ [K in S]: "true"; } & { [key: string]: "false"; })[L]
>a : string
// Verify that mapped type isn't eagerly resolved in type-to-string operation
declare function f1<A extends string, B extends string>(a: A, b: B): { [P in A | B]: any };
>f1 : <A extends string, B extends string>(a: A, b: B) => { [P in A | B]: any; }
>A : A
>B : B
>a : A
>A : A
>b : B
>B : B
>P : P
>A : A
>B : B
function f2<A extends string>(a: A) {
>f2 : <A extends string>(a: A) => { [P in A | B]: any; }
>A : A
>a : A
>A : A
return f1(a, 'x');
>f1(a, 'x') : { [P in A | B]: any; }
>f1 : <A extends string, B extends string>(a: A, b: B) => { [P in A | B]: any; }
>a : A
>'x' : "x"
}
function f3(x: 'a' | 'b') {
>f3 : (x: "a" | "b") => { a: any; b: any; x: any; }
>x : "a" | "b"
return f2(x);
>f2(x) : { a: any; b: any; x: any; }
>f2 : <A extends string>(a: A) => { [P in A | B]: any; }
>x : "a" | "b"
}

View file

@ -0,0 +1,31 @@
tests/cases/compiler/deferredLookupTypeResolution2.ts(14,13): error TS2536: Type '({ [K in S]: "true"; } & { [key: string]: "false"; })["1"]' cannot be used to index type '{ true: "true"; }'.
tests/cases/compiler/deferredLookupTypeResolution2.ts(19,21): error TS2536: Type '({ true: "otherwise"; } & { [k: string]: "true"; })[({ [K in S]: "true"; } & { [key: string]: "false"; })["1"]]' cannot be used to index type '{ true: "true"; }'.
==== tests/cases/compiler/deferredLookupTypeResolution2.ts (2 errors) ====
// Repro from #17456
type StringContains<S extends string, L extends string> = ({ [K in S]: 'true' } & { [key: string]: 'false'})[L];
type ObjectHasKey<O, L extends string> = StringContains<keyof O, L>;
type A<T> = ObjectHasKey<T, '0'>;
type B = ObjectHasKey<[string, number], '1'>; // "true"
type C = ObjectHasKey<[string, number], '2'>; // "false"
type D = A<[string]>; // "true"
// Error, "false" not handled
type E<T> = { true: 'true' }[ObjectHasKey<T, '1'>];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2536: Type '({ [K in S]: "true"; } & { [key: string]: "false"; })["1"]' cannot be used to index type '{ true: "true"; }'.
type Juxtapose<T> = ({ true: 'otherwise' } & { [k: string]: 'true' })[ObjectHasKey<T, '1'>];
// Error, "otherwise" is missing
type DeepError<T> = { true: 'true' }[Juxtapose<T>];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2536: Type '({ true: "otherwise"; } & { [k: string]: "true"; })[({ [K in S]: "true"; } & { [key: string]: "false"; })["1"]]' cannot be used to index type '{ true: "true"; }'.
type DeepOK<T> = { true: 'true', otherwise: 'false' }[Juxtapose<T>];

View file

@ -0,0 +1,55 @@
//// [deferredLookupTypeResolution2.ts]
// Repro from #17456
type StringContains<S extends string, L extends string> = ({ [K in S]: 'true' } & { [key: string]: 'false'})[L];
type ObjectHasKey<O, L extends string> = StringContains<keyof O, L>;
type A<T> = ObjectHasKey<T, '0'>;
type B = ObjectHasKey<[string, number], '1'>; // "true"
type C = ObjectHasKey<[string, number], '2'>; // "false"
type D = A<[string]>; // "true"
// Error, "false" not handled
type E<T> = { true: 'true' }[ObjectHasKey<T, '1'>];
type Juxtapose<T> = ({ true: 'otherwise' } & { [k: string]: 'true' })[ObjectHasKey<T, '1'>];
// Error, "otherwise" is missing
type DeepError<T> = { true: 'true' }[Juxtapose<T>];
type DeepOK<T> = { true: 'true', otherwise: 'false' }[Juxtapose<T>];
//// [deferredLookupTypeResolution2.js]
"use strict";
// Repro from #17456
//// [deferredLookupTypeResolution2.d.ts]
declare type StringContains<S extends string, L extends string> = ({
[K in S]: 'true';
} & {
[key: string]: 'false';
})[L];
declare type ObjectHasKey<O, L extends string> = StringContains<keyof O, L>;
declare type A<T> = ObjectHasKey<T, '0'>;
declare type B = ObjectHasKey<[string, number], '1'>;
declare type C = ObjectHasKey<[string, number], '2'>;
declare type D = A<[string]>;
declare type E<T> = {
true: 'true';
}[ObjectHasKey<T, '1'>];
declare type Juxtapose<T> = ({
true: 'otherwise';
} & {
[k: string]: 'true';
})[ObjectHasKey<T, '1'>];
declare type DeepError<T> = {
true: 'true';
}[Juxtapose<T>];
declare type DeepOK<T> = {
true: 'true';
otherwise: 'false';
}[Juxtapose<T>];

View file

@ -0,0 +1,11 @@
//// [doNotInferUnrelatedTypes.ts]
// #16709
declare function dearray<T>(ara: ReadonlyArray<T>): T;
type LiteralType = "foo" | "bar";
declare var alt: Array<LiteralType>;
let foo: LiteralType = dearray(alt);
//// [doNotInferUnrelatedTypes.js]
var foo = dearray(alt);

View file

@ -0,0 +1,24 @@
=== tests/cases/compiler/doNotInferUnrelatedTypes.ts ===
// #16709
declare function dearray<T>(ara: ReadonlyArray<T>): T;
>dearray : Symbol(dearray, Decl(doNotInferUnrelatedTypes.ts, 0, 0))
>T : Symbol(T, Decl(doNotInferUnrelatedTypes.ts, 1, 25))
>ara : Symbol(ara, Decl(doNotInferUnrelatedTypes.ts, 1, 28))
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.d.ts, --, --))
>T : Symbol(T, Decl(doNotInferUnrelatedTypes.ts, 1, 25))
>T : Symbol(T, Decl(doNotInferUnrelatedTypes.ts, 1, 25))
type LiteralType = "foo" | "bar";
>LiteralType : Symbol(LiteralType, Decl(doNotInferUnrelatedTypes.ts, 1, 54))
declare var alt: Array<LiteralType>;
>alt : Symbol(alt, Decl(doNotInferUnrelatedTypes.ts, 3, 11))
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>LiteralType : Symbol(LiteralType, Decl(doNotInferUnrelatedTypes.ts, 1, 54))
let foo: LiteralType = dearray(alt);
>foo : Symbol(foo, Decl(doNotInferUnrelatedTypes.ts, 5, 3))
>LiteralType : Symbol(LiteralType, Decl(doNotInferUnrelatedTypes.ts, 1, 54))
>dearray : Symbol(dearray, Decl(doNotInferUnrelatedTypes.ts, 0, 0))
>alt : Symbol(alt, Decl(doNotInferUnrelatedTypes.ts, 3, 11))

View file

@ -0,0 +1,25 @@
=== tests/cases/compiler/doNotInferUnrelatedTypes.ts ===
// #16709
declare function dearray<T>(ara: ReadonlyArray<T>): T;
>dearray : <T>(ara: ReadonlyArray<T>) => T
>T : T
>ara : ReadonlyArray<T>
>ReadonlyArray : ReadonlyArray<T>
>T : T
>T : T
type LiteralType = "foo" | "bar";
>LiteralType : LiteralType
declare var alt: Array<LiteralType>;
>alt : LiteralType[]
>Array : T[]
>LiteralType : LiteralType
let foo: LiteralType = dearray(alt);
>foo : LiteralType
>LiteralType : LiteralType
>dearray(alt) : LiteralType
>dearray : <T>(ara: ReadonlyArray<T>) => T
>alt : LiteralType[]

View file

@ -113,32 +113,32 @@ var temp = 10;
(+3) ** temp++;
>(+3) ** temp++ : number
>(+3) : number
>+3 : number
>(+3) : 3
>+3 : 3
>3 : 3
>temp++ : number
>temp : number
(+3) ** temp--;
>(+3) ** temp-- : number
>(+3) : number
>+3 : number
>(+3) : 3
>+3 : 3
>3 : 3
>temp-- : number
>temp : number
(+3) ** ++temp;
>(+3) ** ++temp : number
>(+3) : number
>+3 : number
>(+3) : 3
>+3 : 3
>3 : 3
>++temp : number
>temp : number
(+3) ** --temp;
>(+3) ** --temp : number
>(+3) : number
>+3 : number
>(+3) : 3
>+3 : 3
>3 : 3
>--temp : number
>temp : number
@ -185,8 +185,8 @@ var temp = 10;
(+3) ** temp++ ** 2;
>(+3) ** temp++ ** 2 : number
>(+3) : number
>+3 : number
>(+3) : 3
>+3 : 3
>3 : 3
>temp++ ** 2 : number
>temp++ : number
@ -195,8 +195,8 @@ var temp = 10;
(+3) ** temp-- ** 2;
>(+3) ** temp-- ** 2 : number
>(+3) : number
>+3 : number
>(+3) : 3
>+3 : 3
>3 : 3
>temp-- ** 2 : number
>temp-- : number
@ -205,8 +205,8 @@ var temp = 10;
(+3) ** ++temp ** 2;
>(+3) ** ++temp ** 2 : number
>(+3) : number
>+3 : number
>(+3) : 3
>+3 : 3
>3 : 3
>++temp ** 2 : number
>++temp : number
@ -215,8 +215,8 @@ var temp = 10;
(+3) ** --temp ** 2;
>(+3) ** --temp ** 2 : number
>(+3) : number
>+3 : number
>(+3) : 3
>+3 : 3
>3 : 3
>--temp ** 2 : number
>--temp : number

View file

@ -131,7 +131,7 @@ enum E11 {
A = +0,
>A : E11
>+0 : number
>+0 : 0
>0 : 0
B,

View file

@ -0,0 +1,90 @@
tests/cases/compiler/base.d.ts(1,23): error TS1005: ',' expected.
tests/cases/compiler/base.d.ts(1,34): error TS1005: '=' expected.
tests/cases/compiler/boolean.ts(7,23): error TS1005: ',' expected.
tests/cases/compiler/boolean.ts(7,24): error TS1134: Variable declaration expected.
tests/cases/compiler/boolean.ts(11,16): error TS2304: Cannot find name 'document'.
tests/cases/compiler/boolean.ts(12,22): error TS1005: ';' expected.
tests/cases/compiler/number.ts(7,26): error TS1005: ',' expected.
tests/cases/compiler/number.ts(7,27): error TS1134: Variable declaration expected.
tests/cases/compiler/number.ts(11,16): error TS2304: Cannot find name 'document'.
tests/cases/compiler/number.ts(12,20): error TS1005: ';' expected.
tests/cases/compiler/string.ts(7,20): error TS1005: ',' expected.
tests/cases/compiler/string.ts(7,21): error TS1134: Variable declaration expected.
tests/cases/compiler/string.ts(11,15): error TS2304: Cannot find name 'document'.
tests/cases/compiler/string.ts(12,19): error TS1005: ';' expected.
==== tests/cases/compiler/base.d.ts (2 errors) ====
declare const x: "foo".charCodeAt(0);
~
!!! error TS1005: ',' expected.
~
!!! error TS1005: '=' expected.
==== tests/cases/compiler/string.ts (4 errors) ====
interface String {
typeof<T>(x: T): T;
}
class C {
foo() {
const x: "".typeof(this.foo);
~
!!! error TS1005: ',' expected.
~~~~~~
!!! error TS1134: Variable declaration expected.
}
}
const nodes = document.getElementsByTagName("li");
~~~~~~~~
!!! error TS2304: Cannot find name 'document'.
type ItemType = "".typeof(nodes.item(0));
~
!!! error TS1005: ';' expected.
==== tests/cases/compiler/number.ts (4 errors) ====
interface Number {
typeof<T>(x: T): T;
}
class C2 {
foo() {
const x: 3.141592.typeof(this.foo);
~
!!! error TS1005: ',' expected.
~~~~~~
!!! error TS1134: Variable declaration expected.
}
}
const nodes2 = document.getElementsByTagName("li");
~~~~~~~~
!!! error TS2304: Cannot find name 'document'.
type ItemType2 = 4..typeof(nodes.item(0));
~
!!! error TS1005: ';' expected.
==== tests/cases/compiler/boolean.ts (4 errors) ====
interface Boolean {
typeof<T>(x: T): T;
}
class C3 {
foo() {
const x: false.typeof(this.foo);
~
!!! error TS1005: ',' expected.
~~~~~~
!!! error TS1134: Variable declaration expected.
}
}
const nodes3 = document.getElementsByTagName("li");
~~~~~~~~
!!! error TS2304: Cannot find name 'document'.
type ItemType3 = true.typeof(nodes.item(0));
~
!!! error TS1005: ';' expected.

View file

@ -0,0 +1,85 @@
//// [tests/cases/compiler/expressionTypeNodeShouldError.ts] ////
//// [base.d.ts]
declare const x: "foo".charCodeAt(0);
//// [string.ts]
interface String {
typeof<T>(x: T): T;
}
class C {
foo() {
const x: "".typeof(this.foo);
}
}
const nodes = document.getElementsByTagName("li");
type ItemType = "".typeof(nodes.item(0));
//// [number.ts]
interface Number {
typeof<T>(x: T): T;
}
class C2 {
foo() {
const x: 3.141592.typeof(this.foo);
}
}
const nodes2 = document.getElementsByTagName("li");
type ItemType2 = 4..typeof(nodes.item(0));
//// [boolean.ts]
interface Boolean {
typeof<T>(x: T): T;
}
class C3 {
foo() {
const x: false.typeof(this.foo);
}
}
const nodes3 = document.getElementsByTagName("li");
type ItemType3 = true.typeof(nodes.item(0));
//// [string.js]
var C = (function () {
function C() {
}
C.prototype.foo = function () {
var x;
typeof (this.foo);
};
return C;
}());
var nodes = document.getElementsByTagName("li");
typeof (nodes.item(0));
//// [number.js]
var C2 = (function () {
function C2() {
}
C2.prototype.foo = function () {
var x;
typeof (this.foo);
};
return C2;
}());
var nodes2 = document.getElementsByTagName("li");
typeof (nodes.item(0));
//// [boolean.js]
var C3 = (function () {
function C3() {
}
C3.prototype.foo = function () {
var x;
typeof (this.foo);
};
return C3;
}());
var nodes3 = document.getElementsByTagName("li");
typeof (nodes.item(0));

View file

@ -0,0 +1,47 @@
tests/cases/compiler/indexSignatureAndMappedType.ts(6,5): error TS2322: Type '{ [key: string]: T; }' is not assignable to type 'Record<K, T>'.
tests/cases/compiler/indexSignatureAndMappedType.ts(15,5): error TS2322: Type 'Record<K, U>' is not assignable to type '{ [key: string]: T; }'.
Type 'U' is not assignable to type 'T'.
tests/cases/compiler/indexSignatureAndMappedType.ts(16,5): error TS2322: Type '{ [key: string]: T; }' is not assignable to type 'Record<K, U>'.
==== tests/cases/compiler/indexSignatureAndMappedType.ts (3 errors) ====
// A mapped type { [P in K]: X }, where K is a generic type, is related to
// { [key: string]: Y } if X is related to Y.
function f1<T, K extends string>(x: { [key: string]: T }, y: Record<K, T>) {
x = y;
y = x; // Error
~
!!! error TS2322: Type '{ [key: string]: T; }' is not assignable to type 'Record<K, T>'.
}
function f2<T>(x: { [key: string]: T }, y: Record<string, T>) {
x = y;
y = x;
}
function f3<T, U, K extends string>(x: { [key: string]: T }, y: Record<K, U>) {
x = y; // Error
~
!!! error TS2322: Type 'Record<K, U>' is not assignable to type '{ [key: string]: T; }'.
!!! error TS2322: Type 'U' is not assignable to type 'T'.
y = x; // Error
~
!!! error TS2322: Type '{ [key: string]: T; }' is not assignable to type 'Record<K, U>'.
}
// Repro from #14548
type Dictionary = {
[key: string]: string;
};
interface IBaseEntity {
name: string;
properties: Dictionary;
}
interface IEntity<T extends string> extends IBaseEntity {
properties: Record<T, string>;
}

View file

@ -0,0 +1,73 @@
//// [indexSignatureAndMappedType.ts]
// A mapped type { [P in K]: X }, where K is a generic type, is related to
// { [key: string]: Y } if X is related to Y.
function f1<T, K extends string>(x: { [key: string]: T }, y: Record<K, T>) {
x = y;
y = x; // Error
}
function f2<T>(x: { [key: string]: T }, y: Record<string, T>) {
x = y;
y = x;
}
function f3<T, U, K extends string>(x: { [key: string]: T }, y: Record<K, U>) {
x = y; // Error
y = x; // Error
}
// Repro from #14548
type Dictionary = {
[key: string]: string;
};
interface IBaseEntity {
name: string;
properties: Dictionary;
}
interface IEntity<T extends string> extends IBaseEntity {
properties: Record<T, string>;
}
//// [indexSignatureAndMappedType.js]
"use strict";
// A mapped type { [P in K]: X }, where K is a generic type, is related to
// { [key: string]: Y } if X is related to Y.
function f1(x, y) {
x = y;
y = x; // Error
}
function f2(x, y) {
x = y;
y = x;
}
function f3(x, y) {
x = y; // Error
y = x; // Error
}
//// [indexSignatureAndMappedType.d.ts]
declare function f1<T, K extends string>(x: {
[key: string]: T;
}, y: Record<K, T>): void;
declare function f2<T>(x: {
[key: string]: T;
}, y: Record<string, T>): void;
declare function f3<T, U, K extends string>(x: {
[key: string]: T;
}, y: Record<K, U>): void;
declare type Dictionary = {
[key: string]: string;
};
interface IBaseEntity {
name: string;
properties: Dictionary;
}
interface IEntity<T extends string> extends IBaseEntity {
properties: Record<T, string>;
}

View file

@ -0,0 +1,12 @@
=== tests/cases/compiler/index.js ===
/**
* @param {Array<*>} list
*/
function thing(list) {
>thing : Symbol(thing, Decl(index.js, 0, 0))
>list : Symbol(list, Decl(index.js, 3, 15))
return list;
>list : Symbol(list, Decl(index.js, 3, 15))
}

View file

@ -0,0 +1,12 @@
=== tests/cases/compiler/index.js ===
/**
* @param {Array<*>} list
*/
function thing(list) {
>thing : (list: any[]) => any[]
>list : any[]
return list;
>list : any[]
}

View file

@ -0,0 +1,97 @@
tests/cases/compiler/index.js(2,19): error TS2315: Type 'boolean' is not generic.
tests/cases/compiler/index2.js(2,19): error TS2315: Type 'void' is not generic.
tests/cases/compiler/index3.js(2,19): error TS2315: Type 'undefined' is not generic.
tests/cases/compiler/index4.js(2,19): error TS2315: Type 'Function' is not generic.
tests/cases/compiler/index5.js(2,19): error TS2315: Type 'string' is not generic.
tests/cases/compiler/index6.js(2,19): error TS2315: Type 'number' is not generic.
tests/cases/compiler/index7.js(2,19): error TS2315: Type 'any' is not generic.
tests/cases/compiler/index8.js(4,12): error TS2304: Cannot find name 'fn'.
tests/cases/compiler/index8.js(4,15): error TS2304: Cannot find name 'T'.
==== tests/cases/compiler/index.js (1 errors) ====
/**
* @param {<T>(m: Boolean<T>) => string} somebody
~~~~~~~~~~
!!! error TS2315: Type 'boolean' is not generic.
*/
function sayHello(somebody) {
return 'Hello ' + somebody;
}
==== tests/cases/compiler/index2.js (1 errors) ====
/**
* @param {<T>(m: Void<T>) => string} somebody
~~~~~~~
!!! error TS2315: Type 'void' is not generic.
*/
function sayHello2(somebody) {
return 'Hello ' + somebody;
}
==== tests/cases/compiler/index3.js (1 errors) ====
/**
* @param {<T>(m: Undefined<T>) => string} somebody
~~~~~~~~~~~~
!!! error TS2315: Type 'undefined' is not generic.
*/
function sayHello3(somebody) {
return 'Hello ' + somebody;
}
==== tests/cases/compiler/index4.js (1 errors) ====
/**
* @param {<T>(m: Function<T>) => string} somebody
~~~~~~~~~~~
!!! error TS2315: Type 'Function' is not generic.
*/
function sayHello4(somebody) {
return 'Hello ' + somebody;
}
==== tests/cases/compiler/index5.js (1 errors) ====
/**
* @param {<T>(m: String<T>) => string} somebody
~~~~~~~~~
!!! error TS2315: Type 'string' is not generic.
*/
function sayHello5(somebody) {
return 'Hello ' + somebody;
}
==== tests/cases/compiler/index6.js (1 errors) ====
/**
* @param {<T>(m: Number<T>) => string} somebody
~~~~~~~~~
!!! error TS2315: Type 'number' is not generic.
*/
function sayHello6(somebody) {
return 'Hello ' + somebody;
}
==== tests/cases/compiler/index7.js (1 errors) ====
/**
* @param {<T>(m: Object<T>) => string} somebody
~~~~~~~~~
!!! error TS2315: Type 'any' is not generic.
*/
function sayHello7(somebody) {
return 'Hello ' + somebody;
}
==== tests/cases/compiler/index8.js (2 errors) ====
function fn() {}
/**
* @param {fn<T>} somebody
~~
!!! error TS2304: Cannot find name 'fn'.
~
!!! error TS2304: Cannot find name 'T'.
*/
function sayHello8(somebody) { }

View file

@ -97,7 +97,7 @@ var a;
/** @type {string} */
var s;
var a = ("" + 4);
var s = "" + (4);
var s = "" +/** @type {*} */ (4);
var SomeBase = (function () {
function SomeBase() {
this.p = 42;
@ -128,19 +128,19 @@ 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);
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 = (someFakeClass);
someBase =/** @type {SomeBase} */ (someFakeClass);
// Type assertion cannot be a type-predicate type
/** @type {number | string} */
var numOrStr;

View file

@ -15,6 +15,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(35,21): error
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(36,21): error TS2538: Type 'boolean' cannot be used as an index type.
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(41,31): error TS2538: Type 'boolean' cannot be used as an index type.
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(46,16): error TS2538: Type 'boolean' cannot be used as an index type.
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(49,12): error TS1122: A tuple type element list cannot be empty.
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(63,33): error TS2345: Argument of type '"size"' is not assignable to parameter of type '"name" | "width" | "height" | "visible"'.
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(64,33): error TS2345: Argument of type '"name" | "size"' is not assignable to parameter of type '"name" | "width" | "height" | "visible"'.
Type '"size"' is not assignable to type '"name" | "width" | "height" | "visible"'.
@ -28,7 +29,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(76,5): error
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(77,5): error TS2322: Type 'keyof (T & U)' is not assignable to type 'keyof (T | U)'.
==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (24 errors) ====
==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (25 errors) ====
class Shape {
name: string;
width: number;
@ -112,6 +113,8 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(77,5): error
type T60 = {}["toString"];
type T61 = []["toString"];
~~
!!! error TS1122: A tuple type element list cannot be empty.
declare let cond: boolean;

View file

@ -0,0 +1,35 @@
tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(9,30): error TS2536: Type 'K' cannot be used to index type 'T1<K>'.
tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(13,30): error TS2536: Type 'K' cannot be used to index type 'T3'.
tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(15,47): error TS2536: Type 'S' cannot be used to index type 'AB'.
tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(17,49): error TS2536: Type 'L' cannot be used to index type '{ [key in AB[S]]: true; }'.
==== tests/cases/conformance/types/mapped/mappedTypeErrors2.ts (4 errors) ====
// Repros from #17238
type AB = {
a: 'a'
b: 'a'
};
type T1<K extends keyof AB> = { [key in AB[K]]: true };
type T2<K extends 'a'|'b'> = T1<K>[K]; // Error
~~~~~~~~
!!! error TS2536: Type 'K' cannot be used to index type 'T1<K>'.
type R = AB[keyof AB]; // "a"
type T3 = { [key in R]: true };
type T4<K extends 'a'|'b'> = T3[K] // Error
~~~~~
!!! error TS2536: Type 'K' cannot be used to index type 'T3'.
type T5<S extends 'a'|'b'|'extra'> = {[key in AB[S]]: true}[S]; // Error
~~~~~
!!! error TS2536: Type 'S' cannot be used to index type 'AB'.
type T6<S extends 'a'|'b', L extends 'a'|'b'> = {[key in AB[S]]: true}[L]; // Error
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2536: Type 'L' cannot be used to index type '{ [key in AB[S]]: true; }'.
type T7<S extends 'a'|'b', L extends 'a'> = {[key in AB[S]]: true}[L];

View file

@ -0,0 +1,49 @@
//// [mappedTypeErrors2.ts]
// Repros from #17238
type AB = {
a: 'a'
b: 'a'
};
type T1<K extends keyof AB> = { [key in AB[K]]: true };
type T2<K extends 'a'|'b'> = T1<K>[K]; // Error
type R = AB[keyof AB]; // "a"
type T3 = { [key in R]: true };
type T4<K extends 'a'|'b'> = T3[K] // Error
type T5<S extends 'a'|'b'|'extra'> = {[key in AB[S]]: true}[S]; // Error
type T6<S extends 'a'|'b', L extends 'a'|'b'> = {[key in AB[S]]: true}[L]; // Error
type T7<S extends 'a'|'b', L extends 'a'> = {[key in AB[S]]: true}[L];
//// [mappedTypeErrors2.js]
// Repros from #17238
//// [mappedTypeErrors2.d.ts]
declare type AB = {
a: 'a';
b: 'a';
};
declare type T1<K extends keyof AB> = {
[key in AB[K]]: true;
};
declare type T2<K extends 'a' | 'b'> = T1<K>[K];
declare type R = AB[keyof AB];
declare type T3 = {
[key in R]: true;
};
declare type T4<K extends 'a' | 'b'> = T3[K];
declare type T5<S extends 'a' | 'b' | 'extra'> = {
[key in AB[S]]: true;
}[S];
declare type T6<S extends 'a' | 'b', L extends 'a' | 'b'> = {
[key in AB[S]]: true;
}[L];
declare type T7<S extends 'a' | 'b', L extends 'a'> = {
[key in AB[S]]: true;
}[L];

View file

@ -0,0 +1,28 @@
tests/cases/compiler/noUnusedLocals_selfReference.ts(3,10): error TS6133: 'f' is declared but never used.
tests/cases/compiler/noUnusedLocals_selfReference.ts(4,7): error TS6133: 'C' is declared but never used.
tests/cases/compiler/noUnusedLocals_selfReference.ts(7,6): error TS6133: 'E' is declared but never used.
==== tests/cases/compiler/noUnusedLocals_selfReference.ts (3 errors) ====
export {}; // Make this a module scope, so these are local variables.
function f() { f; }
~
!!! error TS6133: 'f' is declared but never used.
class C {
~
!!! error TS6133: 'C' is declared but never used.
m() { C; }
}
enum E { A = 0, B = E.A }
~
!!! error TS6133: 'E' is declared but never used.
// Does not detect mutual recursion.
function g() { D; }
class D { m() { g; } }
// Does not work on private methods.
class P { private m() { this.m; } }
P;

View file

@ -0,0 +1,49 @@
//// [noUnusedLocals_selfReference.ts]
export {}; // Make this a module scope, so these are local variables.
function f() { f; }
class C {
m() { C; }
}
enum E { A = 0, B = E.A }
// Does not detect mutual recursion.
function g() { D; }
class D { m() { g; } }
// Does not work on private methods.
class P { private m() { this.m; } }
P;
//// [noUnusedLocals_selfReference.js]
"use strict";
exports.__esModule = true;
function f() { f; }
var C = (function () {
function C() {
}
C.prototype.m = function () { C; };
return C;
}());
var E;
(function (E) {
E[E["A"] = 0] = "A";
E[E["B"] = 0] = "B";
})(E || (E = {}));
// Does not detect mutual recursion.
function g() { D; }
var D = (function () {
function D() {
}
D.prototype.m = function () { g; };
return D;
}());
// Does not work on private methods.
var P = (function () {
function P() {
}
P.prototype.m = function () { this.m; };
return P;
}());
P;

View file

@ -41,9 +41,9 @@ function testcase() {
var one = 1;
var _float = -(4 / 3);
var a = new Array(false, undefined, null, "0", obj, -1.3333333333333, "str", -0, true, +0, one, 1, 0, false, _float, -(4 / 3));
if (a.indexOf(-(4 / 3)) === 14 &&
a.indexOf(0) === 7 &&
a.indexOf(-0) === 7 &&
if (a.indexOf(-(4 / 3)) === 14 &&// a[14]=_float===-(4/3)
a.indexOf(0) === 7 &&// a[7] = +0, 0===+0
a.indexOf(-0) === 7 &&// a[7] = +0, -0===+0
a.indexOf(1) === 10) {
return true;
}

View file

@ -6,5 +6,6 @@
//// [parserGreaterThanTokenAmbiguity10.js]
1
>>>
// before
>>>// after
2;

View file

@ -6,5 +6,6 @@
//// [parserGreaterThanTokenAmbiguity15.js]
1
>>=
// before
>>=// after
2;

View file

@ -6,5 +6,6 @@
//// [parserGreaterThanTokenAmbiguity20.js]
1
>>>=
// Before
>>>=// after
2;

View file

@ -6,5 +6,6 @@
//// [parserGreaterThanTokenAmbiguity5.js]
1
>>
// before
>>// after
2;

View file

@ -0,0 +1,8 @@
//// [prefixedNumberLiteralAssignToNumberLiteralType.ts]
let x: 1 = +1;
let y: -1 = -1;
//// [prefixedNumberLiteralAssignToNumberLiteralType.js]
var x = +1;
var y = -1;

View file

@ -0,0 +1,7 @@
=== tests/cases/compiler/prefixedNumberLiteralAssignToNumberLiteralType.ts ===
let x: 1 = +1;
>x : Symbol(x, Decl(prefixedNumberLiteralAssignToNumberLiteralType.ts, 0, 3))
let y: -1 = -1;
>y : Symbol(y, Decl(prefixedNumberLiteralAssignToNumberLiteralType.ts, 2, 3))

View file

@ -0,0 +1,13 @@
=== tests/cases/compiler/prefixedNumberLiteralAssignToNumberLiteralType.ts ===
let x: 1 = +1;
>x : 1
>+1 : 1
>1 : 1
let y: -1 = -1;
>y : -1
>-1 : -1
>1 : 1
>-1 : -1
>1 : 1

View file

@ -9,7 +9,7 @@ maxDepthExceeded/root.ts(4,4): error TS2540: Cannot assign to 'rel' because it i
"maxNodeModuleJsDepth": 1, // Note: Module m1 is already included as a root file
"outDir": "built"
},
"include": ["**/*"],
"include": ["**/*", "node_modules/**/*"],
"exclude": ["node_modules/m2/**/*"]
}

View file

@ -9,7 +9,7 @@ maxDepthExceeded/root.ts(4,4): error TS2540: Cannot assign to 'rel' because it i
"maxNodeModuleJsDepth": 1, // Note: Module m1 is already included as a root file
"outDir": "built"
},
"include": ["**/*"],
"include": ["**/*", "node_modules/**/*"],
"exclude": ["node_modules/m2/**/*"]
}

View file

@ -0,0 +1,30 @@
//// [signatureInstantiationWithRecursiveConstraints.ts]
// Repro from #17148
class Foo {
myFunc<T extends Foo>(arg: T) {}
}
class Bar {
myFunc<T extends Bar>(arg: T) {}
}
const myVar: Foo = new Bar();
//// [signatureInstantiationWithRecursiveConstraints.js]
"use strict";
// Repro from #17148
var Foo = (function () {
function Foo() {
}
Foo.prototype.myFunc = function (arg) { };
return Foo;
}());
var Bar = (function () {
function Bar() {
}
Bar.prototype.myFunc = function (arg) { };
return Bar;
}());
var myVar = new Bar();

View file

@ -0,0 +1,30 @@
=== tests/cases/compiler/signatureInstantiationWithRecursiveConstraints.ts ===
// Repro from #17148
class Foo {
>Foo : Symbol(Foo, Decl(signatureInstantiationWithRecursiveConstraints.ts, 0, 0))
myFunc<T extends Foo>(arg: T) {}
>myFunc : Symbol(Foo.myFunc, Decl(signatureInstantiationWithRecursiveConstraints.ts, 2, 11))
>T : Symbol(T, Decl(signatureInstantiationWithRecursiveConstraints.ts, 3, 9))
>Foo : Symbol(Foo, Decl(signatureInstantiationWithRecursiveConstraints.ts, 0, 0))
>arg : Symbol(arg, Decl(signatureInstantiationWithRecursiveConstraints.ts, 3, 24))
>T : Symbol(T, Decl(signatureInstantiationWithRecursiveConstraints.ts, 3, 9))
}
class Bar {
>Bar : Symbol(Bar, Decl(signatureInstantiationWithRecursiveConstraints.ts, 4, 1))
myFunc<T extends Bar>(arg: T) {}
>myFunc : Symbol(Bar.myFunc, Decl(signatureInstantiationWithRecursiveConstraints.ts, 6, 11))
>T : Symbol(T, Decl(signatureInstantiationWithRecursiveConstraints.ts, 7, 9))
>Bar : Symbol(Bar, Decl(signatureInstantiationWithRecursiveConstraints.ts, 4, 1))
>arg : Symbol(arg, Decl(signatureInstantiationWithRecursiveConstraints.ts, 7, 24))
>T : Symbol(T, Decl(signatureInstantiationWithRecursiveConstraints.ts, 7, 9))
}
const myVar: Foo = new Bar();
>myVar : Symbol(myVar, Decl(signatureInstantiationWithRecursiveConstraints.ts, 10, 5))
>Foo : Symbol(Foo, Decl(signatureInstantiationWithRecursiveConstraints.ts, 0, 0))
>Bar : Symbol(Bar, Decl(signatureInstantiationWithRecursiveConstraints.ts, 4, 1))

View file

@ -0,0 +1,31 @@
=== tests/cases/compiler/signatureInstantiationWithRecursiveConstraints.ts ===
// Repro from #17148
class Foo {
>Foo : Foo
myFunc<T extends Foo>(arg: T) {}
>myFunc : <T extends Foo>(arg: T) => void
>T : T
>Foo : Foo
>arg : T
>T : T
}
class Bar {
>Bar : Bar
myFunc<T extends Bar>(arg: T) {}
>myFunc : <T extends Bar>(arg: T) => void
>T : T
>Bar : Bar
>arg : T
>T : T
}
const myVar: Foo = new Bar();
>myVar : Foo
>Foo : Foo
>new Bar() : Bar
>Bar : typeof Bar

View file

@ -138,7 +138,7 @@ function foo8(x) {
var b;
return typeof x === "string"
? x === "hello"
: ((b = x) &&
: ((b = x) &&// number | boolean
(typeof x === "boolean"
? x // boolean
: x == 10)); // boolean

View file

@ -2,7 +2,7 @@
// allowed per spec
var a = +1;
>a : number
>+1 : number
>+1 : 1
>1 : 1
var b = +(<any>"");

View file

@ -1,8 +1,9 @@
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(2,6): error TS6133: 'handler1' is declared but never used.
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(5,10): error TS6133: 'foo' is declared but never used.
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(6,10): error TS6133: 'handler2' is declared but never used.
==== tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts (2 errors) ====
==== tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts (3 errors) ====
// unused
type handler1 = () => void;
~~~~~~~~
@ -10,6 +11,8 @@ tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(6,10): error TS613
function foo() {
~~~
!!! error TS6133: 'foo' is declared but never used.
type handler2 = () => void;
~~~~~~~~
!!! error TS6133: 'handler2' is declared but never used.

View file

@ -1,14 +1,17 @@
tests/cases/compiler/weakType.ts(16,13): error TS2559: Type '12' has no properties in common with type 'Settings'.
tests/cases/compiler/weakType.ts(17,13): error TS2559: Type '"completely wrong"' has no properties in common with type 'Settings'.
tests/cases/compiler/weakType.ts(18,13): error TS2559: Type 'false' has no properties in common with type 'Settings'.
tests/cases/compiler/weakType.ts(35,18): error TS2559: Type '{ error?: number; }' has no properties in common with type 'ChangeOptions'.
tests/cases/compiler/weakType.ts(60,5): error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak & Spoiler'.
tests/cases/compiler/weakType.ts(15,13): error TS2560: Value of type '() => { timeout: number; }' has no properties in common with type 'Settings'. Did you mean to call it?
tests/cases/compiler/weakType.ts(16,13): error TS2560: Value of type '() => { timeout: number; }' has no properties in common with type 'Settings'. Did you mean to call it?
tests/cases/compiler/weakType.ts(17,13): error TS2560: Value of type 'CtorOnly' has no properties in common with type 'Settings'. Did you mean to call it?
tests/cases/compiler/weakType.ts(18,13): error TS2559: Type '12' has no properties in common with type 'Settings'.
tests/cases/compiler/weakType.ts(19,13): error TS2559: Type '"completely wrong"' has no properties in common with type 'Settings'.
tests/cases/compiler/weakType.ts(20,13): error TS2559: Type 'false' has no properties in common with type 'Settings'.
tests/cases/compiler/weakType.ts(37,18): error TS2559: Type '{ error?: number; }' has no properties in common with type 'ChangeOptions'.
tests/cases/compiler/weakType.ts(62,5): error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak & Spoiler'.
Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak'.
Types of property 'properties' are incompatible.
Type '{ wrong: string; }' has no properties in common with type '{ b?: number; }'.
==== tests/cases/compiler/weakType.ts (5 errors) ====
==== tests/cases/compiler/weakType.ts (8 errors) ====
interface Settings {
timeout?: number;
onError?(): void;
@ -17,13 +20,21 @@ tests/cases/compiler/weakType.ts(60,5): error TS2322: Type '{ properties: { wron
function getDefaultSettings() {
return { timeout: 1000 };
}
interface CtorOnly {
new(s: string): { timeout: 1000 }
}
function doSomething(settings: Settings) { /* ... */ }
// forgot to call `getDefaultSettings`
// but it is not caught because we don't check for call signatures
doSomething(getDefaultSettings);
// same for arrow expressions:
doSomething(() => { });
~~~~~~~~~~~~~~~~~~
!!! error TS2560: Value of type '() => { timeout: number; }' has no properties in common with type 'Settings'. Did you mean to call it?
doSomething(() => ({ timeout: 1000 }));
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2560: Value of type '() => { timeout: number; }' has no properties in common with type 'Settings'. Did you mean to call it?
doSomething(null as CtorOnly);
~~~~~~~~~~~~~~~~
!!! error TS2560: Value of type 'CtorOnly' has no properties in common with type 'Settings'. Did you mean to call it?
doSomething(12);
~~
!!! error TS2559: Type '12' has no properties in common with type 'Settings'.
@ -82,4 +93,5 @@ tests/cases/compiler/weakType.ts(60,5): error TS2322: Type '{ properties: { wron
!!! error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak'.
!!! error TS2322: Types of property 'properties' are incompatible.
!!! error TS2322: Type '{ wrong: string; }' has no properties in common with type '{ b?: number; }'.

View file

@ -7,13 +7,15 @@ interface Settings {
function getDefaultSettings() {
return { timeout: 1000 };
}
interface CtorOnly {
new(s: string): { timeout: 1000 }
}
function doSomething(settings: Settings) { /* ... */ }
// forgot to call `getDefaultSettings`
// but it is not caught because we don't check for call signatures
doSomething(getDefaultSettings);
// same for arrow expressions:
doSomething(() => { });
doSomething(() => ({ timeout: 1000 }));
doSomething(null as CtorOnly);
doSomething(12);
doSomething('completely wrong');
doSomething(false);
@ -59,6 +61,7 @@ declare let unknown: {
}
}
let weak: Weak & Spoiler = unknown
//// [weakType.js]
@ -67,10 +70,9 @@ function getDefaultSettings() {
}
function doSomething(settings) { }
// forgot to call `getDefaultSettings`
// but it is not caught because we don't check for call signatures
doSomething(getDefaultSettings);
// same for arrow expressions:
doSomething(function () { });
doSomething(function () { return ({ timeout: 1000 }); });
doSomething(null);
doSomething(12);
doSomething('completely wrong');
doSomething(false);

View file

@ -0,0 +1,3 @@
function addProp2(x: any): x is { a: string; a: string; } {
return true;
}

View file

@ -0,0 +1,12 @@
var a = 'some'
// comment
+ 'text';
var b = 'some'
/* comment */
+ 'text';
var c = 'some'
/* comment */
+ /*comment1*/
'text';

View file

@ -0,0 +1,13 @@
// @removeComments: true
var a = 'some'
// comment
+ 'text';
var b = 'some'
/* comment */
+ 'text';
var c = 'some'
/* comment */
+ /*comment1*/
'text';

View file

@ -0,0 +1,28 @@
// @strict: true
// @declaration: true
// Repro from #17456
type StringContains<S extends string, L extends string> = (
{ [K in S]: 'true' } &
{ [key: string]: 'false' }
)[L]
type ObjectHasKey<O, L extends string> = StringContains<keyof O, L>
type First<T> = ObjectHasKey<T, '0'>; // Should be deferred
type T1 = ObjectHasKey<{ a: string }, 'a'>; // 'true'
type T2 = ObjectHasKey<{ a: string }, 'b'>; // 'false'
// Verify that mapped type isn't eagerly resolved in type-to-string operation
declare function f1<A extends string, B extends string>(a: A, b: B): { [P in A | B]: any };
function f2<A extends string>(a: A) {
return f1(a, 'x');
}
function f3(x: 'a' | 'b') {
return f2(x);
}

View file

@ -0,0 +1,24 @@
// @strict: true
// @declaration: true
// Repro from #17456
type StringContains<S extends string, L extends string> = ({ [K in S]: 'true' } & { [key: string]: 'false'})[L];
type ObjectHasKey<O, L extends string> = StringContains<keyof O, L>;
type A<T> = ObjectHasKey<T, '0'>;
type B = ObjectHasKey<[string, number], '1'>; // "true"
type C = ObjectHasKey<[string, number], '2'>; // "false"
type D = A<[string]>; // "true"
// Error, "false" not handled
type E<T> = { true: 'true' }[ObjectHasKey<T, '1'>];
type Juxtapose<T> = ({ true: 'otherwise' } & { [k: string]: 'true' })[ObjectHasKey<T, '1'>];
// Error, "otherwise" is missing
type DeepError<T> = { true: 'true' }[Juxtapose<T>];
type DeepOK<T> = { true: 'true', otherwise: 'false' }[Juxtapose<T>];

View file

@ -0,0 +1,6 @@
// #16709
declare function dearray<T>(ara: ReadonlyArray<T>): T;
type LiteralType = "foo" | "bar";
declare var alt: Array<LiteralType>;
let foo: LiteralType = dearray(alt);

View file

@ -0,0 +1,45 @@
// @Filename: base.d.ts
declare const x: "foo".charCodeAt(0);
// @filename: string.ts
interface String {
typeof<T>(x: T): T;
}
class C {
foo() {
const x: "".typeof(this.foo);
}
}
const nodes = document.getElementsByTagName("li");
type ItemType = "".typeof(nodes.item(0));
// @filename: number.ts
interface Number {
typeof<T>(x: T): T;
}
class C2 {
foo() {
const x: 3.141592.typeof(this.foo);
}
}
const nodes2 = document.getElementsByTagName("li");
type ItemType2 = 4..typeof(nodes.item(0));
// @filename: boolean.ts
interface Boolean {
typeof<T>(x: T): T;
}
class C3 {
foo() {
const x: false.typeof(this.foo);
}
}
const nodes3 = document.getElementsByTagName("li");
type ItemType3 = true.typeof(nodes.item(0));

View file

@ -0,0 +1,35 @@
// @strict: true
// @declaration: true
// A mapped type { [P in K]: X }, where K is a generic type, is related to
// { [key: string]: Y } if X is related to Y.
function f1<T, K extends string>(x: { [key: string]: T }, y: Record<K, T>) {
x = y;
y = x; // Error
}
function f2<T>(x: { [key: string]: T }, y: Record<string, T>) {
x = y;
y = x;
}
function f3<T, U, K extends string>(x: { [key: string]: T }, y: Record<K, U>) {
x = y; // Error
y = x; // Error
}
// Repro from #14548
type Dictionary = {
[key: string]: string;
};
interface IBaseEntity {
name: string;
properties: Dictionary;
}
interface IEntity<T extends string> extends IBaseEntity {
properties: Record<T, string>;
}

View file

@ -0,0 +1,10 @@
// @allowJs: true
// @noEmit: true
// @checkJs: true
// @filename: index.js
/**
* @param {Array<*>} list
*/
function thing(list) {
return list;
}

View file

@ -0,0 +1,71 @@
// @allowJs: true
// @noEmit: true
// @checkJs: true
// @filename: index.js
/**
* @param {<T>(m: Boolean<T>) => string} somebody
*/
function sayHello(somebody) {
return 'Hello ' + somebody;
}
// @filename: index2.js
/**
* @param {<T>(m: Void<T>) => string} somebody
*/
function sayHello2(somebody) {
return 'Hello ' + somebody;
}
// @filename: index3.js
/**
* @param {<T>(m: Undefined<T>) => string} somebody
*/
function sayHello3(somebody) {
return 'Hello ' + somebody;
}
// @filename: index4.js
/**
* @param {<T>(m: Function<T>) => string} somebody
*/
function sayHello4(somebody) {
return 'Hello ' + somebody;
}
// @filename: index5.js
/**
* @param {<T>(m: String<T>) => string} somebody
*/
function sayHello5(somebody) {
return 'Hello ' + somebody;
}
// @filename: index6.js
/**
* @param {<T>(m: Number<T>) => string} somebody
*/
function sayHello6(somebody) {
return 'Hello ' + somebody;
}
// @filename: index7.js
/**
* @param {<T>(m: Object<T>) => string} somebody
*/
function sayHello7(somebody) {
return 'Hello ' + somebody;
}
// @filename: index8.js
function fn() {}
/**
* @param {fn<T>} somebody
*/
function sayHello8(somebody) { }

View file

@ -0,0 +1,17 @@
// @noUnusedLocals: true
export {}; // Make this a module scope, so these are local variables.
function f() { f; }
class C {
m() { C; }
}
enum E { A = 0, B = E.A }
// Does not detect mutual recursion.
function g() { D; }
class D { m() { g; } }
// Does not work on private methods.
class P { private m() { this.m; } }
P;

View file

@ -0,0 +1,3 @@
let x: 1 = +1;
let y: -1 = -1;

View file

@ -0,0 +1,13 @@
// @strict: true
// Repro from #17148
class Foo {
myFunc<T extends Foo>(arg: T) {}
}
class Bar {
myFunc<T extends Bar>(arg: T) {}
}
const myVar: Foo = new Bar();

View file

@ -6,13 +6,15 @@ interface Settings {
function getDefaultSettings() {
return { timeout: 1000 };
}
interface CtorOnly {
new(s: string): { timeout: 1000 }
}
function doSomething(settings: Settings) { /* ... */ }
// forgot to call `getDefaultSettings`
// but it is not caught because we don't check for call signatures
doSomething(getDefaultSettings);
// same for arrow expressions:
doSomething(() => { });
doSomething(() => ({ timeout: 1000 }));
doSomething(null as CtorOnly);
doSomething(12);
doSomething('completely wrong');
doSomething(false);
@ -58,3 +60,4 @@ declare let unknown: {
}
}
let weak: Weak & Spoiler = unknown

View file

@ -0,0 +1,22 @@
// @strictNullChecks: true
// @declaration: true
// Repros from #17238
type AB = {
a: 'a'
b: 'a'
};
type T1<K extends keyof AB> = { [key in AB[K]]: true };
type T2<K extends 'a'|'b'> = T1<K>[K]; // Error
type R = AB[keyof AB]; // "a"
type T3 = { [key in R]: true };
type T4<K extends 'a'|'b'> = T3[K] // Error
type T5<S extends 'a'|'b'|'extra'> = {[key in AB[S]]: true}[S]; // Error
type T6<S extends 'a'|'b', L extends 'a'|'b'> = {[key in AB[S]]: true}[L]; // Error
type T7<S extends 'a'|'b', L extends 'a'> = {[key in AB[S]]: true}[L];

Some files were not shown because too many files have changed in this diff Show more