mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into use-type-param-constraints-for-computed-prop-types
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+166
-76
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
+105
-55
@@ -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.");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+28
-7
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -665,6 +665,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
ts.setStackTraceLimit();
|
||||
|
||||
if (ts.Debug.isDebugging) {
|
||||
ts.Debug.enableDebugInfo();
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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) => ({
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
Vendored
+1
-1
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+14
-11
@@ -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();
|
||||
}
|
||||
|
||||
+49
-35
@@ -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");
|
||||
|
||||
+23
-26
@@ -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 };
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+11
-13
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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';
|
||||
@@ -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';
|
||||
@@ -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"
|
||||
|
||||
@@ -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';
|
||||
@@ -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';
|
||||
@@ -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"
|
||||
|
||||
@@ -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 () { },
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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>];
|
||||
|
||||
@@ -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>];
|
||||
@@ -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);
|
||||
@@ -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))
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -131,7 +131,7 @@ enum E11 {
|
||||
|
||||
A = +0,
|
||||
>A : E11
|
||||
>+0 : number
|
||||
>+0 : 0
|
||||
>0 : 0
|
||||
|
||||
B,
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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));
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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[]
|
||||
}
|
||||
|
||||
@@ -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) { }
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
|
||||
//// [parserGreaterThanTokenAmbiguity10.js]
|
||||
1
|
||||
>>>
|
||||
// before
|
||||
>>>// after
|
||||
2;
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
|
||||
//// [parserGreaterThanTokenAmbiguity15.js]
|
||||
1
|
||||
>>=
|
||||
// before
|
||||
>>=// after
|
||||
2;
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
|
||||
//// [parserGreaterThanTokenAmbiguity20.js]
|
||||
1
|
||||
>>>=
|
||||
// Before
|
||||
>>>=// after
|
||||
2;
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
|
||||
//// [parserGreaterThanTokenAmbiguity5.js]
|
||||
1
|
||||
>>
|
||||
// before
|
||||
>>// after
|
||||
2;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
//// [prefixedNumberLiteralAssignToNumberLiteralType.ts]
|
||||
let x: 1 = +1;
|
||||
|
||||
let y: -1 = -1;
|
||||
|
||||
//// [prefixedNumberLiteralAssignToNumberLiteralType.js]
|
||||
var x = +1;
|
||||
var y = -1;
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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/**/*"]
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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/**/*"]
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// allowed per spec
|
||||
var a = +1;
|
||||
>a : number
|
||||
>+1 : number
|
||||
>+1 : 1
|
||||
>1 : 1
|
||||
|
||||
var b = +(<any>"");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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; }'.
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
function addProp2(x: any): x is { a: string; a: string; } {
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
var a = 'some'
|
||||
// comment
|
||||
+ 'text';
|
||||
|
||||
var b = 'some'
|
||||
/* comment */
|
||||
+ 'text';
|
||||
|
||||
var c = 'some'
|
||||
/* comment */
|
||||
+ /*comment1*/
|
||||
'text';
|
||||
@@ -0,0 +1,13 @@
|
||||
// @removeComments: true
|
||||
var a = 'some'
|
||||
// comment
|
||||
+ 'text';
|
||||
|
||||
var b = 'some'
|
||||
/* comment */
|
||||
+ 'text';
|
||||
|
||||
var c = 'some'
|
||||
/* comment */
|
||||
+ /*comment1*/
|
||||
'text';
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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>];
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// @allowJs: true
|
||||
// @noEmit: true
|
||||
// @checkJs: true
|
||||
// @filename: index.js
|
||||
/**
|
||||
* @param {Array<*>} list
|
||||
*/
|
||||
function thing(list) {
|
||||
return list;
|
||||
}
|
||||
@@ -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) { }
|
||||
@@ -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;
|
||||
@@ -0,0 +1,3 @@
|
||||
let x: 1 = +1;
|
||||
|
||||
let y: -1 = -1;
|
||||
@@ -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();
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user