mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into typesVersions
This commit is contained in:
+303
-217
@@ -31,6 +31,18 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker {
|
||||
const getPackagesSet: () => Map<true> = memoize(() => {
|
||||
const set = createMap<true>();
|
||||
host.getSourceFiles().forEach(sf => {
|
||||
if (!sf.resolvedModules) return;
|
||||
|
||||
forEachEntry(sf.resolvedModules, r => {
|
||||
if (r && r.packageId) set.set(r.packageId.name, true);
|
||||
});
|
||||
});
|
||||
return set;
|
||||
});
|
||||
|
||||
// Cancellation that controls whether or not we can cancel in the middle of type checking.
|
||||
// In general cancelling is *not* safe for the type checker. We might be in the middle of
|
||||
// computing something, and we will leave our internals in an inconsistent state. Callers
|
||||
@@ -53,7 +65,8 @@ namespace ts {
|
||||
let typeCount = 0;
|
||||
let symbolCount = 0;
|
||||
let enumCount = 0;
|
||||
let symbolInstantiationDepth = 0;
|
||||
let instantiationDepth = 0;
|
||||
let constraintDepth = 0;
|
||||
|
||||
const emptySymbols = createSymbolTable();
|
||||
const identityMapper: (type: Type) => Type = identity;
|
||||
@@ -357,7 +370,9 @@ namespace ts {
|
||||
finally {
|
||||
cancellationToken = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getLocalTypeParametersOfClassOrInterfaceOrTypeAlias,
|
||||
};
|
||||
|
||||
function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, isForSignatureHelp: boolean): Signature | undefined {
|
||||
@@ -1195,17 +1210,23 @@ namespace ts {
|
||||
// local types not visible outside the function body
|
||||
: false;
|
||||
}
|
||||
if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.FunctionScopedVariable) {
|
||||
// parameters are visible only inside function body, parameter list and return type
|
||||
// technically for parameter list case here we might mix parameters and variables declared in function,
|
||||
// however it is detected separately when checking initializers of parameters
|
||||
// to make sure that they reference no variables declared after them.
|
||||
useResult =
|
||||
if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.Variable) {
|
||||
// parameter initializer will lookup as normal variable scope when targeting es2015+
|
||||
if (compilerOptions.target && compilerOptions.target >= ScriptTarget.ES2015 && isParameter(lastLocation) && result.valueDeclaration !== lastLocation) {
|
||||
useResult = false;
|
||||
}
|
||||
else if (result.flags & SymbolFlags.FunctionScopedVariable) {
|
||||
// parameters are visible only inside function body, parameter list and return type
|
||||
// technically for parameter list case here we might mix parameters and variables declared in function,
|
||||
// however it is detected separately when checking initializers of parameters
|
||||
// to make sure that they reference no variables declared after them.
|
||||
useResult =
|
||||
lastLocation.kind === SyntaxKind.Parameter ||
|
||||
(
|
||||
lastLocation === (<FunctionLikeDeclaration>location).type &&
|
||||
!!findAncestor(result.valueDeclaration, isParameter)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (location.kind === SyntaxKind.ConditionalType) {
|
||||
@@ -2264,12 +2285,9 @@ namespace ts {
|
||||
resolvedFileName));
|
||||
}
|
||||
function typesPackageExists(packageName: string): boolean {
|
||||
return host.getSourceFiles().some(sf => !!sf.resolvedModules && !!forEachEntry(sf.resolvedModules, r =>
|
||||
r && r.packageId && r.packageId.name === getTypesPackageName(packageName)));
|
||||
return getPackagesSet().has(getTypesPackageName(packageName));
|
||||
}
|
||||
|
||||
// An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
|
||||
// and an external module with no 'export =' declaration resolves to the module itself.
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol;
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined;
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol {
|
||||
@@ -3908,13 +3926,22 @@ namespace ts {
|
||||
const links = getSymbolLinks(symbol);
|
||||
let specifier = links.specifierCache && links.specifierCache.get(contextFile.path);
|
||||
if (!specifier) {
|
||||
specifier = moduleSpecifiers.getModuleSpecifierForDeclarationFile(
|
||||
const isBundle = (compilerOptions.out || compilerOptions.outFile);
|
||||
// For declaration bundles, we need to generate absolute paths relative to the common source dir for imports,
|
||||
// just like how the declaration emitter does for the ambient module declarations - we can easily accomplish this
|
||||
// using the `baseUrl` compiler option (which we would otherwise never use in declaration emit) and a non-relative
|
||||
// specifier preference
|
||||
const { moduleResolverHost } = context.tracker;
|
||||
const specifierCompilerOptions = isBundle ? { ...compilerOptions, baseUrl: moduleResolverHost.getCommonSourceDirectory() } : compilerOptions;
|
||||
specifier = first(first(moduleSpecifiers.getModuleSpecifiers(
|
||||
symbol,
|
||||
compilerOptions,
|
||||
specifierCompilerOptions,
|
||||
contextFile,
|
||||
context.tracker.moduleResolverHost,
|
||||
moduleResolverHost,
|
||||
host.getSourceFiles(),
|
||||
{ importModuleSpecifierPreference: isBundle ? "non-relative" : "relative" },
|
||||
host.redirectTargetsMap,
|
||||
);
|
||||
)));
|
||||
links.specifierCache = links.specifierCache || createMap();
|
||||
links.specifierCache.set(contextFile.path, specifier);
|
||||
}
|
||||
@@ -4698,6 +4725,12 @@ namespace ts {
|
||||
return getReturnTypeOfSignature(getterSignature);
|
||||
}
|
||||
}
|
||||
if (isInJavaScriptFile(declaration)) {
|
||||
const typeTag = getJSDocType(func);
|
||||
if (typeTag && isFunctionTypeNode(typeTag)) {
|
||||
return getTypeAtPosition(getSignatureFromDeclaration(typeTag), func.parameters.indexOf(declaration));
|
||||
}
|
||||
}
|
||||
// Use contextual parameter type if one is available
|
||||
const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration);
|
||||
if (type) {
|
||||
@@ -4794,7 +4827,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getJSExpandoObjectType(decl: Node, symbol: Symbol, init: Expression | undefined): Type | undefined {
|
||||
if (!init || !isObjectLiteralExpression(init) || init.properties.length) {
|
||||
if (!isInJavaScriptFile(decl) || !init || !isObjectLiteralExpression(init) || init.properties.length) {
|
||||
return undefined;
|
||||
}
|
||||
const exports = createSymbolTable();
|
||||
@@ -5303,22 +5336,14 @@ namespace ts {
|
||||
function getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
|
||||
const links = getSymbolLinks(symbol);
|
||||
if (!links.type) {
|
||||
if (symbolInstantiationDepth === 100) {
|
||||
error(symbol.valueDeclaration, Diagnostics.Generic_type_instantiation_is_excessively_deep_and_possibly_infinite);
|
||||
links.type = errorType;
|
||||
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
|
||||
return links.type = errorType;
|
||||
}
|
||||
else {
|
||||
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
|
||||
return links.type = errorType;
|
||||
}
|
||||
symbolInstantiationDepth++;
|
||||
let type = instantiateType(getTypeOfSymbol(links.target!), links.mapper!);
|
||||
symbolInstantiationDepth--;
|
||||
if (!popTypeResolution()) {
|
||||
type = reportCircularityError(symbol);
|
||||
}
|
||||
links.type = type;
|
||||
let type = instantiateType(getTypeOfSymbol(links.target!), links.mapper!);
|
||||
if (!popTypeResolution()) {
|
||||
type = reportCircularityError(symbol);
|
||||
}
|
||||
links.type = type;
|
||||
}
|
||||
return links.type;
|
||||
}
|
||||
@@ -6906,10 +6931,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
|
||||
const objectType = getBaseConstraintOfType(type.objectType) || type.objectType;
|
||||
const indexType = getBaseConstraintOfType(type.indexType) || type.indexType;
|
||||
const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType) : undefined;
|
||||
return constraint && constraint !== errorType ? constraint : undefined;
|
||||
const objectType = getConstraintOfType(type.objectType) || type.objectType;
|
||||
if (objectType !== type.objectType) {
|
||||
const constraint = getIndexedAccessType(objectType, type.indexType, /*accessNode*/ undefined, errorType);
|
||||
if (constraint && constraint !== errorType) {
|
||||
return constraint;
|
||||
}
|
||||
}
|
||||
const baseConstraint = getBaseConstraintOfType(type);
|
||||
return baseConstraint && baseConstraint !== type ? baseConstraint : undefined;
|
||||
}
|
||||
|
||||
function getDefaultConstraintOfConditionalType(type: ConditionalType) {
|
||||
@@ -6928,7 +6958,8 @@ namespace ts {
|
||||
// over the conditional type and possibly reduced. For example, 'T extends undefined ? never : T'
|
||||
// removes 'undefined' from T.
|
||||
if (type.root.isDistributive) {
|
||||
const constraint = getConstraintOfType(getSimplifiedType(type.checkType));
|
||||
const simplified = getSimplifiedType(type.checkType);
|
||||
const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified;
|
||||
if (constraint) {
|
||||
const mapper = makeUnaryTypeMapper(type.root.checkType, constraint);
|
||||
const instantiated = getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
|
||||
@@ -7011,6 +7042,7 @@ namespace ts {
|
||||
* circularly references the type variable.
|
||||
*/
|
||||
function getResolvedBaseConstraint(type: InstantiableType | UnionOrIntersectionType): Type {
|
||||
let nonTerminating = false;
|
||||
return type.resolvedBaseConstraint ||
|
||||
(type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), type));
|
||||
|
||||
@@ -7019,8 +7051,18 @@ namespace ts {
|
||||
if (!pushTypeResolution(t, TypeSystemPropertyName.ImmediateBaseConstraint)) {
|
||||
return circularConstraintType;
|
||||
}
|
||||
if (constraintDepth === 50) {
|
||||
// We have reached 50 recursive invocations of getImmediateBaseConstraint and there is a
|
||||
// very high likelyhood we're dealing with an infinite generic type that perpetually generates
|
||||
// new type identities as we descend into it. We stop the recursion here and mark this type
|
||||
// and the outer types as having circular constraints.
|
||||
nonTerminating = true;
|
||||
return t.immediateBaseConstraint = noConstraintType;
|
||||
}
|
||||
constraintDepth++;
|
||||
let result = computeBaseConstraint(getSimplifiedType(t));
|
||||
if (!popTypeResolution()) {
|
||||
constraintDepth--;
|
||||
if (!popTypeResolution() || nonTerminating) {
|
||||
result = circularConstraintType;
|
||||
}
|
||||
t.immediateBaseConstraint = result || noConstraintType;
|
||||
@@ -7059,7 +7101,7 @@ namespace ts {
|
||||
if (t.flags & TypeFlags.IndexedAccess) {
|
||||
const baseObjectType = getBaseConstraint((<IndexedAccessType>t).objectType);
|
||||
const baseIndexType = getBaseConstraint((<IndexedAccessType>t).indexType);
|
||||
const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined;
|
||||
const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType, /*accessNode*/ undefined, errorType) : undefined;
|
||||
return baseIndexedAccess && baseIndexedAccess !== errorType ? getBaseConstraint(baseIndexedAccess) : undefined;
|
||||
}
|
||||
if (t.flags & TypeFlags.Conditional) {
|
||||
@@ -7069,9 +7111,6 @@ namespace ts {
|
||||
if (t.flags & TypeFlags.Substitution) {
|
||||
return getBaseConstraint((<SubstitutionType>t).substitute);
|
||||
}
|
||||
if (isGenericMappedType(t)) {
|
||||
return emptyObjectType;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
@@ -9144,7 +9183,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | undefined, cacheSymbol: boolean) {
|
||||
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | undefined, cacheSymbol: boolean, missingType: Type) {
|
||||
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
|
||||
const propName = isTypeUsableAsLateBoundName(indexType) ? getLateBoundNameFromType(indexType) :
|
||||
accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ?
|
||||
@@ -9157,7 +9196,7 @@ namespace ts {
|
||||
markPropertyAsReferenced(prop, accessExpression, /*isThisAccess*/ accessExpression.expression.kind === SyntaxKind.ThisKeyword);
|
||||
if (isAssignmentTarget(accessExpression) && (isReferenceToReadonlyEntity(accessExpression, prop) || isReferenceThroughNamespaceImport(accessExpression))) {
|
||||
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, symbolToString(prop));
|
||||
return errorType;
|
||||
return missingType;
|
||||
}
|
||||
if (cacheSymbol) {
|
||||
getNodeLinks(accessNode!).resolvedSymbol = prop;
|
||||
@@ -9216,7 +9255,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
return anyType;
|
||||
return missingType;
|
||||
}
|
||||
}
|
||||
if (isJSLiteralType(objectType)) {
|
||||
@@ -9234,7 +9273,10 @@ namespace ts {
|
||||
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
|
||||
}
|
||||
}
|
||||
return errorType;
|
||||
if (isTypeAny(indexType)) {
|
||||
return indexType;
|
||||
}
|
||||
return missingType;
|
||||
}
|
||||
|
||||
function isGenericObjectType(type: Type): boolean {
|
||||
@@ -9245,22 +9287,6 @@ namespace ts {
|
||||
return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive | TypeFlags.Index);
|
||||
}
|
||||
|
||||
// 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): boolean {
|
||||
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;
|
||||
}
|
||||
|
||||
function isMappedTypeToNever(type: Type): boolean {
|
||||
return !!(getObjectFlags(type) & ObjectFlags.Mapped) && getTemplateTypeFromMappedType(type as MappedType) === neverType;
|
||||
}
|
||||
|
||||
function getSimplifiedType(type: Type): Type {
|
||||
return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(<IndexedAccessType>type) : type;
|
||||
}
|
||||
@@ -9275,35 +9301,12 @@ namespace ts {
|
||||
// We recursively simplify the object type as it may in turn be an indexed access type. For example, with
|
||||
// '{ [P in T]: { [Q in U]: number } }[T][U]' we want to first simplify the inner indexed access type.
|
||||
const objectType = getSimplifiedType(type.objectType);
|
||||
if (objectType.flags & TypeFlags.Intersection && isGenericObjectType(objectType)) {
|
||||
// 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.
|
||||
if (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 type.simplified = getUnionType([
|
||||
getSimplifiedType(getIndexedAccessType(getIntersectionType(regularTypes), type.indexType)),
|
||||
getIntersectionType(stringIndexTypes)
|
||||
]);
|
||||
}
|
||||
// Given an indexed access type T[K], if T is an intersection containing one or more generic types and one or
|
||||
// more mapped types with a template type `never`, '(U & V & { [P in T]: never })[K]', return a
|
||||
// transformed type that removes the never-mapped type: '(U & V)[K]'. This mirrors what would happen
|
||||
// eventually anyway, but it easier to reason about.
|
||||
if (some((<IntersectionType>objectType).types, isMappedTypeToNever)) {
|
||||
const nonNeverTypes = filter((<IntersectionType>objectType).types, t => !isMappedTypeToNever(t));
|
||||
return type.simplified = getSimplifiedType(getIndexedAccessType(getIntersectionType(nonNeverTypes), type.indexType));
|
||||
}
|
||||
const indexType = getSimplifiedType(type.indexType);
|
||||
if (objectType.flags & TypeFlags.Union) {
|
||||
return type.simplified = mapType(objectType, t => getSimplifiedType(getIndexedAccessType(t, indexType)));
|
||||
}
|
||||
if (objectType.flags & TypeFlags.Intersection) {
|
||||
return type.simplified = getIntersectionType(map((objectType as IntersectionType).types, t => getSimplifiedType(getIndexedAccessType(t, indexType))));
|
||||
}
|
||||
// If the object type is a mapped type { [P in K]: E }, where K is generic, 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
|
||||
@@ -9327,7 +9330,7 @@ namespace ts {
|
||||
return instantiateType(getTemplateTypeFromMappedType(objectType), templateMapper);
|
||||
}
|
||||
|
||||
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode): Type {
|
||||
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode, missingType = accessNode ? errorType : unknownType): Type {
|
||||
if (objectType === wildcardType || indexType === wildcardType) {
|
||||
return wildcardType;
|
||||
}
|
||||
@@ -9355,15 +9358,15 @@ namespace ts {
|
||||
if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) {
|
||||
const propTypes: Type[] = [];
|
||||
for (const t of (<UnionType>indexType).types) {
|
||||
const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false);
|
||||
if (propType === errorType) {
|
||||
return errorType;
|
||||
const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false, missingType);
|
||||
if (propType === missingType) {
|
||||
return missingType;
|
||||
}
|
||||
propTypes.push(propType);
|
||||
}
|
||||
return getUnionType(propTypes);
|
||||
}
|
||||
return getPropertyTypeForIndexType(apparentObjectType, indexType, accessNode, /*cacheSymbol*/ true);
|
||||
return getPropertyTypeForIndexType(apparentObjectType, indexType, accessNode, /*cacheSymbol*/ true, missingType);
|
||||
}
|
||||
|
||||
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
|
||||
@@ -10293,49 +10296,66 @@ namespace ts {
|
||||
function instantiateType(type: Type, mapper: TypeMapper | undefined): Type;
|
||||
function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined;
|
||||
function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined {
|
||||
if (type && mapper && mapper !== identityMapper) {
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
return mapper(<TypeParameter>type);
|
||||
if (!type || !mapper || mapper === identityMapper) {
|
||||
return type;
|
||||
}
|
||||
if (instantiationDepth === 50) {
|
||||
// We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
|
||||
// with a combination of infinite generic types that perpetually generate new type identities. We stop
|
||||
// the recursion here by yielding the error type.
|
||||
return errorType;
|
||||
}
|
||||
instantiationDepth++;
|
||||
const result = instantiateTypeWorker(type, mapper);
|
||||
instantiationDepth--;
|
||||
return result;
|
||||
}
|
||||
|
||||
function instantiateTypeWorker(type: Type, mapper: TypeMapper): Type {
|
||||
const flags = type.flags;
|
||||
if (flags & TypeFlags.TypeParameter) {
|
||||
return mapper(type);
|
||||
}
|
||||
if (flags & TypeFlags.Object) {
|
||||
const objectFlags = (<ObjectType>type).objectFlags;
|
||||
if (objectFlags & ObjectFlags.Anonymous) {
|
||||
// If the anonymous type originates in a declaration of a function, method, class, or
|
||||
// interface, in an object type literal, or in an object literal expression, we may need
|
||||
// to instantiate the type because it might reference a type parameter.
|
||||
return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ?
|
||||
getAnonymousTypeInstantiation(<AnonymousType>type, mapper) : type;
|
||||
}
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Anonymous) {
|
||||
// If the anonymous type originates in a declaration of a function, method, class, or
|
||||
// interface, in an object type literal, or in an object literal expression, we may need
|
||||
// to instantiate the type because it might reference a type parameter.
|
||||
return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ?
|
||||
getAnonymousTypeInstantiation(<AnonymousType>type, mapper) : type;
|
||||
}
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Mapped) {
|
||||
return getAnonymousTypeInstantiation(<MappedType>type, mapper);
|
||||
}
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Reference) {
|
||||
const typeArguments = (<TypeReference>type).typeArguments;
|
||||
const newTypeArguments = instantiateTypes(typeArguments, mapper);
|
||||
return newTypeArguments !== typeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type;
|
||||
}
|
||||
if (objectFlags & ObjectFlags.Mapped) {
|
||||
return getAnonymousTypeInstantiation(<AnonymousType>type, mapper);
|
||||
}
|
||||
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) {
|
||||
const types = (<UnionType>type).types;
|
||||
const newTypes = instantiateTypes(types, mapper);
|
||||
return newTypes !== types ? getUnionType(newTypes, UnionReduction.Literal, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) : type;
|
||||
}
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
const types = (<IntersectionType>type).types;
|
||||
const newTypes = instantiateTypes(types, mapper);
|
||||
return newTypes !== types ? getIntersectionType(newTypes, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) : type;
|
||||
}
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
return getIndexType(instantiateType((<IndexType>type).type, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.Conditional) {
|
||||
return getConditionalTypeInstantiation(<ConditionalType>type, combineTypeMappers((<ConditionalType>type).mapper, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.Substitution) {
|
||||
return instantiateType((<SubstitutionType>type).typeVariable, mapper);
|
||||
if (objectFlags & ObjectFlags.Reference) {
|
||||
const typeArguments = (<TypeReference>type).typeArguments;
|
||||
const newTypeArguments = instantiateTypes(typeArguments, mapper);
|
||||
return newTypeArguments !== typeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
if (flags & TypeFlags.Union && !(flags & TypeFlags.Primitive)) {
|
||||
const types = (<UnionType>type).types;
|
||||
const newTypes = instantiateTypes(types, mapper);
|
||||
return newTypes !== types ? getUnionType(newTypes, UnionReduction.Literal, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) : type;
|
||||
}
|
||||
if (flags & TypeFlags.Intersection) {
|
||||
const types = (<IntersectionType>type).types;
|
||||
const newTypes = instantiateTypes(types, mapper);
|
||||
return newTypes !== types ? getIntersectionType(newTypes, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) : type;
|
||||
}
|
||||
if (flags & TypeFlags.Index) {
|
||||
return getIndexType(instantiateType((<IndexType>type).type, mapper));
|
||||
}
|
||||
if (flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
|
||||
}
|
||||
if (flags & TypeFlags.Conditional) {
|
||||
return getConditionalTypeInstantiation(<ConditionalType>type, combineTypeMappers((<ConditionalType>type).mapper, mapper));
|
||||
}
|
||||
if (flags & TypeFlags.Substitution) {
|
||||
return instantiateType((<SubstitutionType>type).typeVariable, mapper);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@@ -10510,8 +10530,12 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isOrHasGenericConditional(type: Type): boolean {
|
||||
return !!(type.flags & TypeFlags.Conditional || (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isOrHasGenericConditional)));
|
||||
}
|
||||
|
||||
function elaborateError(node: Expression | undefined, source: Type, target: Type): boolean {
|
||||
if (!node) return false;
|
||||
if (!node || isOrHasGenericConditional(target)) return false;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JsxExpression:
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
@@ -10544,9 +10568,9 @@ namespace ts {
|
||||
let reportedError = false;
|
||||
for (let status = iterator.next(); !status.done; status = iterator.next()) {
|
||||
const { errorNode: prop, innerExpression: next, nameType, errorMessage } = status.value;
|
||||
const sourcePropType = getIndexedAccessType(source, nameType);
|
||||
const targetPropType = getIndexedAccessType(target, nameType);
|
||||
if (!isTypeAssignableTo(sourcePropType, targetPropType)) {
|
||||
const sourcePropType = getIndexedAccessType(source, nameType, /*accessNode*/ undefined, errorType);
|
||||
const targetPropType = getIndexedAccessType(target, nameType, /*accessNode*/ undefined, errorType);
|
||||
if (sourcePropType !== errorType && targetPropType !== errorType && !isTypeAssignableTo(sourcePropType, targetPropType)) {
|
||||
const elaborated = next && elaborateError(next, sourcePropType, targetPropType);
|
||||
if (elaborated) {
|
||||
reportedError = true;
|
||||
@@ -11156,7 +11180,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (relation !== comparableRelation &&
|
||||
!(source.flags & TypeFlags.UnionOrIntersection) &&
|
||||
!(source.flags & TypeFlags.Union) &&
|
||||
!(target.flags & TypeFlags.Union) &&
|
||||
!isIntersectionConstituent &&
|
||||
source !== globalObjectType &&
|
||||
@@ -11265,7 +11289,7 @@ namespace ts {
|
||||
function isIdenticalTo(source: Type, target: Type): Ternary {
|
||||
let result: Ternary;
|
||||
const flags = source.flags & target.flags;
|
||||
if (flags & TypeFlags.Object) {
|
||||
if (flags & TypeFlags.Object || flags & TypeFlags.IndexedAccess || flags & TypeFlags.Conditional || flags & TypeFlags.Index || flags & TypeFlags.Substitution) {
|
||||
return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false);
|
||||
}
|
||||
if (flags & (TypeFlags.Union | TypeFlags.Intersection)) {
|
||||
@@ -11275,32 +11299,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & TypeFlags.Index) {
|
||||
return isRelatedTo((<IndexType>source).type, (<IndexType>target).type, /*reportErrors*/ false);
|
||||
}
|
||||
if (flags & TypeFlags.IndexedAccess) {
|
||||
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, /*reportErrors*/ false)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & TypeFlags.Conditional) {
|
||||
if ((<ConditionalType>source).root.isDistributive === (<ConditionalType>target).root.isDistributive) {
|
||||
if (result = isRelatedTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & TypeFlags.Substitution) {
|
||||
return isRelatedTo((<SubstitutionType>source).substitute, (<SubstitutionType>target).substitute, /*reportErrors*/ false);
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
|
||||
@@ -11612,6 +11610,37 @@ namespace ts {
|
||||
}
|
||||
|
||||
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
const flags = source.flags & target.flags;
|
||||
if (relation === identityRelation && !(flags & TypeFlags.Object)) {
|
||||
if (flags & TypeFlags.Index) {
|
||||
return isRelatedTo((<IndexType>source).type, (<IndexType>target).type, /*reportErrors*/ false);
|
||||
}
|
||||
let result = Ternary.False;
|
||||
if (flags & TypeFlags.IndexedAccess) {
|
||||
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, /*reportErrors*/ false)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & TypeFlags.Conditional) {
|
||||
if ((<ConditionalType>source).root.isDistributive === (<ConditionalType>target).root.isDistributive) {
|
||||
if (result = isRelatedTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & TypeFlags.Substitution) {
|
||||
return isRelatedTo((<SubstitutionType>source).substitute, (<SubstitutionType>target).substitute, /*reportErrors*/ false);
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
let result: Ternary;
|
||||
let originalErrorInfo: DiagnosticMessageChain | undefined;
|
||||
const saveErrorInfo = errorInfo;
|
||||
@@ -11647,12 +11676,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else if (target.flags & TypeFlags.IndexedAccess) {
|
||||
// A type S is related to a type T[K] if S is related to C, where C is the
|
||||
// constraint of T[K]
|
||||
const constraint = getConstraintForRelation(target);
|
||||
if (constraint) {
|
||||
if (result = isRelatedTo(source, constraint, reportErrors)) {
|
||||
return result;
|
||||
// A type S is related to a type T[K] if S is related to C, where C is the base constraint of T[K]
|
||||
if (relation !== identityRelation) {
|
||||
const constraint = getBaseConstraintOfType(target);
|
||||
if (constraint && constraint !== target) {
|
||||
if (result = isRelatedTo(source, constraint, reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11756,6 +11786,9 @@ namespace ts {
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
if (relation === definitelyAssignableRelation && isGenericMappedType(source)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
|
||||
if (relation !== identityRelation) {
|
||||
source = getApparentType(source);
|
||||
@@ -13524,14 +13557,16 @@ namespace ts {
|
||||
const sourceLen = sourceSignatures.length;
|
||||
const targetLen = targetSignatures.length;
|
||||
const len = sourceLen < targetLen ? sourceLen : targetLen;
|
||||
const skipParameters = !!(source.flags & TypeFlags.ContainsAnyFunctionType);
|
||||
for (let i = 0; i < len; i++) {
|
||||
inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getBaseSignature(targetSignatures[targetLen - len + i]));
|
||||
inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getBaseSignature(targetSignatures[targetLen - len + i]), skipParameters);
|
||||
}
|
||||
}
|
||||
|
||||
function inferFromSignature(source: Signature, target: Signature) {
|
||||
forEachMatchingParameterType(source, target, inferFromContravariantTypes);
|
||||
|
||||
function inferFromSignature(source: Signature, target: Signature, skipParameters: boolean) {
|
||||
if (!skipParameters) {
|
||||
forEachMatchingParameterType(source, target, inferFromContravariantTypes);
|
||||
}
|
||||
const sourceTypePredicate = getTypePredicateOfSignature(source);
|
||||
const targetTypePredicate = getTypePredicateOfSignature(target);
|
||||
if (sourceTypePredicate && targetTypePredicate && sourceTypePredicate.kind === targetTypePredicate.kind) {
|
||||
@@ -13638,10 +13673,11 @@ namespace ts {
|
||||
if (!inferredType) {
|
||||
const signature = context.signature;
|
||||
if (signature) {
|
||||
if (inference.contraCandidates) {
|
||||
// If we have contravariant inferences we find the best common subtype and treat
|
||||
// that as a single covariant candidate.
|
||||
inference.candidates = append(inference.candidates, getContravariantInference(inference));
|
||||
if (inference.contraCandidates && (!inference.candidates || inference.candidates.length === 1 && inference.candidates[0].flags & TypeFlags.Never)) {
|
||||
// If we have contravariant inferences, but no covariant inferences or a single
|
||||
// covariant inference of 'never', we find the best common subtype and treat that
|
||||
// as a single covariant candidate.
|
||||
inference.candidates = [getContravariantInference(inference)];
|
||||
inference.contraCandidates = undefined;
|
||||
}
|
||||
if (inference.candidates) {
|
||||
@@ -14123,10 +14159,10 @@ namespace ts {
|
||||
getInitialTypeOfBindingElement(node);
|
||||
}
|
||||
|
||||
function getInitialOrAssignedType(node: VariableDeclaration | BindingElement | Expression) {
|
||||
return node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ?
|
||||
function getInitialOrAssignedType(node: VariableDeclaration | BindingElement | Expression, reference: Node) {
|
||||
return getConstraintForLocation(node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ?
|
||||
getInitialType(<VariableDeclaration | BindingElement>node) :
|
||||
getAssignedType(node);
|
||||
getAssignedType(node), reference);
|
||||
}
|
||||
|
||||
function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) {
|
||||
@@ -14407,8 +14443,8 @@ namespace ts {
|
||||
return resultType;
|
||||
|
||||
function getTypeAtFlowNode(flow: FlowNode): FlowType {
|
||||
if (flowDepth === 2500) {
|
||||
// We have made 2500 recursive invocations. To avoid overflowing the call stack we report an error
|
||||
if (flowDepth === 2000) {
|
||||
// We have made 2000 recursive invocations. To avoid overflowing the call stack we report an error
|
||||
// and disable further control flow analysis in the containing function or module body.
|
||||
flowAnalysisDisabled = true;
|
||||
reportFlowControlError(reference);
|
||||
@@ -14512,11 +14548,11 @@ namespace ts {
|
||||
if (isEmptyArrayAssignment(node)) {
|
||||
return getEvolvingArrayType(neverType);
|
||||
}
|
||||
const assignedType = getBaseTypeOfLiteralType(getInitialOrAssignedType(node));
|
||||
const assignedType = getBaseTypeOfLiteralType(getInitialOrAssignedType(node, reference));
|
||||
return isTypeAssignableTo(assignedType, declaredType) ? assignedType : anyArrayType;
|
||||
}
|
||||
if (declaredType.flags & TypeFlags.Union) {
|
||||
return getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node));
|
||||
return getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node, reference));
|
||||
}
|
||||
return declaredType;
|
||||
}
|
||||
@@ -14548,7 +14584,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const indexType = getTypeOfExpression((<ElementAccessExpression>node.left).argumentExpression);
|
||||
// We must get the context free expression type so as to not recur in an uncached fashion on the LHS (which causes exponential blowup in compile time)
|
||||
const indexType = getContextFreeTypeOfExpression((<ElementAccessExpression>node.left).argumentExpression);
|
||||
if (isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) {
|
||||
evolvedType = addEvolvingArrayElementType(evolvedType, node.right);
|
||||
}
|
||||
@@ -18356,7 +18393,7 @@ namespace ts {
|
||||
return errorType;
|
||||
}
|
||||
|
||||
const indexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : checkExpression(indexExpression);
|
||||
const indexType = checkExpression(indexExpression);
|
||||
|
||||
if (objectType === errorType || objectType === silentNeverType) {
|
||||
return objectType;
|
||||
@@ -18367,7 +18404,7 @@ namespace ts {
|
||||
return errorType;
|
||||
}
|
||||
|
||||
return checkIndexedAccessIndexType(getIndexedAccessType(objectType, indexType, node), node);
|
||||
return checkIndexedAccessIndexType(getIndexedAccessType(objectType, isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType, node), node);
|
||||
}
|
||||
|
||||
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
|
||||
@@ -18609,7 +18646,7 @@ namespace ts {
|
||||
return getInferredTypes(context);
|
||||
}
|
||||
|
||||
function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray<Expression>, excludeArgument: boolean[] | undefined, context: InferenceContext): Type[] {
|
||||
function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray<Expression>, excludeArgument: ReadonlyArray<boolean> | undefined, context: InferenceContext): Type[] {
|
||||
// Clear out all the inference results from the last time inferTypeArguments was called on this context
|
||||
for (const inference of context.inferences) {
|
||||
// As an optimization, we don't have to clear (and later recompute) inferred types
|
||||
@@ -19023,19 +19060,7 @@ namespace ts {
|
||||
// For a decorator, no arguments are susceptible to contextual typing due to the fact
|
||||
// decorators are applied to a declaration by the emitter, and not to an expression.
|
||||
const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters;
|
||||
let excludeArgument: boolean[] | undefined;
|
||||
if (!isDecorator && !isSingleNonGenericCandidate) {
|
||||
// We do not need to call `getEffectiveArgumentCount` here as it only
|
||||
// applies when calculating the number of arguments for a decorator.
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (isContextSensitive(args[i])) {
|
||||
if (!excludeArgument) {
|
||||
excludeArgument = new Array(args.length);
|
||||
}
|
||||
excludeArgument[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
let excludeArgument = !isDecorator && !isSingleNonGenericCandidate ? getExcludeArgument(args) : undefined;
|
||||
|
||||
// The following variables are captured and modified by calls to chooseOverload.
|
||||
// If overload resolution or type argument inference fails, we want to report the
|
||||
@@ -19198,6 +19223,21 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getExcludeArgument(args: ReadonlyArray<Expression>): boolean[] | undefined {
|
||||
let excludeArgument: boolean[] | undefined;
|
||||
// We do not need to call `getEffectiveArgumentCount` here as it only
|
||||
// applies when calculating the number of arguments for a decorator.
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (isContextSensitive(args[i])) {
|
||||
if (!excludeArgument) {
|
||||
excludeArgument = new Array(args.length);
|
||||
}
|
||||
excludeArgument[i] = true;
|
||||
}
|
||||
}
|
||||
return excludeArgument;
|
||||
}
|
||||
|
||||
// No signature was applicable. We have already reported the errors for the invalid signature.
|
||||
// If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
|
||||
function getCandidateForOverloadFailure(
|
||||
@@ -19276,17 +19316,29 @@ namespace ts {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
const typeArgumentNodes: ReadonlyArray<TypeNode> = callLikeExpressionMayHaveTypeArguments(node) ? node.typeArguments || emptyArray : emptyArray;
|
||||
const typeArgumentNodes: ReadonlyArray<TypeNode> | undefined = callLikeExpressionMayHaveTypeArguments(node) ? node.typeArguments : undefined;
|
||||
const instantiated = typeArgumentNodes
|
||||
? createSignatureInstantiation(candidate, getTypeArgumentsFromNodes(typeArgumentNodes, typeParameters, isInJavaScriptFile(node)))
|
||||
: inferSignatureInstantiationForOverloadFailure(node, typeParameters, candidate, args);
|
||||
candidates[bestIndex] = instantiated;
|
||||
return instantiated;
|
||||
}
|
||||
|
||||
function getTypeArgumentsFromNodes(typeArgumentNodes: ReadonlyArray<TypeNode>, typeParameters: ReadonlyArray<TypeParameter>, isJs: boolean): ReadonlyArray<Type> {
|
||||
const typeArguments = typeArgumentNodes.map(getTypeOfNode);
|
||||
while (typeArguments.length > typeParameters.length) {
|
||||
typeArguments.pop();
|
||||
}
|
||||
while (typeArguments.length < typeParameters.length) {
|
||||
typeArguments.push(getConstraintOfTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isInJavaScriptFile(node)));
|
||||
typeArguments.push(getConstraintOfTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isJs));
|
||||
}
|
||||
const instantiated = createSignatureInstantiation(candidate, typeArguments);
|
||||
candidates[bestIndex] = instantiated;
|
||||
return instantiated;
|
||||
return typeArguments;
|
||||
}
|
||||
|
||||
function inferSignatureInstantiationForOverloadFailure(node: CallLikeExpression, typeParameters: ReadonlyArray<TypeParameter>, candidate: Signature, args: ReadonlyArray<Expression>): Signature {
|
||||
const inferenceContext = createInferenceContext(typeParameters, candidate, /*flags*/ isInJavaScriptFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
|
||||
const typeArgumentTypes = inferTypeArguments(node, candidate, args, getExcludeArgument(args), inferenceContext);
|
||||
return createSignatureInstantiation(candidate, typeArgumentTypes);
|
||||
}
|
||||
|
||||
function getLongestCandidateIndex(candidates: Signature[], argsCount: number): number {
|
||||
@@ -20549,8 +20601,10 @@ namespace ts {
|
||||
return links.contextFreeType;
|
||||
}
|
||||
const returnType = getReturnTypeFromBody(node, checkMode);
|
||||
const singleReturnSignature = createSignature(undefined, undefined, undefined, emptyArray, returnType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||
return links.contextFreeType = createAnonymousType(node.symbol, emptySymbols, [singleReturnSignature], emptyArray, undefined, undefined);
|
||||
const returnOnlySignature = createSignature(undefined, undefined, undefined, emptyArray, returnType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||
const returnOnlyType = createAnonymousType(node.symbol, emptySymbols, [returnOnlySignature], emptyArray, undefined, undefined);
|
||||
returnOnlyType.flags |= TypeFlags.ContainsAnyFunctionType;
|
||||
return links.contextFreeType = returnOnlyType;
|
||||
}
|
||||
return anyFunctionType;
|
||||
}
|
||||
@@ -21671,15 +21725,19 @@ namespace ts {
|
||||
* to cache the result.
|
||||
*/
|
||||
function getTypeOfExpression(node: Expression, cache?: boolean) {
|
||||
const expr = skipParentheses(node);
|
||||
// Optimize for the common case of a call to a function with a single non-generic call
|
||||
// signature where we can just fetch the return type without checking the arguments.
|
||||
if (node.kind === SyntaxKind.CallExpression && (<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(node)) {
|
||||
const funcType = checkNonNullExpression((<CallExpression>node).expression);
|
||||
if (expr.kind === SyntaxKind.CallExpression && (<CallExpression>expr).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
|
||||
const funcType = checkNonNullExpression((<CallExpression>expr).expression);
|
||||
const signature = getSingleCallSignature(funcType);
|
||||
if (signature && !signature.typeParameters) {
|
||||
return getReturnTypeOfSignature(signature);
|
||||
}
|
||||
}
|
||||
else if (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
|
||||
return getTypeFromTypeNode((<TypeAssertion>expr).type);
|
||||
}
|
||||
// Otherwise simply call checkExpression. Ideally, the entire family of checkXXX functions
|
||||
// should have a parameter that indicates whether full error checking is required such that
|
||||
// we can perform the optimizations locally.
|
||||
@@ -21694,9 +21752,13 @@ namespace ts {
|
||||
* It sets the contextual type of the node to any before calling getTypeOfExpression.
|
||||
*/
|
||||
function getContextFreeTypeOfExpression(node: Expression) {
|
||||
const links = getNodeLinks(node);
|
||||
if (links.contextFreeType) {
|
||||
return links.contextFreeType;
|
||||
}
|
||||
const saveContextualType = node.contextualType;
|
||||
node.contextualType = anyType;
|
||||
const type = getTypeOfExpression(node);
|
||||
const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
|
||||
node.contextualType = saveContextualType;
|
||||
return type;
|
||||
}
|
||||
@@ -24219,7 +24281,7 @@ namespace ts {
|
||||
if (nameText) {
|
||||
const property = getPropertyOfType(parentType!, nameText)!; // TODO: GH#18217
|
||||
markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isThisAccess*/ false); // A destructuring is never a write-only reference.
|
||||
if (parent.initializer && property && !isComputedPropertyName(name)) {
|
||||
if (parent.initializer && property) {
|
||||
checkPropertyAccessibility(parent, parent.initializer.kind === SyntaxKind.SuperKeyword, parentType!, property);
|
||||
}
|
||||
}
|
||||
@@ -27238,6 +27300,7 @@ namespace ts {
|
||||
case SyntaxKind.DefaultKeyword:
|
||||
case SyntaxKind.FunctionKeyword:
|
||||
case SyntaxKind.EqualsGreaterThanToken:
|
||||
case SyntaxKind.ClassKeyword:
|
||||
return getSymbolOfNode(node.parent);
|
||||
case SyntaxKind.ImportType:
|
||||
return isLiteralImportTypeNode(node) ? getSymbolAtLocation(node.argument.literal) : undefined;
|
||||
@@ -27731,6 +27794,27 @@ namespace ts {
|
||||
hasModifier(parameter, ModifierFlags.ParameterPropertyModifier);
|
||||
}
|
||||
|
||||
function isJSContainerFunctionDeclaration(node: Declaration): boolean {
|
||||
const declaration = getParseTreeNode(node, isFunctionDeclaration);
|
||||
if (!declaration) {
|
||||
return false;
|
||||
}
|
||||
const symbol = getSymbolOfNode(declaration);
|
||||
if (!symbol || !(symbol.flags & SymbolFlags.Function)) {
|
||||
return false;
|
||||
}
|
||||
return !!forEachEntry(getExportsOfSymbol(symbol), p => isPropertyAccessExpression(p.valueDeclaration));
|
||||
}
|
||||
|
||||
function getPropertiesOfContainerFunction(node: Declaration): Symbol[] {
|
||||
const declaration = getParseTreeNode(node, isFunctionDeclaration);
|
||||
if (!declaration) {
|
||||
return emptyArray;
|
||||
}
|
||||
const symbol = getSymbolOfNode(declaration);
|
||||
return symbol && getPropertiesOfType(getTypeOfSymbol(symbol)) || emptyArray;
|
||||
}
|
||||
|
||||
function getNodeCheckFlags(node: Node): NodeCheckFlags {
|
||||
return getNodeLinks(node).flags || 0;
|
||||
}
|
||||
@@ -27838,7 +27922,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createTypeOfDeclaration(declarationIn: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean) {
|
||||
function createTypeOfDeclaration(declarationIn: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean) {
|
||||
const declaration = getParseTreeNode(declarationIn, isVariableLikeOrAccessor);
|
||||
if (!declaration) {
|
||||
return createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode;
|
||||
@@ -27971,6 +28055,8 @@ namespace ts {
|
||||
isImplementationOfOverload,
|
||||
isRequiredInitializedParameter,
|
||||
isOptionalUninitializedParameterProperty,
|
||||
isJSContainerFunctionDeclaration,
|
||||
getPropertiesOfContainerFunction,
|
||||
createTypeOfDeclaration,
|
||||
createReturnTypeOfSignatureDeclaration,
|
||||
createTypeOfExpression,
|
||||
|
||||
@@ -815,10 +815,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getOptionNameMap(): OptionNameMap {
|
||||
if (optionNameMapCache) {
|
||||
return optionNameMapCache;
|
||||
}
|
||||
return optionNameMapCache || (optionNameMapCache = createOptionNameMap(optionDeclarations));
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function createOptionNameMap(optionDeclarations: ReadonlyArray<CommandLineOption>): OptionNameMap {
|
||||
const optionNameMap = createMap<CommandLineOption>();
|
||||
const shortOptionNames = createMap<string>();
|
||||
forEach(optionDeclarations, option => {
|
||||
@@ -828,8 +829,7 @@ namespace ts {
|
||||
}
|
||||
});
|
||||
|
||||
optionNameMapCache = { optionNameMap, shortOptionNames };
|
||||
return optionNameMapCache;
|
||||
return { optionNameMap, shortOptionNames };
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -979,7 +979,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getOptionFromName(optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined {
|
||||
return getOptionDeclarationFromName(getOptionNameMap, optionName, allowShort);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
optionName = optionName.toLowerCase();
|
||||
const { optionNameMap, shortOptionNames } = getOptionNameMap();
|
||||
// Try to translate short option names to their full equivalents.
|
||||
|
||||
@@ -1964,10 +1964,6 @@
|
||||
"category": "Error",
|
||||
"code": 2549
|
||||
},
|
||||
"Generic type instantiation is excessively deep and possibly infinite.": {
|
||||
"category": "Error",
|
||||
"code": 2550
|
||||
},
|
||||
"Property '{0}' does not exist on type '{1}'. Did you mean '{2}'?": {
|
||||
"category": "Error",
|
||||
"code": 2551
|
||||
@@ -2900,6 +2896,11 @@
|
||||
"category": "Error",
|
||||
"code": 5071
|
||||
},
|
||||
"Unknown build option '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 5072
|
||||
},
|
||||
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
|
||||
@@ -1,8 +1,52 @@
|
||||
// Used by importFixes, getEditsForFileRename, and declaration emit to synthesize import module specifiers.
|
||||
/* @internal */
|
||||
namespace ts.moduleSpecifiers {
|
||||
export interface ModuleSpecifierPreferences {
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
const enum RelativePreference { Relative, NonRelative, Auto }
|
||||
// See UserPreferences#importPathEnding
|
||||
const enum Ending { Minimal, Index, JsExtension }
|
||||
|
||||
// Processed preferences
|
||||
interface Preferences {
|
||||
readonly relativePreference: RelativePreference;
|
||||
readonly ending: Ending;
|
||||
}
|
||||
|
||||
function getPreferences({ importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences, compilerOptions: CompilerOptions, importingSourceFile: SourceFile): Preferences {
|
||||
return {
|
||||
relativePreference: importModuleSpecifierPreference === "relative" ? RelativePreference.Relative : importModuleSpecifierPreference === "non-relative" ? RelativePreference.NonRelative : RelativePreference.Auto,
|
||||
ending: getEnding(),
|
||||
};
|
||||
function getEnding(): Ending {
|
||||
switch (importModuleSpecifierEnding) {
|
||||
case "minimal": return Ending.Minimal;
|
||||
case "index": return Ending.Index;
|
||||
case "js": return Ending.JsExtension;
|
||||
default: return usesJsExtensionOnImports(importingSourceFile) ? Ending.JsExtension
|
||||
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs ? Ending.Index : Ending.Minimal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getPreferencesForUpdate(compilerOptions: CompilerOptions, oldImportSpecifier: string): Preferences {
|
||||
return {
|
||||
relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative : RelativePreference.NonRelative,
|
||||
ending: hasJavaScriptOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
|
||||
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateModuleSpecifier(
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFileName: Path,
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
oldImportSpecifier: string,
|
||||
): string | undefined {
|
||||
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFileName, toFileName, host, files, redirectTargetsMap, getPreferencesForUpdate(compilerOptions, oldImportSpecifier));
|
||||
if (res === oldImportSpecifier) return undefined;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Note: importingSourceFile is just for usesJsExtensionOnImports
|
||||
@@ -13,35 +57,25 @@ namespace ts.moduleSpecifiers {
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
preferences: ModuleSpecifierPreferences = {},
|
||||
preferences: UserPreferences = {},
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
): string {
|
||||
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFileName, host);
|
||||
const modulePaths = getAllModulePaths(files, importingSourceFileName, toFileName, info.getCanonicalFileName, host, redirectTargetsMap);
|
||||
return firstDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions)) ||
|
||||
first(getLocalModuleSpecifiers(toFileName, info, compilerOptions, preferences));
|
||||
return getModuleSpecifierWorker(compilerOptions, importingSourceFileName, toFileName, host, files, redirectTargetsMap, getPreferences(preferences, compilerOptions, importingSourceFile));
|
||||
}
|
||||
|
||||
export function getModuleSpecifierForDeclarationFile(
|
||||
moduleSymbol: Symbol,
|
||||
function getModuleSpecifierWorker(
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFileName: Path,
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
preferences: Preferences
|
||||
): string {
|
||||
const isBundle = (compilerOptions.out || compilerOptions.outFile);
|
||||
if (isBundle && host.getCommonSourceDirectory) {
|
||||
// For declaration bundles, we need to generate absolute paths relative to the common source dir for imports,
|
||||
// just like how the declaration emitter does for the ambient module declarations - we can easily accomplish this
|
||||
// using the `baseUrl` compiler option (which we would otherwise never use in declaration emit) and a non-relative
|
||||
// specifier preference
|
||||
compilerOptions = {
|
||||
...compilerOptions,
|
||||
baseUrl: host.getCommonSourceDirectory(),
|
||||
};
|
||||
}
|
||||
const preferences: ModuleSpecifierPreferences = { importModuleSpecifierPreference: isBundle ? "non-relative" : "relative" };
|
||||
return first(first(getModuleSpecifiers(moduleSymbol, compilerOptions, importingSourceFile, host, host.getSourceFiles ? host.getSourceFiles() : [importingSourceFile], preferences, redirectTargetsMap)));
|
||||
const info = getInfo(importingSourceFileName, host);
|
||||
const modulePaths = getAllModulePaths(files, importingSourceFileName, toFileName, info.getCanonicalFileName, host, redirectTargetsMap);
|
||||
return firstDefined(modulePaths, moduleFileName => tryGetModuleNameAsNodeModule(moduleFileName, info, host, compilerOptions)) ||
|
||||
first(getLocalModuleSpecifiers(toFileName, info, compilerOptions, preferences));
|
||||
}
|
||||
|
||||
// For each symlink/original for a module, returns a list of ways to import that file.
|
||||
@@ -51,60 +85,39 @@ namespace ts.moduleSpecifiers {
|
||||
importingSourceFile: SourceFile,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
preferences: ModuleSpecifierPreferences,
|
||||
userPreferences: UserPreferences,
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
): ReadonlyArray<ReadonlyArray<string>> {
|
||||
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
|
||||
if (ambient) return [[ambient]];
|
||||
|
||||
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFile.path, host);
|
||||
if (!files) {
|
||||
return Debug.fail("Files list must be present to resolve symlinks in specifier resolution");
|
||||
}
|
||||
const info = getInfo(importingSourceFile.path, host);
|
||||
const moduleSourceFile = getSourceFileOfNode(moduleSymbol.valueDeclaration || getNonAugmentationDeclaration(moduleSymbol));
|
||||
const modulePaths = getAllModulePaths(files, importingSourceFile.path, moduleSourceFile.fileName, info.getCanonicalFileName, host, redirectTargetsMap);
|
||||
|
||||
const global = mapDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions));
|
||||
const preferences = getPreferences(userPreferences, compilerOptions, importingSourceFile);
|
||||
const global = mapDefined(modulePaths, moduleFileName => tryGetModuleNameAsNodeModule(moduleFileName, info, host, compilerOptions));
|
||||
return global.length ? global.map(g => [g]) : modulePaths.map(moduleFileName =>
|
||||
getLocalModuleSpecifiers(moduleFileName, info, compilerOptions, preferences));
|
||||
}
|
||||
|
||||
interface Info {
|
||||
readonly moduleResolutionKind: ModuleResolutionKind;
|
||||
readonly addJsExtension: boolean;
|
||||
readonly getCanonicalFileName: GetCanonicalFileName;
|
||||
readonly sourceDirectory: Path;
|
||||
}
|
||||
// importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path
|
||||
function getInfo(compilerOptions: CompilerOptions, importingSourceFile: SourceFile, importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info {
|
||||
const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions);
|
||||
const addJsExtension = usesJsExtensionOnImports(importingSourceFile);
|
||||
function getInfo(importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info {
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true);
|
||||
const sourceDirectory = getDirectoryPath(importingSourceFileName);
|
||||
return { moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory };
|
||||
return { getCanonicalFileName, sourceDirectory };
|
||||
}
|
||||
|
||||
function getGlobalModuleSpecifier(
|
||||
moduleFileName: string,
|
||||
{ addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
compilerOptions: CompilerOptions,
|
||||
) {
|
||||
return tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension)
|
||||
|| tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory);
|
||||
}
|
||||
|
||||
function getLocalModuleSpecifiers(
|
||||
moduleFileName: string,
|
||||
{ moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
|
||||
compilerOptions: CompilerOptions,
|
||||
preferences: ModuleSpecifierPreferences,
|
||||
): ReadonlyArray<string> {
|
||||
function getLocalModuleSpecifiers(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, compilerOptions: CompilerOptions, { ending, relativePreference }: Preferences): ReadonlyArray<string> {
|
||||
const { baseUrl, paths, rootDirs } = compilerOptions;
|
||||
|
||||
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName) ||
|
||||
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), moduleResolutionKind, addJsExtension);
|
||||
if (!baseUrl || preferences.importModuleSpecifierPreference === "relative") {
|
||||
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), ending, compilerOptions);
|
||||
if (!baseUrl || relativePreference === RelativePreference.Relative) {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
@@ -113,7 +126,7 @@ namespace ts.moduleSpecifiers {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, moduleResolutionKind, addJsExtension);
|
||||
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions);
|
||||
if (paths) {
|
||||
const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
|
||||
if (fromPaths) {
|
||||
@@ -121,11 +134,11 @@ namespace ts.moduleSpecifiers {
|
||||
}
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference === "non-relative") {
|
||||
if (relativePreference === RelativePreference.NonRelative) {
|
||||
return [importRelativeToBaseUrl];
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference !== undefined) Debug.assertNever(preferences.importModuleSpecifierPreference);
|
||||
if (relativePreference !== RelativePreference.Auto) Debug.assertNever(relativePreference);
|
||||
|
||||
if (isPathRelativeToParent(relativeToBaseUrl)) {
|
||||
return [relativePath];
|
||||
@@ -164,7 +177,7 @@ namespace ts.moduleSpecifiers {
|
||||
}
|
||||
|
||||
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false;
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJavaScriptOrJsonFileExtension(text) : undefined) || false;
|
||||
}
|
||||
|
||||
function stringsEqual(a: string, b: string, getCanonicalFileName: GetCanonicalFileName): boolean {
|
||||
@@ -284,37 +297,8 @@ namespace ts.moduleSpecifiers {
|
||||
return removeFileExtension(relativePath);
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromTypeRoots(
|
||||
options: CompilerOptions,
|
||||
host: GetEffectiveTypeRootsHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
moduleFileName: string,
|
||||
addJsExtension: boolean,
|
||||
): string | undefined {
|
||||
const roots = getEffectiveTypeRoots(options, host);
|
||||
return firstDefined(roots, unNormalizedTypeRoot => {
|
||||
const typeRoot = toPath(unNormalizedTypeRoot, /*basePath*/ undefined, getCanonicalFileName);
|
||||
if (startsWith(moduleFileName, typeRoot)) {
|
||||
// For a type definition, we can strip `/index` even with classic resolution.
|
||||
return removeExtensionAndIndexPostFix(moduleFileName.substring(typeRoot.length + 1), ModuleResolutionKind.NodeJs, addJsExtension);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function tryGetModuleNameAsNodeModule(
|
||||
options: CompilerOptions,
|
||||
moduleFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
sourceDirectory: Path,
|
||||
): string | undefined {
|
||||
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {
|
||||
// nothing to do here
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryGetModuleNameAsNodeModule(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, host: ModuleSpecifierResolutionHost, options: CompilerOptions): string | undefined {
|
||||
const parts: NodeModulePathParts = getNodeModulePathParts(moduleFileName)!;
|
||||
|
||||
if (!parts) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -331,7 +315,7 @@ namespace ts.moduleSpecifiers {
|
||||
const subModuleName = moduleFileName.slice(parts.packageRootIndex + 1);
|
||||
const fromPaths = tryGetModuleNameFromPaths(
|
||||
removeFileExtension(subModuleName),
|
||||
removeExtensionAndIndexPostFix(subModuleName, ModuleResolutionKind.NodeJs, /*addJsExtension*/ false),
|
||||
removeExtensionAndIndexPostFix(subModuleName, Ending.Minimal, options),
|
||||
versionPaths.paths
|
||||
);
|
||||
if (fromPaths !== undefined) {
|
||||
@@ -346,8 +330,12 @@ namespace ts.moduleSpecifiers {
|
||||
// Get a path that's relative to node_modules or the importing file's path
|
||||
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
|
||||
if (!startsWith(sourceDirectory, getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex)))) return undefined;
|
||||
|
||||
// If the module was found in @types, get the actual Node package name
|
||||
return getPackageNameFromTypesPackageName(moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1));
|
||||
const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1);
|
||||
const packageName = getPackageNameFromTypesPackageName(nodeModulesDirectoryName);
|
||||
// For classic resolution, only allow importing from node_modules/@types, not other node_modules
|
||||
return getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs && packageName === nodeModulesDirectoryName ? undefined : packageName;
|
||||
|
||||
function getDirectoryOrExtensionlessFileName(path: string): string {
|
||||
// If the file is the main module, it can be imported by the package name
|
||||
@@ -456,13 +444,36 @@ namespace ts.moduleSpecifiers {
|
||||
});
|
||||
}
|
||||
|
||||
function removeExtensionAndIndexPostFix(fileName: string, moduleResolutionKind: ModuleResolutionKind, addJsExtension: boolean): string {
|
||||
function removeExtensionAndIndexPostFix(fileName: string, ending: Ending, options: CompilerOptions): string {
|
||||
if (fileExtensionIs(fileName, Extension.Json)) return fileName;
|
||||
const noExtension = removeFileExtension(fileName);
|
||||
return addJsExtension
|
||||
? noExtension + ".js"
|
||||
: moduleResolutionKind === ModuleResolutionKind.NodeJs
|
||||
? removeSuffix(noExtension, "/index")
|
||||
: noExtension;
|
||||
switch (ending) {
|
||||
case Ending.Minimal:
|
||||
return removeSuffix(noExtension, "/index");
|
||||
case Ending.Index:
|
||||
return noExtension;
|
||||
case Ending.JsExtension:
|
||||
return noExtension + getJavaScriptExtensionForFile(fileName, options);
|
||||
default:
|
||||
return Debug.assertNever(ending);
|
||||
}
|
||||
}
|
||||
|
||||
function getJavaScriptExtensionForFile(fileName: string, options: CompilerOptions): Extension {
|
||||
const ext = extensionFromPath(fileName);
|
||||
switch (ext) {
|
||||
case Extension.Ts:
|
||||
case Extension.Dts:
|
||||
return Extension.Js;
|
||||
case Extension.Tsx:
|
||||
return options.jsx === JsxEmit.Preserve ? Extension.Jsx : Extension.Js;
|
||||
case Extension.Js:
|
||||
case Extension.Jsx:
|
||||
case Extension.Json:
|
||||
return ext;
|
||||
default:
|
||||
return Debug.assertNever(ext);
|
||||
}
|
||||
}
|
||||
|
||||
function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined {
|
||||
|
||||
@@ -515,7 +515,7 @@ namespace ts {
|
||||
performance.mark("beforeParse");
|
||||
let result: SourceFile;
|
||||
if (languageVersion === ScriptTarget.JSON) {
|
||||
result = Parser.parseJsonText(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes);
|
||||
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON);
|
||||
}
|
||||
else {
|
||||
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind);
|
||||
@@ -689,8 +689,12 @@ namespace ts {
|
||||
if (scriptKind === ScriptKind.JSON) {
|
||||
const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes);
|
||||
convertToObjectWorker(result, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined);
|
||||
result.referencedFiles = emptyArray;
|
||||
result.typeReferenceDirectives = emptyArray;
|
||||
result.libReferenceDirectives = emptyArray;
|
||||
result.amdDependencies = emptyArray;
|
||||
result.hasNoDefaultLib = false;
|
||||
result.pragmas = emptyMap;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -7754,7 +7758,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void;
|
||||
|
||||
/*@internal*/
|
||||
|
||||
+36
-41
@@ -67,19 +67,24 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
|
||||
return createCompilerHostWorker(options, setParentNodes);
|
||||
}
|
||||
/*@internal*/
|
||||
// TODO(shkamat): update this after reworking ts build API
|
||||
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
|
||||
const existingDirectories = createMap<boolean>();
|
||||
|
||||
function getCanonicalFileName(fileName: string): string {
|
||||
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
|
||||
// otherwise use toLowerCase as a canonical form.
|
||||
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
return system.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined {
|
||||
let text: string | undefined;
|
||||
try {
|
||||
performance.mark("beforeIORead");
|
||||
text = sys.readFile(fileName, options.charset);
|
||||
text = system.readFile(fileName, options.charset);
|
||||
performance.mark("afterIORead");
|
||||
performance.measure("I/O Read", "beforeIORead", "afterIORead");
|
||||
}
|
||||
@@ -97,7 +102,7 @@ namespace ts {
|
||||
if (existingDirectories.has(directoryPath)) {
|
||||
return true;
|
||||
}
|
||||
if (sys.directoryExists(directoryPath)) {
|
||||
if (system.directoryExists(directoryPath)) {
|
||||
existingDirectories.set(directoryPath, true);
|
||||
return true;
|
||||
}
|
||||
@@ -108,7 +113,7 @@ namespace ts {
|
||||
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
|
||||
const parentDirectory = getDirectoryPath(directoryPath);
|
||||
ensureDirectoriesExist(parentDirectory);
|
||||
sys.createDirectory(directoryPath);
|
||||
system.createDirectory(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,8 +124,8 @@ namespace ts {
|
||||
outputFingerprints = createMap<OutputFingerprint>();
|
||||
}
|
||||
|
||||
const hash = sys.createHash!(data); // TODO: GH#18217
|
||||
const mtimeBefore = sys.getModifiedTime!(fileName); // TODO: GH#18217
|
||||
const hash = system.createHash!(data); // TODO: GH#18217
|
||||
const mtimeBefore = system.getModifiedTime!(fileName); // TODO: GH#18217
|
||||
|
||||
if (mtimeBefore) {
|
||||
const fingerprint = outputFingerprints.get(fileName);
|
||||
@@ -133,9 +138,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
system.writeFile(fileName, data, writeByteOrderMark);
|
||||
|
||||
const mtimeAfter = sys.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
|
||||
const mtimeAfter = system.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
|
||||
|
||||
outputFingerprints.set(fileName, {
|
||||
hash,
|
||||
@@ -149,11 +154,11 @@ namespace ts {
|
||||
performance.mark("beforeIOWrite");
|
||||
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
||||
|
||||
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
|
||||
if (isWatchSet(options) && system.createHash && system.getModifiedTime) {
|
||||
writeFileIfUpdated(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
else {
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
system.writeFile(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
|
||||
performance.mark("afterIOWrite");
|
||||
@@ -167,32 +172,29 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getDefaultLibLocation(): string {
|
||||
return getDirectoryPath(normalizePath(sys.getExecutingFilePath()));
|
||||
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
|
||||
}
|
||||
|
||||
const newLine = getNewLineCharacter(options);
|
||||
const realpath = sys.realpath && ((path: string) => sys.realpath!(path));
|
||||
const newLine = getNewLineCharacter(options, () => system.newLine);
|
||||
const realpath = system.realpath && ((path: string) => system.realpath!(path));
|
||||
|
||||
return {
|
||||
getSourceFile,
|
||||
getDefaultLibLocation,
|
||||
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
|
||||
writeFile,
|
||||
getCurrentDirectory: memoize(() => sys.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
||||
getCurrentDirectory: memoize(() => system.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
|
||||
getCanonicalFileName,
|
||||
getNewLine: () => newLine,
|
||||
fileExists: fileName => sys.fileExists(fileName),
|
||||
readFile: fileName => sys.readFile(fileName),
|
||||
trace: (s: string) => sys.write(s + newLine),
|
||||
directoryExists: directoryName => sys.directoryExists(directoryName),
|
||||
getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
|
||||
getDirectories: (path: string) => sys.getDirectories(path),
|
||||
fileExists: fileName => system.fileExists(fileName),
|
||||
readFile: fileName => system.readFile(fileName),
|
||||
trace: (s: string) => system.write(s + newLine),
|
||||
directoryExists: directoryName => system.directoryExists(directoryName),
|
||||
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
|
||||
getDirectories: (path: string) => system.getDirectories(path),
|
||||
realpath,
|
||||
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth),
|
||||
getModifiedTime: sys.getModifiedTime && (path => sys.getModifiedTime!(path)),
|
||||
setModifiedTime: sys.setModifiedTime && ((path, date) => sys.setModifiedTime!(path, date)),
|
||||
deleteFile: sys.deleteFile && (path => sys.deleteFile!(path))
|
||||
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2319,27 +2321,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string {
|
||||
const fileNames: string[] = [];
|
||||
for (const file of sourceFiles) {
|
||||
if (!file.isDeclarationFile) {
|
||||
fileNames.push(file.fileName);
|
||||
}
|
||||
}
|
||||
const fileNames = mapDefined(sourceFiles, file => file.isDeclarationFile ? undefined : file.fileName);
|
||||
return computeCommonSourceDirectoryOfFilenames(fileNames, currentDirectory, getCanonicalFileName);
|
||||
}
|
||||
|
||||
function checkSourceFilesBelongToPath(sourceFiles: SourceFile[], rootDirectory: string): boolean {
|
||||
function checkSourceFilesBelongToPath(sourceFiles: ReadonlyArray<SourceFile>, rootDirectory: string): boolean {
|
||||
let allFilesBelongToPath = true;
|
||||
if (sourceFiles) {
|
||||
const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
|
||||
const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
|
||||
|
||||
for (const sourceFile of sourceFiles) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
|
||||
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
|
||||
allFilesBelongToPath = false;
|
||||
}
|
||||
for (const sourceFile of sourceFiles) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
|
||||
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
|
||||
allFilesBelongToPath = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -978,7 +978,7 @@ namespace ts {
|
||||
}
|
||||
case SyntaxKind.FunctionDeclaration: {
|
||||
// Generators lose their generator-ness, excepting their return type
|
||||
return cleanup(updateFunctionDeclaration(
|
||||
const clean = cleanup(updateFunctionDeclaration(
|
||||
input,
|
||||
/*decorators*/ undefined,
|
||||
ensureModifiers(input, isPrivate),
|
||||
@@ -989,6 +989,21 @@ namespace ts {
|
||||
ensureType(input, input.type),
|
||||
/*body*/ undefined
|
||||
));
|
||||
if (clean && resolver.isJSContainerFunctionDeclaration(input)) {
|
||||
const declarations = mapDefined(resolver.getPropertiesOfContainerFunction(input), p => {
|
||||
if (!isPropertyAccessExpression(p.valueDeclaration)) {
|
||||
return undefined;
|
||||
}
|
||||
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker);
|
||||
const varDecl = createVariableDeclaration(unescapeLeadingUnderscores(p.escapedName), type, /*initializer*/ undefined);
|
||||
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([varDecl]));
|
||||
});
|
||||
const namespaceDecl = createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input, isPrivate), input.name!, createModuleBlock(declarations), NodeFlags.Namespace);
|
||||
return [clean, namespaceDecl];
|
||||
}
|
||||
else {
|
||||
return clean;
|
||||
}
|
||||
}
|
||||
case SyntaxKind.ModuleDeclaration: {
|
||||
needsDeclare = false;
|
||||
|
||||
+397
-404
File diff suppressed because it is too large
Load Diff
+29
-20
@@ -2632,7 +2632,7 @@ namespace ts {
|
||||
/* @internal */ ambientModuleNames: ReadonlyArray<string>;
|
||||
/* @internal */ checkJsDirective?: CheckJsDirective;
|
||||
/* @internal */ version: string;
|
||||
/* @internal */ pragmas: PragmaMap;
|
||||
/* @internal */ pragmas: ReadonlyPragmaMap;
|
||||
/* @internal */ localJsxNamespace?: __String;
|
||||
/* @internal */ localJsxFactory?: EntityName;
|
||||
|
||||
@@ -3097,6 +3097,10 @@ namespace ts {
|
||||
*/
|
||||
/* @internal */ getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] | undefined;
|
||||
/* @internal */ getTypePredicateOfSignature(signature: Signature): TypePredicate;
|
||||
/**
|
||||
* An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
|
||||
* and an external module with no 'export =' declaration resolves to the module itself.
|
||||
*/
|
||||
/* @internal */ resolveExternalModuleSymbol(symbol: Symbol): Symbol;
|
||||
/** @param node A location where we might consider accessing `this`. Not necessarily a ThisExpression. */
|
||||
/* @internal */ tryGetThisTypeAt(node: Node): Type | undefined;
|
||||
@@ -3114,6 +3118,8 @@ namespace ts {
|
||||
* and the operation is cancelled, then it should be discarded, otherwise it is safe to keep.
|
||||
*/
|
||||
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;
|
||||
|
||||
/* @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): ReadonlyArray<TypeParameter> | undefined;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -3374,7 +3380,9 @@ namespace ts {
|
||||
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
|
||||
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
|
||||
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
|
||||
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
|
||||
isJSContainerFunctionDeclaration(node: FunctionDeclaration): boolean;
|
||||
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
|
||||
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
|
||||
createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
|
||||
createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
|
||||
createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): Expression;
|
||||
@@ -4715,16 +4723,6 @@ namespace ts {
|
||||
verticalTab = 0x0B, // \v
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface UpToDateHost {
|
||||
fileExists(fileName: string): boolean;
|
||||
getModifiedTime(fileName: string): Date | undefined;
|
||||
getUnchangedTime?(fileName: string): Date | undefined;
|
||||
getLastStatus?(fileName: string): UpToDateStatus | undefined;
|
||||
setLastStatus?(fileName: string, status: UpToDateStatus): void;
|
||||
parseConfigFile?(configFilePath: ResolvedConfigFileName): ParsedCommandLine | undefined;
|
||||
}
|
||||
|
||||
export interface ModuleResolutionHost {
|
||||
// TODO: GH#18217 Optional methods frequently used as non-optional
|
||||
|
||||
@@ -4855,10 +4853,6 @@ namespace ts {
|
||||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
|
||||
createHash?(data: string): string;
|
||||
|
||||
getModifiedTime?(fileName: string): Date | undefined;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -5343,8 +5337,6 @@ namespace ts {
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
fileExists?(path: string): boolean;
|
||||
readFile?(path: string): string | undefined;
|
||||
getSourceFiles?(): ReadonlyArray<SourceFile>; // Used for cached resolutions to find symlinks without traversing the fs (again)
|
||||
getCommonSourceDirectory?(): string;
|
||||
}
|
||||
|
||||
// Note: this used to be deprecated in our public API, but is still used internally
|
||||
@@ -5357,7 +5349,7 @@ namespace ts {
|
||||
reportInaccessibleThisError?(): void;
|
||||
reportPrivateInBaseOfClassExpression?(propertyName: string): void;
|
||||
reportInaccessibleUniqueSymbolError?(): void;
|
||||
moduleResolverHost?: ModuleSpecifierResolutionHost;
|
||||
moduleResolverHost?: EmitHost;
|
||||
trackReferencedAmbientModule?(decl: ModuleDeclaration, symbol: Symbol): void;
|
||||
trackExternalModuleSymbolOfImportTypeNode?(symbol: Symbol): void;
|
||||
}
|
||||
@@ -5596,15 +5588,32 @@ namespace ts {
|
||||
/* @internal */
|
||||
export type PragmaPsuedoMapEntry = {[K in keyof PragmaPsuedoMap]: {name: K, args: PragmaPsuedoMap[K]}}[keyof PragmaPsuedoMap];
|
||||
|
||||
/* @internal */
|
||||
export interface ReadonlyPragmaMap extends ReadonlyMap<PragmaPsuedoMap[keyof PragmaPsuedoMap] | PragmaPsuedoMap[keyof PragmaPsuedoMap][]> {
|
||||
get<TKey extends keyof PragmaPsuedoMap>(key: TKey): PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][];
|
||||
forEach(action: <TKey extends keyof PragmaPsuedoMap>(value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][], key: TKey) => void): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A strongly-typed es6 map of pragma entries, the values of which are either a single argument
|
||||
* value (if only one was found), or an array of multiple argument values if the pragma is present
|
||||
* in multiple places
|
||||
*/
|
||||
/* @internal */
|
||||
export interface PragmaMap extends Map<PragmaPsuedoMap[keyof PragmaPsuedoMap] | PragmaPsuedoMap[keyof PragmaPsuedoMap][]> {
|
||||
export interface PragmaMap extends Map<PragmaPsuedoMap[keyof PragmaPsuedoMap] | PragmaPsuedoMap[keyof PragmaPsuedoMap][]>, ReadonlyPragmaMap {
|
||||
set<TKey extends keyof PragmaPsuedoMap>(key: TKey, value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][]): this;
|
||||
get<TKey extends keyof PragmaPsuedoMap>(key: TKey): PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][];
|
||||
forEach(action: <TKey extends keyof PragmaPsuedoMap>(value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][], key: TKey) => void): void;
|
||||
}
|
||||
|
||||
export interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
+56
-13
@@ -15,7 +15,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export const resolvingEmptyArray: never[] = [] as never[];
|
||||
export const emptyMap: ReadonlyMap<never> = createMap<never>();
|
||||
export const emptyMap = createMap<never>() as ReadonlyMap<never> & ReadonlyPragmaMap;
|
||||
export const emptyUnderscoreEscapedMap: ReadonlyUnderscoreEscapedMap<never> = emptyMap as ReadonlyUnderscoreEscapedMap<never>;
|
||||
|
||||
export const externalHelpersModuleNameText = "tslib";
|
||||
@@ -2330,6 +2330,13 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
function skipParenthesesUp(node: Node): Node {
|
||||
while (node.kind === SyntaxKind.ParenthesizedExpression) {
|
||||
node = node.parent;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// a node is delete target iff. it is PropertyAccessExpression/ElementAccessExpression with parentheses skipped
|
||||
export function isDeleteTarget(node: Node): boolean {
|
||||
if (node.kind !== SyntaxKind.PropertyAccessExpression && node.kind !== SyntaxKind.ElementAccessExpression) {
|
||||
@@ -4226,6 +4233,8 @@ namespace ts {
|
||||
if (!parent) return AccessKind.Read;
|
||||
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return accessKind(parent);
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
const { operator } = parent as PrefixUnaryExpression | PostfixUnaryExpression;
|
||||
@@ -4237,13 +4246,35 @@ namespace ts {
|
||||
: AccessKind.Read;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return (parent as PropertyAccessExpression).name !== node ? AccessKind.Read : accessKind(parent);
|
||||
case SyntaxKind.PropertyAssignment: {
|
||||
const parentAccess = accessKind(parent.parent);
|
||||
// In `({ x: varname }) = { x: 1 }`, the left `x` is a read, the right `x` is a write.
|
||||
return node === (parent as PropertyAssignment).name ? reverseAccessKind(parentAccess) : parentAccess;
|
||||
}
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
// Assume it's the local variable being accessed, since we don't check public properties for --noUnusedLocals.
|
||||
return node === (parent as ShorthandPropertyAssignment).objectAssignmentInitializer ? AccessKind.Read : accessKind(parent.parent);
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return accessKind(parent);
|
||||
default:
|
||||
return AccessKind.Read;
|
||||
}
|
||||
|
||||
function writeOrReadWrite(): AccessKind {
|
||||
// If grandparent is not an ExpressionStatement, this is used as an expression in addition to having a side effect.
|
||||
return parent.parent && parent.parent.kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite;
|
||||
return parent.parent && skipParenthesesUp(parent.parent).kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite;
|
||||
}
|
||||
}
|
||||
function reverseAccessKind(a: AccessKind): AccessKind {
|
||||
switch (a) {
|
||||
case AccessKind.Read:
|
||||
return AccessKind.Write;
|
||||
case AccessKind.Write:
|
||||
return AccessKind.Read;
|
||||
case AccessKind.ReadWrite:
|
||||
return AccessKind.ReadWrite;
|
||||
default:
|
||||
return Debug.assertNever(a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4873,13 +4904,13 @@ namespace ts {
|
||||
if (isDeclaration(hostNode)) {
|
||||
return getDeclarationIdentifier(hostNode);
|
||||
}
|
||||
// Covers remaining cases
|
||||
// Covers remaining cases (returning undefined if none match).
|
||||
switch (hostNode.kind) {
|
||||
case SyntaxKind.VariableStatement:
|
||||
if (hostNode.declarationList && hostNode.declarationList.declarations[0]) {
|
||||
return getDeclarationIdentifier(hostNode.declarationList.declarations[0]);
|
||||
}
|
||||
return undefined;
|
||||
break;
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
const expr = hostNode.expression;
|
||||
switch (expr.kind) {
|
||||
@@ -4891,9 +4922,7 @@ namespace ts {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
case SyntaxKind.EndOfFileToken:
|
||||
return undefined;
|
||||
break;
|
||||
case SyntaxKind.ParenthesizedExpression: {
|
||||
return getDeclarationIdentifier(hostNode.expression);
|
||||
}
|
||||
@@ -4901,10 +4930,8 @@ namespace ts {
|
||||
if (isDeclaration(hostNode.statement) || isExpression(hostNode.statement)) {
|
||||
return getDeclarationIdentifier(hostNode.statement);
|
||||
}
|
||||
return undefined;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Debug.assertNever(hostNode, "Found typedef tag attached to node which it should not be!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5140,7 +5167,20 @@ namespace ts {
|
||||
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
|
||||
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
|
||||
}
|
||||
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray);
|
||||
if (node.typeParameters) {
|
||||
return node.typeParameters;
|
||||
}
|
||||
if (isInJavaScriptFile(node)) {
|
||||
const decls = getJSDocTypeParameterDeclarations(node);
|
||||
if (decls.length) {
|
||||
return decls;
|
||||
}
|
||||
const typeTag = getJSDocType(node);
|
||||
if (typeTag && isFunctionTypeNode(typeTag) && typeTag.typeParameters) {
|
||||
return typeTag.typeParameters;
|
||||
}
|
||||
}
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined {
|
||||
@@ -7313,8 +7353,6 @@ namespace ts {
|
||||
if (pathComponents.length === 0) return "";
|
||||
|
||||
const root = pathComponents[0] && ensureTrailingDirectorySeparator(pathComponents[0]);
|
||||
if (pathComponents.length === 1) return root;
|
||||
|
||||
return root + pathComponents.slice(1).join(directorySeparator);
|
||||
}
|
||||
|
||||
@@ -7918,6 +7956,7 @@ namespace ts {
|
||||
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
|
||||
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
export const supportedJavaScriptAndJsonExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx, Extension.Json];
|
||||
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
|
||||
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ReadonlyArray<string> {
|
||||
@@ -7943,6 +7982,10 @@ namespace ts {
|
||||
return some(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function hasJavaScriptOrJsonFileExtension(fileName: string): boolean {
|
||||
return supportedJavaScriptAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
|
||||
}
|
||||
|
||||
export function hasTypeScriptFileExtension(fileName: string): boolean {
|
||||
return some(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
+34
-26
@@ -27,12 +27,6 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const nonClearingMessageCodes: number[] = [
|
||||
Diagnostics.Found_1_error_Watching_for_file_changes.code,
|
||||
Diagnostics.Found_0_errors_Watching_for_file_changes.code
|
||||
];
|
||||
|
||||
/**
|
||||
* @returns Whether the screen was cleared.
|
||||
*/
|
||||
@@ -41,7 +35,7 @@ namespace ts {
|
||||
!options.preserveWatchOutput &&
|
||||
!options.extendedDiagnostics &&
|
||||
!options.diagnostics &&
|
||||
!contains(nonClearingMessageCodes, diagnostic.code)) {
|
||||
contains(screenStartingMessageCodes, diagnostic.code)) {
|
||||
system.clearScreen();
|
||||
return true;
|
||||
}
|
||||
@@ -174,6 +168,17 @@ namespace ts {
|
||||
|
||||
const noopFileWatcher: FileWatcher = { close: noop };
|
||||
|
||||
export function createWatchHost(system = sys, reportWatchStatus?: WatchStatusReporter): WatchHost {
|
||||
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
|
||||
return {
|
||||
onWatchStatusChange,
|
||||
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
|
||||
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
|
||||
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
|
||||
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the watch compiler host that can be extended with config file or root file names and options host
|
||||
*/
|
||||
@@ -186,7 +191,7 @@ namespace ts {
|
||||
host; // tslint:disable-line no-unused-expression (TODO: `host` is unused!)
|
||||
const useCaseSensitiveFileNames = () => system.useCaseSensitiveFileNames;
|
||||
const writeFileName = (s: string) => system.write(s + system.newLine);
|
||||
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
|
||||
const { onWatchStatusChange, watchFile, watchDirectory, setTimeout, clearTimeout } = createWatchHost(system, reportWatchStatus);
|
||||
return {
|
||||
useCaseSensitiveFileNames,
|
||||
getNewLine: () => system.newLine,
|
||||
@@ -200,10 +205,10 @@ namespace ts {
|
||||
readDirectory: (path, extensions, exclude, include, depth) => system.readDirectory(path, extensions, exclude, include, depth),
|
||||
realpath: system.realpath && (path => system.realpath!(path)),
|
||||
getEnvironmentVariable: system.getEnvironmentVariable && (name => system.getEnvironmentVariable(name)),
|
||||
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
|
||||
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
|
||||
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
|
||||
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop,
|
||||
watchFile,
|
||||
watchDirectory,
|
||||
setTimeout,
|
||||
clearTimeout,
|
||||
trace: s => system.write(s),
|
||||
onWatchStatusChange,
|
||||
createDirectory: path => system.createDirectory(path),
|
||||
@@ -224,10 +229,10 @@ namespace ts {
|
||||
|
||||
const reportSummary = (errorCount: number) => {
|
||||
if (errorCount === 1) {
|
||||
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
else {
|
||||
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -270,7 +275,21 @@ namespace ts {
|
||||
export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
export type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
export interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
export interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
export interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
// TODO: GH#18217 Optional methods are frequently asserted
|
||||
|
||||
/**
|
||||
@@ -279,8 +298,6 @@ namespace ts {
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
|
||||
// Only for testing
|
||||
/*@internal*/
|
||||
@@ -323,15 +340,6 @@ namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
|
||||
/** Internal interface used to wire emit through same host */
|
||||
|
||||
@@ -374,5 +374,41 @@ namespace fakes {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
|
||||
export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost {
|
||||
diagnostics: ts.Diagnostic[] = [];
|
||||
|
||||
reportDiagnostic(diagnostic: ts.Diagnostic) {
|
||||
this.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
reportSolutionBuilderStatus(diagnostic: ts.Diagnostic) {
|
||||
this.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
clearDiagnostics() {
|
||||
this.diagnostics.length = 0;
|
||||
}
|
||||
|
||||
assertDiagnosticMessages(...expected: ts.DiagnosticMessage[]) {
|
||||
const actual = this.diagnostics.slice();
|
||||
if (actual.length !== expected.length) {
|
||||
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
|
||||
}
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual[i].code !== expected[i].code) {
|
||||
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printDiagnostics(header = "== Diagnostics ==") {
|
||||
const out = ts.createDiagnosticReporter(ts.sys);
|
||||
ts.sys.write(header + "\r\n");
|
||||
for (const d of this.diagnostics) {
|
||||
out(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+110
-75
@@ -50,10 +50,8 @@ namespace FourSlash {
|
||||
data?: {};
|
||||
}
|
||||
|
||||
export interface Range {
|
||||
export interface Range extends ts.TextRange {
|
||||
fileName: string;
|
||||
pos: number;
|
||||
end: number;
|
||||
marker?: Marker;
|
||||
}
|
||||
|
||||
@@ -870,8 +868,7 @@ namespace FourSlash {
|
||||
const actualByName = ts.createMap<ts.CompletionEntry>();
|
||||
for (const entry of actualCompletions.entries) {
|
||||
if (actualByName.has(entry.name)) {
|
||||
// TODO: GH#23587
|
||||
if (entry.name !== "undefined" && entry.name !== "require") this.raiseError(`Duplicate (${actualCompletions.entries.filter(a => a.name === entry.name).length}) completions for ${entry.name}`);
|
||||
this.raiseError(`Duplicate (${actualCompletions.entries.filter(a => a.name === entry.name).length}) completions for ${entry.name}`);
|
||||
}
|
||||
else {
|
||||
actualByName.set(entry.name, entry);
|
||||
@@ -911,8 +908,8 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private verifyCompletionEntry(actual: ts.CompletionEntry, expected: FourSlashInterface.ExpectedCompletionEntry) {
|
||||
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, sourceDisplay } = typeof expected === "string"
|
||||
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, sourceDisplay: undefined }
|
||||
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, source, sourceDisplay } = typeof expected === "string"
|
||||
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, source: undefined, sourceDisplay: undefined }
|
||||
: expected;
|
||||
|
||||
if (actual.insertText !== insertText) {
|
||||
@@ -930,6 +927,7 @@ namespace FourSlash {
|
||||
|
||||
assert.equal(actual.hasAction, hasAction);
|
||||
assert.equal(actual.isRecommended, isRecommended);
|
||||
assert.equal(actual.source, source);
|
||||
|
||||
if (text) {
|
||||
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source)!;
|
||||
@@ -1103,7 +1101,7 @@ namespace FourSlash {
|
||||
return node;
|
||||
}
|
||||
|
||||
private verifyRange(desc: string, expected: Range, actual: ts.Node) {
|
||||
private verifyRange(desc: string, expected: ts.TextRange, actual: ts.Node) {
|
||||
const actualStart = actual.getStart();
|
||||
const actualEnd = actual.getEnd();
|
||||
if (actualStart !== expected.pos || actualEnd !== expected.end) {
|
||||
@@ -1713,11 +1711,8 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public baselineQuickInfo() {
|
||||
let baselineFile = this.testData.globalOptions[MetadataOptionNames.baselineFile];
|
||||
if (!baselineFile) {
|
||||
baselineFile = ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline");
|
||||
}
|
||||
|
||||
const baselineFile = this.testData.globalOptions[MetadataOptionNames.baselineFile] ||
|
||||
ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline");
|
||||
Harness.Baseline.runBaseline(
|
||||
baselineFile,
|
||||
stringify(
|
||||
@@ -1958,18 +1953,11 @@ Actual: ${stringify(fullActual)}`);
|
||||
* May be negative.
|
||||
*/
|
||||
private applyEdits(fileName: string, edits: ReadonlyArray<ts.TextChange>, isFormattingEdit: boolean): number {
|
||||
// We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track
|
||||
// of the incremental offset from each edit to the next. We assume these edit ranges don't overlap
|
||||
|
||||
// Copy this so we don't ruin someone else's copy
|
||||
edits = JSON.parse(JSON.stringify(edits));
|
||||
|
||||
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
|
||||
const oldContent = this.getFileContent(fileName);
|
||||
let runningOffset = 0;
|
||||
|
||||
for (let i = 0; i < edits.length; i++) {
|
||||
const edit = edits[i];
|
||||
forEachTextChange(edits, edit => {
|
||||
const offsetStart = edit.span.start;
|
||||
const offsetEnd = offsetStart + edit.span.length;
|
||||
this.editScriptAndUpdateMarkers(fileName, offsetStart, offsetEnd, edit.newText);
|
||||
@@ -1985,14 +1973,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
}
|
||||
runningOffset += editDelta;
|
||||
|
||||
// Update positions of any future edits affected by this change
|
||||
for (let j = i + 1; j < edits.length; j++) {
|
||||
if (edits[j].span.start >= edits[i].span.start) {
|
||||
edits[j].span.start += editDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (isFormattingEdit) {
|
||||
const newContent = this.getFileContent(fileName);
|
||||
@@ -2034,30 +2015,14 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.languageServiceAdapterHost.editScript(fileName, editStart, editEnd, newText);
|
||||
for (const marker of this.testData.markers) {
|
||||
if (marker.fileName === fileName) {
|
||||
marker.position = updatePosition(marker.position);
|
||||
marker.position = updatePosition(marker.position, editStart, editEnd, newText);
|
||||
}
|
||||
}
|
||||
|
||||
for (const range of this.testData.ranges) {
|
||||
if (range.fileName === fileName) {
|
||||
range.pos = updatePosition(range.pos);
|
||||
range.end = updatePosition(range.end);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePosition(position: number) {
|
||||
if (position > editStart) {
|
||||
if (position < editEnd) {
|
||||
// Inside the edit - mark it as invalidated (?)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
// Move marker back/forward by the appropriate amount
|
||||
return position + (editStart - editEnd) + newText.length;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return position;
|
||||
range.pos = updatePosition(range.pos, editStart, editEnd, newText);
|
||||
range.end = updatePosition(range.end, editStart, editEnd, newText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2488,22 +2453,24 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
this.applyCodeActions(codeActions);
|
||||
|
||||
this.verifyNewContent(options, ts.flatMap(codeActions, a => a.changes.map(c => c.fileName)));
|
||||
this.verifyNewContentAfterChange(options, ts.flatMap(codeActions, a => a.changes.map(c => c.fileName)));
|
||||
}
|
||||
|
||||
public verifyRangeIs(expectedText: string, includeWhiteSpace?: boolean) {
|
||||
this.verifyTextMatches(this.rangeText(this.getOnlyRange()), !!includeWhiteSpace, expectedText);
|
||||
}
|
||||
|
||||
private getOnlyRange() {
|
||||
const ranges = this.getRanges();
|
||||
if (ranges.length !== 1) {
|
||||
this.raiseError("Exactly one range should be specified in the testfile.");
|
||||
}
|
||||
return ts.first(ranges);
|
||||
}
|
||||
|
||||
const actualText = this.rangeText(ranges[0]);
|
||||
|
||||
const result = includeWhiteSpace
|
||||
? actualText === expectedText
|
||||
: this.removeWhitespace(actualText) === this.removeWhitespace(expectedText);
|
||||
|
||||
if (!result) {
|
||||
private verifyTextMatches(actualText: string, includeWhitespace: boolean, expectedText: string) {
|
||||
const removeWhitespace = (s: string): string => includeWhitespace ? s : this.removeWhitespace(s);
|
||||
if (removeWhitespace(actualText) !== removeWhitespace(expectedText)) {
|
||||
this.raiseError(`Actual range text doesn't match expected text.\n${showTextDiff(expectedText, actualText)}`);
|
||||
}
|
||||
}
|
||||
@@ -2570,33 +2537,68 @@ Actual: ${stringify(fullActual)}`);
|
||||
const action = actions[index];
|
||||
|
||||
assert.equal(action.description, options.description);
|
||||
assert.deepEqual(action.commands, options.commands);
|
||||
|
||||
for (const change of action.changes) {
|
||||
this.applyEdits(change.fileName, change.textChanges, /*isFormattingEdit*/ false);
|
||||
if (options.applyChanges) {
|
||||
for (const change of action.changes) {
|
||||
this.applyEdits(change.fileName, change.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
this.verifyNewContentAfterChange(options, action.changes.map(c => c.fileName));
|
||||
}
|
||||
else {
|
||||
this.verifyNewContent(options, action.changes);
|
||||
}
|
||||
|
||||
this.verifyNewContent(options, action.changes.map(c => c.fileName));
|
||||
}
|
||||
|
||||
private verifyNewContent(options: FourSlashInterface.NewContentOptions, changedFiles: ReadonlyArray<string>) {
|
||||
const assertedChangedFiles = !options.newFileContent || typeof options.newFileContent === "string"
|
||||
private verifyNewContent({ newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, changes: ReadonlyArray<ts.FileTextChanges>): void {
|
||||
if (newRangeContent !== undefined) {
|
||||
assert(newFileContent === undefined);
|
||||
assert(changes.length === 1, "Affected 0 or more than 1 file, must use 'newFileContent' instead of 'newRangeContent'");
|
||||
const change = ts.first(changes);
|
||||
assert(change.fileName = this.activeFile.fileName);
|
||||
const newText = ts.textChanges.applyChanges(this.getFileContent(this.activeFile.fileName), change.textChanges);
|
||||
const newRange = updateTextRangeForTextChanges(this.getOnlyRange(), change.textChanges);
|
||||
const actualText = newText.slice(newRange.pos, newRange.end);
|
||||
this.verifyTextMatches(actualText, /*includeWhitespace*/ true, newRangeContent);
|
||||
}
|
||||
else {
|
||||
if (newFileContent === undefined) throw ts.Debug.fail();
|
||||
if (typeof newFileContent !== "object") newFileContent = { [this.activeFile.fileName]: newFileContent };
|
||||
for (const change of changes) {
|
||||
const expectedNewContent = newFileContent[change.fileName];
|
||||
if (expectedNewContent === undefined) {
|
||||
ts.Debug.fail(`Did not expect a change in ${change.fileName}`);
|
||||
}
|
||||
const oldText = this.tryGetFileContent(change.fileName);
|
||||
ts.Debug.assert(!!change.isNewFile === (oldText === undefined));
|
||||
const newContent = change.isNewFile ? ts.first(change.textChanges).newText : ts.textChanges.applyChanges(oldText!, change.textChanges);
|
||||
assert.equal(newContent, expectedNewContent);
|
||||
}
|
||||
for (const newFileName in newFileContent) {
|
||||
ts.Debug.assert(changes.some(c => c.fileName === newFileName), "No change in file", () => newFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private verifyNewContentAfterChange({ newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, changedFiles: ReadonlyArray<string>) {
|
||||
const assertedChangedFiles = !newFileContent || typeof newFileContent === "string"
|
||||
? [this.activeFile.fileName]
|
||||
: ts.getOwnKeys(options.newFileContent);
|
||||
: ts.getOwnKeys(newFileContent);
|
||||
assert.deepEqual(assertedChangedFiles, changedFiles);
|
||||
|
||||
if (options.newFileContent !== undefined) {
|
||||
assert(!options.newRangeContent);
|
||||
if (typeof options.newFileContent === "string") {
|
||||
this.verifyCurrentFileContent(options.newFileContent);
|
||||
if (newFileContent !== undefined) {
|
||||
assert(!newRangeContent);
|
||||
if (typeof newFileContent === "string") {
|
||||
this.verifyCurrentFileContent(newFileContent);
|
||||
}
|
||||
else {
|
||||
for (const fileName in options.newFileContent) {
|
||||
this.verifyFileContent(fileName, options.newFileContent[fileName]);
|
||||
for (const fileName in newFileContent) {
|
||||
this.verifyFileContent(fileName, newFileContent[fileName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.verifyRangeIs(options.newRangeContent!, /*includeWhitespace*/ true);
|
||||
this.verifyRangeIs(newRangeContent!, /*includeWhitespace*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3114,7 +3116,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
assert(action.name === "Move to a new file" && action.description === "Move to a new file");
|
||||
|
||||
const editInfo = this.languageService.getEditsForRefactor(range.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions)!;
|
||||
this.testNewFileContents(editInfo.edits, options.newFileContents, "move to new file");
|
||||
this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits);
|
||||
}
|
||||
|
||||
private testNewFileContents(edits: ReadonlyArray<ts.FileTextChanges>, newFileContents: { [fileName: string]: string }, description: string): void {
|
||||
@@ -3380,6 +3382,36 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
}
|
||||
|
||||
function updateTextRangeForTextChanges({ pos, end }: ts.TextRange, textChanges: ReadonlyArray<ts.TextChange>): ts.TextRange {
|
||||
forEachTextChange(textChanges, change => {
|
||||
const update = (p: number): number => updatePosition(p, change.span.start, ts.textSpanEnd(change.span), change.newText);
|
||||
pos = update(pos);
|
||||
end = update(end);
|
||||
});
|
||||
return { pos, end };
|
||||
}
|
||||
|
||||
/** Apply each textChange in order, updating future changes to account for the text offset of previous changes. */
|
||||
function forEachTextChange(changes: ReadonlyArray<ts.TextChange>, cb: (change: ts.TextChange) => void): void {
|
||||
// Copy this so we don't ruin someone else's copy
|
||||
changes = JSON.parse(JSON.stringify(changes));
|
||||
for (let i = 0; i < changes.length; i++) {
|
||||
const change = changes[i];
|
||||
cb(change);
|
||||
const changeDelta = change.newText.length - change.span.length;
|
||||
for (let j = i + 1; j < changes.length; j++) {
|
||||
if (changes[j].span.start >= change.span.start) {
|
||||
changes[j].span.start += changeDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updatePosition(position: number, editStart: number, editEnd: number, { length }: string): number {
|
||||
// If inside the edit, return -1 to mark as invalid
|
||||
return position <= editStart ? position : position < editEnd ? -1 : position + length - + (editEnd - editStart);
|
||||
}
|
||||
|
||||
function renameKeys<T>(obj: { readonly [key: string]: T }, renameKey: (key: string) => string): { readonly [key: string]: T } {
|
||||
const res: { [key: string]: T } = {};
|
||||
for (const key in obj) {
|
||||
@@ -4758,6 +4790,7 @@ namespace FourSlashInterface {
|
||||
|
||||
export type ExpectedCompletionEntry = string | {
|
||||
readonly name: string,
|
||||
readonly source?: string,
|
||||
readonly insertText?: string,
|
||||
readonly replacementSpan?: FourSlash.Range,
|
||||
readonly hasAction?: boolean, // If not specified, will assert that this is false.
|
||||
@@ -4842,10 +4875,12 @@ namespace FourSlashInterface {
|
||||
}
|
||||
|
||||
export interface VerifyCodeFixOptions extends NewContentOptions {
|
||||
description: string;
|
||||
errorCode?: number;
|
||||
index?: number;
|
||||
preferences?: ts.UserPreferences;
|
||||
readonly description: string;
|
||||
readonly errorCode?: number;
|
||||
readonly index?: number;
|
||||
readonly preferences?: ts.UserPreferences;
|
||||
readonly applyChanges?: boolean;
|
||||
readonly commands?: ReadonlyArray<ts.CodeActionCommand>;
|
||||
}
|
||||
|
||||
export interface VerifyCodeFixAvailableOptions {
|
||||
|
||||
@@ -620,14 +620,14 @@ interface Array<T> {}`
|
||||
}
|
||||
}
|
||||
|
||||
removeFile(filePath: string) {
|
||||
deleteFile(filePath: string) {
|
||||
const path = this.toFullPath(filePath);
|
||||
const currentEntry = this.fs.get(path) as FsFile;
|
||||
Debug.assert(isFsFile(currentEntry));
|
||||
this.removeFileOrFolder(currentEntry, returnFalse);
|
||||
}
|
||||
|
||||
removeFolder(folderPath: string, recursive?: boolean) {
|
||||
deleteFolder(folderPath: string, recursive?: boolean) {
|
||||
const path = this.toFullPath(folderPath);
|
||||
const currentEntry = this.fs.get(path) as FsFolder;
|
||||
Debug.assert(isFsFolder(currentEntry));
|
||||
@@ -635,7 +635,7 @@ interface Array<T> {}`
|
||||
const subEntries = currentEntry.entries.slice();
|
||||
subEntries.forEach(fsEntry => {
|
||||
if (isFsFolder(fsEntry)) {
|
||||
this.removeFolder(fsEntry.fullPath, recursive);
|
||||
this.deleteFolder(fsEntry.fullPath, recursive);
|
||||
}
|
||||
else {
|
||||
this.removeFileOrFolder(fsEntry, returnFalse);
|
||||
@@ -766,6 +766,14 @@ interface Array<T> {}`
|
||||
return (fsEntry && fsEntry.modifiedTime)!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
setModifiedTime(s: string, date: Date) {
|
||||
const path = this.toFullPath(s);
|
||||
const fsEntry = this.fs.get(path);
|
||||
if (fsEntry) {
|
||||
fsEntry.modifiedTime = date;
|
||||
}
|
||||
}
|
||||
|
||||
readFile(s: string): string | undefined {
|
||||
const fsEntry = this.getRealFile(this.toFullPath(s));
|
||||
return fsEntry ? fsEntry.content : undefined;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -218,9 +218,15 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function convertUserPreferences(preferences: protocol.UserPreferences): UserPreferences {
|
||||
const { lazyConfiguredProjectsFromExternalProject, ...userPreferences } = preferences;
|
||||
return userPreferences;
|
||||
}
|
||||
|
||||
export interface HostConfiguration {
|
||||
formatCodeOptions: FormatCodeSettings;
|
||||
preferences: UserPreferences;
|
||||
preferences: protocol.UserPreferences;
|
||||
hostInfo: string;
|
||||
extraFileExtensions?: FileExtensionInfo[];
|
||||
}
|
||||
@@ -802,7 +808,7 @@ namespace ts.server {
|
||||
return info && info.getFormatCodeSettings() || this.hostConfiguration.formatCodeOptions;
|
||||
}
|
||||
|
||||
getPreferences(file: NormalizedPath): UserPreferences {
|
||||
getPreferences(file: NormalizedPath): protocol.UserPreferences {
|
||||
const info = this.getScriptInfoForNormalizedPath(file);
|
||||
return info && info.getPreferences() || this.hostConfiguration.preferences;
|
||||
}
|
||||
@@ -811,7 +817,7 @@ namespace ts.server {
|
||||
return this.hostConfiguration.formatCodeOptions;
|
||||
}
|
||||
|
||||
getHostPreferences(): UserPreferences {
|
||||
getHostPreferences(): protocol.UserPreferences {
|
||||
return this.hostConfiguration.preferences;
|
||||
}
|
||||
|
||||
@@ -1561,6 +1567,13 @@ namespace ts.server {
|
||||
return project;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
private createLoadAndUpdateConfiguredProject(configFileName: NormalizedPath) {
|
||||
const project = this.createAndLoadConfiguredProject(configFileName);
|
||||
project.updateGraph();
|
||||
return project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the config file of the project, and update the project root file names.
|
||||
*/
|
||||
@@ -1979,7 +1992,19 @@ namespace ts.server {
|
||||
this.logger.info("Format host information updated");
|
||||
}
|
||||
if (args.preferences) {
|
||||
const { lazyConfiguredProjectsFromExternalProject } = this.hostConfiguration.preferences;
|
||||
this.hostConfiguration.preferences = { ...this.hostConfiguration.preferences, ...args.preferences };
|
||||
if (lazyConfiguredProjectsFromExternalProject && !this.hostConfiguration.preferences.lazyConfiguredProjectsFromExternalProject) {
|
||||
// Load configured projects for external projects that are pending reload
|
||||
this.configuredProjects.forEach(project => {
|
||||
if (project.hasExternalProjectRef() &&
|
||||
project.pendingReload === ConfigFileProgramReloadLevel.Full &&
|
||||
!this.pendingProjectUpdates.has(project.getProjectName())) {
|
||||
this.loadConfiguredProject(project);
|
||||
project.updateGraph();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (args.extraFileExtensions) {
|
||||
this.hostConfiguration.extraFileExtensions = args.extraFileExtensions;
|
||||
@@ -2192,8 +2217,7 @@ namespace ts.server {
|
||||
if (configFileName) {
|
||||
project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
if (!project) {
|
||||
project = this.createAndLoadConfiguredProject(configFileName);
|
||||
project.updateGraph();
|
||||
project = this.createLoadAndUpdateConfiguredProject(configFileName);
|
||||
// Send the event only if the project got created as part of this open request and info is part of the project
|
||||
if (info.isOrphan()) {
|
||||
// Since the file isnt part of configured project, do not send config file info
|
||||
@@ -2633,7 +2657,9 @@ namespace ts.server {
|
||||
let project = this.findConfiguredProjectByProjectName(tsconfigFile);
|
||||
if (!project) {
|
||||
// errors are stored in the project, do not need to update the graph
|
||||
project = this.createConfiguredProjectWithDelayLoad(tsconfigFile);
|
||||
project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject ?
|
||||
this.createConfiguredProjectWithDelayLoad(tsconfigFile) :
|
||||
this.createLoadAndUpdateConfiguredProject(tsconfigFile);
|
||||
}
|
||||
if (project && !contains(exisingConfigFiles, tsconfigFile)) {
|
||||
// keep project alive even if no documents are opened - its lifetime is bound to the lifetime of containing external project
|
||||
|
||||
@@ -1520,6 +1520,11 @@ namespace ts.server {
|
||||
) || false;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
hasExternalProjectRef() {
|
||||
return !!this.externalProjectRefCount;
|
||||
}
|
||||
|
||||
getEffectiveTypeRoots() {
|
||||
return getEffectiveTypeRoots(this.getCompilationSettings(), this.directoryStructureHost) || [];
|
||||
}
|
||||
|
||||
@@ -1839,7 +1839,7 @@ namespace ts.server.protocol {
|
||||
* begin with prefix.
|
||||
*/
|
||||
export interface CompletionsRequest extends FileLocationRequest {
|
||||
command: CommandTypes.Completions;
|
||||
command: CommandTypes.Completions | CommandTypes.CompletionInfo;
|
||||
arguments: CompletionsRequestArgs;
|
||||
}
|
||||
|
||||
@@ -2823,6 +2823,7 @@ namespace ts.server.protocol {
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
}
|
||||
|
||||
export interface CompilerOptions {
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace ts.server {
|
||||
*/
|
||||
readonly containingProjects: Project[] = [];
|
||||
private formatSettings: FormatCodeSettings | undefined;
|
||||
private preferences: UserPreferences | undefined;
|
||||
private preferences: protocol.UserPreferences | undefined;
|
||||
|
||||
/* @internal */
|
||||
fileWatcher: FileWatcher | undefined;
|
||||
@@ -333,7 +333,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getFormatCodeSettings(): FormatCodeSettings | undefined { return this.formatSettings; }
|
||||
getPreferences(): UserPreferences | undefined { return this.preferences; }
|
||||
getPreferences(): protocol.UserPreferences | undefined { return this.preferences; }
|
||||
|
||||
attachToProject(project: Project): boolean {
|
||||
const isNew = !this.isAttached(project);
|
||||
@@ -432,7 +432,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
setOptions(formatSettings: FormatCodeSettings, preferences: UserPreferences | undefined): void {
|
||||
setOptions(formatSettings: FormatCodeSettings, preferences: protocol.UserPreferences | undefined): void {
|
||||
if (formatSettings) {
|
||||
if (!this.formatSettings) {
|
||||
this.formatSettings = getDefaultFormatCodeSettings(this.host);
|
||||
|
||||
@@ -1423,7 +1423,7 @@ namespace ts.server {
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
const completions = project.getLanguageService().getCompletionsAtPosition(file, position, {
|
||||
...this.getPreferences(file),
|
||||
...convertUserPreferences(this.getPreferences(file)),
|
||||
triggerCharacter: args.triggerCharacter,
|
||||
includeExternalModuleExports: args.includeExternalModuleExports,
|
||||
includeInsertTextCompletions: args.includeInsertTextCompletions
|
||||
@@ -2352,7 +2352,7 @@ namespace ts.server {
|
||||
return this.projectService.getFormatCodeOptions(file);
|
||||
}
|
||||
|
||||
private getPreferences(file: NormalizedPath): UserPreferences {
|
||||
private getPreferences(file: NormalizedPath): protocol.UserPreferences {
|
||||
return this.projectService.getPreferences(file);
|
||||
}
|
||||
|
||||
@@ -2360,7 +2360,7 @@ namespace ts.server {
|
||||
return this.projectService.getHostFormatCodeOptions();
|
||||
}
|
||||
|
||||
private getHostPreferences(): UserPreferences {
|
||||
private getHostPreferences(): protocol.UserPreferences {
|
||||
return this.projectService.getHostPreferences();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,27 +112,23 @@ namespace ts.codefix {
|
||||
|
||||
export function createMethodFromCallExpression(
|
||||
context: CodeFixContextBase,
|
||||
{ typeArguments, arguments: args, parent: parent }: CallExpression,
|
||||
call: CallExpression,
|
||||
methodName: string,
|
||||
inJs: boolean,
|
||||
makeStatic: boolean,
|
||||
preferences: UserPreferences,
|
||||
body: boolean,
|
||||
): MethodDeclaration {
|
||||
const { typeArguments, arguments: args, parent } = call;
|
||||
const checker = context.program.getTypeChecker();
|
||||
const types = map(args,
|
||||
arg => {
|
||||
let type = checker.getTypeAtLocation(arg);
|
||||
if (type === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
// Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {"
|
||||
type = checker.getBaseTypeOfLiteralType(type);
|
||||
return checker.typeToTypeNode(type);
|
||||
});
|
||||
const types = map(args, arg =>
|
||||
// Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {"
|
||||
checker.typeToTypeNode(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(arg))));
|
||||
const names = map(args, arg =>
|
||||
isIdentifier(arg) ? arg.text :
|
||||
isPropertyAccessExpression(arg) ? arg.name.text : undefined);
|
||||
isPropertyAccessExpression(arg) ? arg.name.text : undefined);
|
||||
const contextualType = checker.getContextualType(call);
|
||||
const returnType = inJs ? undefined : contextualType && checker.typeToTypeNode(contextualType, call) || createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
return createMethod(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ makeStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
|
||||
@@ -142,7 +138,7 @@ namespace ts.codefix {
|
||||
/*typeParameters*/ inJs ? undefined : map(typeArguments, (_, i) =>
|
||||
createTypeParameterDeclaration(CharacterCodes.T + typeArguments!.length - 1 <= CharacterCodes.Z ? String.fromCharCode(CharacterCodes.T + i) : `T${i}`)),
|
||||
/*parameters*/ createDummyParameters(args.length, names, types, /*minArgumentCount*/ undefined, inJs),
|
||||
/*type*/ inJs ? undefined : createKeywordTypeNode(SyntaxKind.AnyKeyword),
|
||||
/*type*/ returnType,
|
||||
body ? createStubbedMethodBody(preferences) : undefined);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,14 +163,19 @@ namespace ts.codefix {
|
||||
position: number,
|
||||
preferences: UserPreferences,
|
||||
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
|
||||
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getTypeChecker(), program.getSourceFiles());
|
||||
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getCompilerOptions(), program.getTypeChecker(), program.getSourceFiles());
|
||||
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol));
|
||||
// We sort the best codefixes first, so taking `first` is best for completions.
|
||||
const moduleSpecifier = first(getNewImportInfos(program, sourceFile, position, exportInfos, host, preferences)).moduleSpecifier;
|
||||
const fix = first(getFixForImport(exportInfos, symbolName, position, program, sourceFile, host, preferences));
|
||||
return { moduleSpecifier, codeAction: codeActionForFix({ host, formatContext }, sourceFile, symbolName, fix, getQuotePreference(sourceFile, preferences)) };
|
||||
return { moduleSpecifier, codeAction: codeFixActionToCodeAction(codeActionForFix({ host, formatContext }, sourceFile, symbolName, fix, getQuotePreference(sourceFile, preferences))) };
|
||||
}
|
||||
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
|
||||
|
||||
function codeFixActionToCodeAction({ description, changes, commands }: CodeFixAction): CodeAction {
|
||||
return { description, changes, commands };
|
||||
}
|
||||
|
||||
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
|
||||
const result: SymbolExportInfo[] = [];
|
||||
forEachExternalModule(checker, allSourceFiles, (moduleSymbol, moduleFile) => {
|
||||
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
|
||||
@@ -178,10 +183,14 @@ namespace ts.codefix {
|
||||
return;
|
||||
}
|
||||
|
||||
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions);
|
||||
if (defaultInfo && defaultInfo.name === symbolName && skipAlias(defaultInfo.symbol, checker) === exportedSymbol) {
|
||||
result.push({ moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(defaultInfo.symbol) });
|
||||
}
|
||||
|
||||
for (const exported of checker.getExportsOfModule(moduleSymbol)) {
|
||||
if ((exported.escapedName === InternalSymbolName.Default || exported.name === symbolName) && skipAlias(exported, checker) === exportedSymbol) {
|
||||
const isDefaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol) === exported;
|
||||
result.push({ moduleSymbol, importKind: isDefaultExport ? ImportKind.Default : ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) });
|
||||
if (exported.name === symbolName && skipAlias(exported, checker) === exportedSymbol) {
|
||||
result.push({ moduleSymbol, importKind: ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) });
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -395,13 +404,9 @@ namespace ts.codefix {
|
||||
forEachExternalModuleToImportFrom(checker, sourceFile, program.getSourceFiles(), moduleSymbol => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
// check the default export
|
||||
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
|
||||
if (defaultExport) {
|
||||
const info = getDefaultExportInfo(defaultExport, moduleSymbol, program);
|
||||
if (info && info.name === symbolName && symbolHasMeaning(info.symbolForMeaning, currentTokenMeaning)) {
|
||||
addSymbol(moduleSymbol, defaultExport, ImportKind.Default);
|
||||
}
|
||||
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, program.getCompilerOptions());
|
||||
if (defaultInfo && defaultInfo.name === symbolName && symbolHasMeaning(defaultInfo.symbolForMeaning, currentTokenMeaning)) {
|
||||
addSymbol(moduleSymbol, defaultInfo.symbol, defaultInfo.kind);
|
||||
}
|
||||
|
||||
// check exports with the same name
|
||||
@@ -413,7 +418,24 @@ namespace ts.codefix {
|
||||
return originalSymbolToExportInfos;
|
||||
}
|
||||
|
||||
function getDefaultExportInfo(defaultExport: Symbol, moduleSymbol: Symbol, program: Program): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
|
||||
function getDefaultLikeExportInfo(
|
||||
moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions,
|
||||
): { readonly symbol: Symbol, readonly symbolForMeaning: Symbol, readonly name: string, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
|
||||
const exported = getDefaultLikeExportWorker(moduleSymbol, checker);
|
||||
if (!exported) return undefined;
|
||||
const { symbol, kind } = exported;
|
||||
const info = getDefaultExportInfoWorker(symbol, moduleSymbol, checker, compilerOptions);
|
||||
return info && { symbol, symbolForMeaning: info.symbolForMeaning, name: info.name, kind };
|
||||
}
|
||||
|
||||
function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
|
||||
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
|
||||
if (defaultExport) return { symbol: defaultExport, kind: ImportKind.Default };
|
||||
const exportEquals = checker.resolveExternalModuleSymbol(moduleSymbol);
|
||||
return exportEquals === moduleSymbol ? undefined : { symbol: exportEquals, kind: ImportKind.Equals };
|
||||
}
|
||||
|
||||
function getDefaultExportInfoWorker(defaultExport: Symbol, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
|
||||
const localSymbol = getLocalSymbolForExportDefault(defaultExport);
|
||||
if (localSymbol) return { symbolForMeaning: localSymbol, name: localSymbol.name };
|
||||
|
||||
@@ -421,11 +443,11 @@ namespace ts.codefix {
|
||||
if (name !== undefined) return { symbolForMeaning: defaultExport, name };
|
||||
|
||||
if (defaultExport.flags & SymbolFlags.Alias) {
|
||||
const aliased = program.getTypeChecker().getImmediateAliasedSymbol(defaultExport);
|
||||
return aliased && getDefaultExportInfo(aliased, Debug.assertDefined(aliased.parent), program);
|
||||
const aliased = checker.getImmediateAliasedSymbol(defaultExport);
|
||||
return aliased && getDefaultExportInfoWorker(aliased, Debug.assertDefined(aliased.parent), checker, compilerOptions);
|
||||
}
|
||||
else {
|
||||
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, program.getCompilerOptions().target!) };
|
||||
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1378,6 +1378,14 @@ namespace ts.Completions {
|
||||
return;
|
||||
}
|
||||
|
||||
if (resolvedModuleSymbol !== moduleSymbol &&
|
||||
// Don't add another completion for `export =` of a symbol that's already global.
|
||||
// So in `declare namespace foo {} declare module "foo" { export = foo; }`, there will just be the global completion for `foo`.
|
||||
resolvedModuleSymbol.declarations.some(d => !!d.getSourceFile().externalModuleIndicator)) {
|
||||
symbols.push(resolvedModuleSymbol);
|
||||
symbolToOriginInfoMap[getSymbolId(resolvedModuleSymbol)] = { kind: SymbolOriginInfoKind.Export, moduleSymbol, isDefaultExport: false };
|
||||
}
|
||||
|
||||
for (let symbol of typeChecker.getExportsOfModule(moduleSymbol)) {
|
||||
// Don't add a completion for a re-export, only for the original.
|
||||
// The actual import fix might end up coming from a re-export -- we don't compute that until getting completion details.
|
||||
@@ -2116,8 +2124,8 @@ namespace ts.Completions {
|
||||
const kind = stringToToken(entry.name)!;
|
||||
switch (keywordFilter) {
|
||||
case KeywordCompletionFilters.None:
|
||||
// "undefined" is a global variable, so don't need a keyword completion for it.
|
||||
return kind !== SyntaxKind.UndefinedKeyword;
|
||||
return kind === SyntaxKind.AsyncKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind) || kind === SyntaxKind.DeclareKeyword || kind === SyntaxKind.ModuleKeyword
|
||||
|| isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword;
|
||||
case KeywordCompletionFilters.ClassElementKeywords:
|
||||
return isClassMemberCompletionKeyword(kind);
|
||||
case KeywordCompletionFilters.InterfaceElementKeywords:
|
||||
@@ -2152,7 +2160,7 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
function isFunctionLikeBodyKeyword(kind: SyntaxKind) {
|
||||
return kind === SyntaxKind.AsyncKeyword || !isClassMemberCompletionKeyword(kind);
|
||||
return kind === SyntaxKind.AsyncKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind);
|
||||
}
|
||||
|
||||
function keywordForNode(node: Node): SyntaxKind {
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace ts {
|
||||
newFileOrDirPath: string,
|
||||
host: LanguageServiceHost,
|
||||
formatContext: formatting.FormatContext,
|
||||
preferences: UserPreferences,
|
||||
_preferences: UserPreferences,
|
||||
sourceMapper: SourceMapper,
|
||||
): ReadonlyArray<FileTextChanges> {
|
||||
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
|
||||
@@ -15,7 +15,7 @@ namespace ts {
|
||||
const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper);
|
||||
return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => {
|
||||
updateTsconfigFiles(program, changeTracker, oldToNew, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames);
|
||||
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName, preferences);
|
||||
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -122,7 +122,6 @@ namespace ts {
|
||||
newToOld: PathUpdater,
|
||||
host: LanguageServiceHost,
|
||||
getCanonicalFileName: GetCanonicalFileName,
|
||||
preferences: UserPreferences,
|
||||
): void {
|
||||
const allFiles = program.getSourceFiles();
|
||||
for (const sourceFile of allFiles) {
|
||||
@@ -156,7 +155,7 @@ namespace ts {
|
||||
|
||||
// Need an update if the imported file moved, or the importing file moved and was using a relative path.
|
||||
return toImport !== undefined && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text)))
|
||||
? moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport.newFileName, host, allFiles, preferences, program.redirectTargetsMap)
|
||||
? moduleSpecifiers.updateModuleSpecifier(program.getCompilerOptions(), newImportFromPath, toImport.newFileName, host, allFiles, program.redirectTargetsMap, importLiteral.text)
|
||||
: undefined;
|
||||
});
|
||||
}
|
||||
@@ -210,7 +209,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined) {
|
||||
for (const ref of sourceFile.referencedFiles) {
|
||||
for (const ref of sourceFile.referencedFiles || emptyArray) { // TODO: GH#26162
|
||||
const updated = updateRef(ref.fileName);
|
||||
if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) changeTracker.replaceRangeWithText(sourceFile, ref, updated);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace ts.GoToDefinition {
|
||||
|
||||
const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node);
|
||||
// Don't go to the component constructor definition for a JSX element, just go to the component definition.
|
||||
if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorDeclaration(calledDeclaration))) {
|
||||
if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorLike(calledDeclaration))) {
|
||||
const sigInfo = createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration);
|
||||
// For a function, if this is the original function definition, return just sigInfo.
|
||||
// If this is the original constructor definition, parent is the class.
|
||||
@@ -319,4 +319,15 @@ namespace ts.GoToDefinition {
|
||||
// Don't go to a function type, go to the value having that type.
|
||||
return tryCast(signature && signature.declaration, (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d));
|
||||
}
|
||||
|
||||
function isConstructorLike(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
namespace ts.SignatureHelp {
|
||||
const enum InvocationKind { Call, TypeArgs, Contextual }
|
||||
interface CallInvocation { readonly kind: InvocationKind.Call; readonly node: CallLikeExpression; }
|
||||
interface TypeArgsInvocation { readonly kind: InvocationKind.TypeArgs; readonly called: Expression; }
|
||||
interface TypeArgsInvocation { readonly kind: InvocationKind.TypeArgs; readonly called: Identifier; }
|
||||
interface ContextualInvocation {
|
||||
readonly kind: InvocationKind.Contextual;
|
||||
readonly signature: Signature;
|
||||
@@ -44,7 +44,7 @@ namespace ts.SignatureHelp {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
// Extra syntactic and semantic filtering of signature help
|
||||
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners);
|
||||
const candidateInfo = getCandidateOrTypeInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners);
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
if (!candidateInfo) {
|
||||
@@ -53,11 +53,24 @@ namespace ts.SignatureHelp {
|
||||
return isSourceFileJavaScript(sourceFile) ? createJavaScriptSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined;
|
||||
}
|
||||
|
||||
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker));
|
||||
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker =>
|
||||
candidateInfo.kind === CandidateOrTypeKind.Candidate
|
||||
? createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker)
|
||||
: createTypeHelpItems(candidateInfo.symbol, argumentInfo, sourceFile, typeChecker));
|
||||
}
|
||||
|
||||
interface CandidateInfo { readonly candidates: ReadonlyArray<Signature>; readonly resolvedSignature: Signature; }
|
||||
function getCandidateInfo({ invocation, argumentCount }: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | undefined {
|
||||
const enum CandidateOrTypeKind { Candidate, Type }
|
||||
interface CandidateInfo {
|
||||
readonly kind: CandidateOrTypeKind.Candidate;
|
||||
readonly candidates: ReadonlyArray<Signature>;
|
||||
readonly resolvedSignature: Signature;
|
||||
}
|
||||
interface TypeInfo {
|
||||
readonly kind: CandidateOrTypeKind.Type;
|
||||
readonly symbol: Symbol;
|
||||
}
|
||||
|
||||
function getCandidateOrTypeInfo({ invocation, argumentCount }: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | TypeInfo | undefined {
|
||||
switch (invocation.kind) {
|
||||
case InvocationKind.Call: {
|
||||
if (onlyUseSyntacticOwners && !isSyntacticOwner(startingToken, invocation.node, sourceFile)) {
|
||||
@@ -65,17 +78,21 @@ namespace ts.SignatureHelp {
|
||||
}
|
||||
const candidates: Signature[] = [];
|
||||
const resolvedSignature = checker.getResolvedSignatureForSignatureHelp(invocation.node, candidates, argumentCount)!; // TODO: GH#18217
|
||||
return candidates.length === 0 ? undefined : { candidates, resolvedSignature };
|
||||
return candidates.length === 0 ? undefined : { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature };
|
||||
}
|
||||
case InvocationKind.TypeArgs: {
|
||||
if (onlyUseSyntacticOwners && !lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.called)) {
|
||||
const { called } = invocation;
|
||||
if (onlyUseSyntacticOwners && !containsPrecedingToken(startingToken, sourceFile, isIdentifier(called) ? called.parent : called)) {
|
||||
return undefined;
|
||||
}
|
||||
const candidates = getPossibleGenericSignatures(invocation.called, argumentCount, checker);
|
||||
return candidates.length === 0 ? undefined : { candidates, resolvedSignature: first(candidates) };
|
||||
const candidates = getPossibleGenericSignatures(called, argumentCount, checker);
|
||||
if (candidates.length !== 0) return { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature: first(candidates) };
|
||||
|
||||
const symbol = checker.getSymbolAtLocation(called);
|
||||
return symbol && { kind: CandidateOrTypeKind.Type, symbol };
|
||||
}
|
||||
case InvocationKind.Contextual:
|
||||
return { candidates: [invocation.signature], resolvedSignature: invocation.signature };
|
||||
return { kind: CandidateOrTypeKind.Candidate, candidates: [invocation.signature], resolvedSignature: invocation.signature };
|
||||
default:
|
||||
return Debug.assertNever(invocation);
|
||||
}
|
||||
@@ -92,7 +109,7 @@ namespace ts.SignatureHelp {
|
||||
return !!containingList && contains(invocationChildren, containingList);
|
||||
}
|
||||
case SyntaxKind.LessThanToken:
|
||||
return lessThanFollowsCalledExpression(startingToken, sourceFile, node.expression);
|
||||
return containsPrecedingToken(startingToken, sourceFile, node.expression);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -114,12 +131,12 @@ namespace ts.SignatureHelp {
|
||||
}));
|
||||
}
|
||||
|
||||
function lessThanFollowsCalledExpression(startingToken: Node, sourceFile: SourceFile, calledExpression: Expression) {
|
||||
function containsPrecedingToken(startingToken: Node, sourceFile: SourceFile, container: Node) {
|
||||
const precedingToken = Debug.assertDefined(
|
||||
findPrecedingToken(startingToken.getFullStart(), sourceFile, startingToken.parent, /*excludeJsdoc*/ true)
|
||||
);
|
||||
|
||||
return rangeContainsRange(calledExpression, precedingToken);
|
||||
return rangeContainsRange(container, precedingToken);
|
||||
}
|
||||
|
||||
export interface ArgumentInfoForCompletions {
|
||||
@@ -457,6 +474,10 @@ namespace ts.SignatureHelp {
|
||||
return invocation.kind === InvocationKind.Call ? getInvokedExpression(invocation.node) : invocation.called;
|
||||
}
|
||||
|
||||
function getEnclosingDeclarationFromInvocation(invocation: Invocation): Node {
|
||||
return invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node;
|
||||
}
|
||||
|
||||
const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
|
||||
function createSignatureHelpItems(
|
||||
candidates: ReadonlyArray<Signature>,
|
||||
@@ -465,7 +486,7 @@ namespace ts.SignatureHelp {
|
||||
sourceFile: SourceFile,
|
||||
typeChecker: TypeChecker,
|
||||
): SignatureHelpItems {
|
||||
const enclosingDeclaration = invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node;
|
||||
const enclosingDeclaration = getEnclosingDeclarationFromInvocation(invocation);
|
||||
const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol : typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation));
|
||||
const callTargetDisplayParts = callTargetSymbol ? symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : emptyArray;
|
||||
const items = candidates.map(candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile));
|
||||
@@ -480,11 +501,36 @@ namespace ts.SignatureHelp {
|
||||
return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount };
|
||||
}
|
||||
|
||||
function createTypeHelpItems(
|
||||
symbol: Symbol,
|
||||
{ argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex }: ArgumentListInfo,
|
||||
sourceFile: SourceFile,
|
||||
checker: TypeChecker
|
||||
): SignatureHelpItems | undefined {
|
||||
const typeParameters = checker.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
|
||||
if (!typeParameters) return undefined;
|
||||
const items = [getTypeHelpItem(symbol, typeParameters, checker, getEnclosingDeclarationFromInvocation(invocation), sourceFile)];
|
||||
return { items, applicableSpan, selectedItemIndex: 0, argumentIndex, argumentCount };
|
||||
}
|
||||
|
||||
function getTypeHelpItem(symbol: Symbol, typeParameters: ReadonlyArray<TypeParameter>, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
|
||||
const typeSymbolDisplay = symbolToDisplayParts(checker, symbol);
|
||||
|
||||
const printer = createPrinter({ removeComments: true });
|
||||
const parameters = typeParameters.map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer));
|
||||
|
||||
const documentation = symbol.getDocumentationComment(checker);
|
||||
const tags = symbol.getJsDocTags();
|
||||
const prefixDisplayParts = [...typeSymbolDisplay, punctuationPart(SyntaxKind.LessThanToken)];
|
||||
return { isVariadic: false, prefixDisplayParts, suffixDisplayParts: [punctuationPart(SyntaxKind.GreaterThanToken)], separatorDisplayParts, parameters, documentation, tags };
|
||||
}
|
||||
|
||||
const separatorDisplayParts: SymbolDisplayPart[] = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
|
||||
|
||||
function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: ReadonlyArray<SymbolDisplayPart>, isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
|
||||
const { isVariadic, parameters, prefix, suffix } = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile);
|
||||
const prefixDisplayParts = [...callTargetDisplayParts, ...prefix];
|
||||
const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)];
|
||||
const separatorDisplayParts = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
|
||||
const documentation = candidateSignature.getDocumentationComment(checker);
|
||||
const tags = candidateSignature.getJsDocTags();
|
||||
return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags };
|
||||
|
||||
@@ -611,7 +611,8 @@ namespace ts.SymbolDisplay {
|
||||
displayParts.push(textPart(allSignatures.length === 2 ? "overload" : "overloads"));
|
||||
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
|
||||
}
|
||||
documentation = signature.getDocumentationComment(typeChecker);
|
||||
const docComment = signature.getDocumentationComment(typeChecker);
|
||||
documentation = docComment.length === 0 ? undefined : docComment;
|
||||
tags = signature.getJsDocTags();
|
||||
}
|
||||
|
||||
|
||||
@@ -233,14 +233,6 @@ namespace ts {
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
}
|
||||
|
||||
export interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
/* @internal */
|
||||
export const emptyOptions = {};
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
"unittests/transform.ts",
|
||||
"unittests/transpile.ts",
|
||||
"unittests/tsbuild.ts",
|
||||
"unittests/tsbuildWatchMode.ts",
|
||||
"unittests/tsconfigParsing.ts",
|
||||
"unittests/tscWatchMode.ts",
|
||||
"unittests/versionCache.ts",
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
namespace ts {
|
||||
let currentTime = 100;
|
||||
let lastDiagnostics: Diagnostic[] = [];
|
||||
const reportDiagnostic: DiagnosticReporter = diagnostic => lastDiagnostics.push(diagnostic);
|
||||
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiagnostic(createCompilerDiagnostic(message, ...args));
|
||||
const buildHost: BuildHost = {
|
||||
error: report,
|
||||
verbose: report,
|
||||
message: report,
|
||||
errorDiagnostic: d => reportDiagnostic(d)
|
||||
};
|
||||
|
||||
export namespace Sample1 {
|
||||
tick();
|
||||
const projFs = loadProjectFromDisk("tests/projects/sample1");
|
||||
@@ -21,12 +11,12 @@ namespace ts {
|
||||
describe("tsbuild - sanity check of clean build of 'sample1' project", () => {
|
||||
it("can build the sample project 'sample1' without error", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*empty*/);
|
||||
host.assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Check for outputs. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -37,12 +27,11 @@ namespace ts {
|
||||
|
||||
describe("tsbuild - dry builds", () => {
|
||||
it("doesn't write any files in a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0);
|
||||
host.assertDiagnosticMessages(Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0);
|
||||
|
||||
// Check for outputs to not be written. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -51,28 +40,26 @@ namespace ts {
|
||||
});
|
||||
|
||||
it("indicates that it would skip builds during a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
let builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
let builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
tick();
|
||||
|
||||
clearDiagnostics();
|
||||
builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
host.clearDiagnostics();
|
||||
builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
|
||||
host.assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - clean builds", () => {
|
||||
it("removes all files it built", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
// Verify they exist
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -91,9 +78,9 @@ namespace ts {
|
||||
describe("tsbuild - force builds", () => {
|
||||
it("always builds under --force", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: true, verbose: false });
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: true, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
let currentTime = time();
|
||||
checkOutputTimestamps(currentTime);
|
||||
@@ -116,14 +103,14 @@ namespace ts {
|
||||
|
||||
describe("tsbuild - can detect when and what to rebuild", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
it("Builds the project", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
Diagnostics.Building_project_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
@@ -135,10 +122,10 @@ namespace ts {
|
||||
|
||||
// All three projects are up to date
|
||||
it("Detects that all projects are up to date", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2);
|
||||
@@ -147,12 +134,12 @@ namespace ts {
|
||||
|
||||
// Update a file in the leaf node (tests), only it should rebuild the last one
|
||||
it("Only builds the leaf node project", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
fs.writeFileSync("/src/tests/index.ts", "const m = 10;");
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
|
||||
@@ -162,12 +149,12 @@ namespace ts {
|
||||
|
||||
// Update a file in the parent (without affecting types), should get fast downstream builds
|
||||
it("Detects type-only changes in upstream projects", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
replaceText(fs, "/src/core/index.ts", "HELLO WORLD", "WELCOME PLANET");
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
|
||||
Diagnostics.Building_project_0,
|
||||
Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies,
|
||||
@@ -180,15 +167,13 @@ namespace ts {
|
||||
describe("tsbuild - downstream-blocked compilations", () => {
|
||||
it("won't build downstream projects if upstream projects have errors", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
// Induce an error in the middle project
|
||||
replaceText(fs, "/src/logic/index.ts", "c.multiply(10, 15)", `c.muitply()`);
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(
|
||||
host.assertDiagnosticMessages(
|
||||
Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
Diagnostics.Building_project_0,
|
||||
@@ -204,12 +189,11 @@ namespace ts {
|
||||
describe("tsbuild - project invalidation", () => {
|
||||
it("invalidates projects correctly", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
|
||||
clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*empty*/);
|
||||
host.assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Update a timestamp in the middle project
|
||||
tick();
|
||||
@@ -221,14 +205,14 @@ namespace ts {
|
||||
// Rebuild this project
|
||||
tick();
|
||||
builder.invalidateProject("/src/logic");
|
||||
builder.buildInvalidatedProjects();
|
||||
builder.buildInvalidatedProject();
|
||||
// The file should be updated
|
||||
assert.equal(fs.statSync("/src/logic/index.js").mtimeMs, time(), "JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should *not* have been rebuilt");
|
||||
|
||||
// Build downstream projects should update 'tests', but not 'core'
|
||||
tick();
|
||||
builder.buildDependentInvalidatedProjects();
|
||||
builder.buildInvalidatedProject();
|
||||
assert.equal(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/core/index.js").mtimeMs, time(), "Upstream JS file should not have been rebuilt");
|
||||
});
|
||||
@@ -240,11 +224,10 @@ namespace ts {
|
||||
|
||||
function verifyProjectWithResolveJsonModule(configFile: string, ...expectedDiagnosticMessages: DiagnosticMessage[]) {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, [configFile], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, [configFile], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(...expectedDiagnosticMessages);
|
||||
host.assertDiagnosticMessages(...expectedDiagnosticMessages);
|
||||
if (!expectedDiagnosticMessages.length) {
|
||||
// Check for outputs. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
@@ -274,11 +257,11 @@ namespace ts {
|
||||
let fs: vfs.FileSystem | undefined;
|
||||
before(() => {
|
||||
fs = outFileFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
});
|
||||
after(() => {
|
||||
fs = undefined;
|
||||
@@ -293,25 +276,24 @@ namespace ts {
|
||||
describe("tsbuild - downstream prepend projects always get rebuilt", () => {
|
||||
it("", () => {
|
||||
const fs = outFileFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "First build timestamp is correct");
|
||||
tick();
|
||||
replaceText(fs, "src/first/first_PART1.ts", "Hello", "Hola");
|
||||
tick();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "Second build timestamp is correct");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("tsbuild - graph-ordering", () => {
|
||||
let host: fakes.CompilerHost | undefined;
|
||||
let host: fakes.SolutionBuilderHost | undefined;
|
||||
const deps: [string, string][] = [
|
||||
["A", "B"],
|
||||
["B", "C"],
|
||||
@@ -324,7 +306,7 @@ namespace ts {
|
||||
|
||||
before(() => {
|
||||
const fs = new vfs.FileSystem(false);
|
||||
host = new fakes.CompilerHost(fs);
|
||||
host = new fakes.SolutionBuilderHost(fs);
|
||||
writeProjects(fs, ["A", "B", "C", "D", "E", "F", "G"], deps);
|
||||
});
|
||||
|
||||
@@ -349,7 +331,7 @@ namespace ts {
|
||||
});
|
||||
|
||||
function checkGraphOrdering(rootNames: string[], expectedBuildSet: string[]) {
|
||||
const builder = createSolutionBuilder(host!, buildHost, rootNames, { dry: true, force: false, verbose: false });
|
||||
const builder = createSolutionBuilder(host!, rootNames, { dry: true, force: false, verbose: false });
|
||||
|
||||
const projFileNames = rootNames.map(getProjectFileName);
|
||||
const graph = builder.getBuildGraph(projFileNames);
|
||||
@@ -404,30 +386,6 @@ namespace ts {
|
||||
fs.writeFileSync(path, newContent, "utf-8");
|
||||
}
|
||||
|
||||
function assertDiagnosticMessages(...expected: DiagnosticMessage[]) {
|
||||
const actual = lastDiagnostics.slice();
|
||||
if (actual.length !== expected.length) {
|
||||
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
|
||||
}
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual[i].code !== expected[i].code) {
|
||||
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearDiagnostics() {
|
||||
lastDiagnostics = [];
|
||||
}
|
||||
|
||||
export function printDiagnostics(header = "== Diagnostics ==") {
|
||||
const out = createDiagnosticReporter(sys);
|
||||
sys.write(header + "\r\n");
|
||||
for (const d of lastDiagnostics) {
|
||||
out(d);
|
||||
}
|
||||
}
|
||||
|
||||
function tick() {
|
||||
currentTime += 60_000;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
namespace ts.tscWatch {
|
||||
export import libFile = TestFSWithWatch.libFile;
|
||||
function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const host = createSolutionBuilderWithWatchHost(system);
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { dry: false, force: false, verbose: false, watch: true });
|
||||
}
|
||||
|
||||
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const solutionBuilder = createSolutionBuilder(host, rootNames, defaultOptions);
|
||||
solutionBuilder.buildAllProjects();
|
||||
solutionBuilder.startWatching();
|
||||
return solutionBuilder;
|
||||
}
|
||||
|
||||
describe("tsbuild-watch program updates", () => {
|
||||
const projectsLocation = "/user/username/projects";
|
||||
const project = "sample1";
|
||||
const enum SubProject {
|
||||
core = "core",
|
||||
logic = "logic",
|
||||
tests = "tests",
|
||||
ui = "ui"
|
||||
}
|
||||
type ReadonlyFile = Readonly<File>;
|
||||
/** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */
|
||||
type SubProjectFiles = [ReadonlyFile, ReadonlyFile] | [ReadonlyFile, ReadonlyFile, ReadonlyFile, ReadonlyFile];
|
||||
const root = Harness.IO.getWorkspaceRoot();
|
||||
|
||||
function projectFilePath(subProject: SubProject, baseFileName: string) {
|
||||
return `${projectsLocation}/${project}/${subProject}/${baseFileName.toLowerCase()}`;
|
||||
}
|
||||
|
||||
function projectFile(subProject: SubProject, baseFileName: string): File {
|
||||
return {
|
||||
path: projectFilePath(subProject, baseFileName),
|
||||
content: Harness.IO.readFile(`${root}/tests/projects/${project}/${subProject}/${baseFileName}`)!
|
||||
};
|
||||
}
|
||||
|
||||
function subProjectFiles(subProject: SubProject, anotherModuleAndSomeDecl?: true): SubProjectFiles {
|
||||
const tsconfig = projectFile(subProject, "tsconfig.json");
|
||||
const index = projectFile(subProject, "index.ts");
|
||||
if (!anotherModuleAndSomeDecl) {
|
||||
return [tsconfig, index];
|
||||
}
|
||||
const anotherModule = projectFile(SubProject.core, "anotherModule.ts");
|
||||
const someDecl = projectFile(SubProject.core, "some_decl.ts");
|
||||
return [tsconfig, index, anotherModule, someDecl];
|
||||
}
|
||||
|
||||
function getOutputFileNames(subProject: SubProject, baseFileNameWithoutExtension: string) {
|
||||
const file = projectFilePath(subProject, baseFileNameWithoutExtension);
|
||||
return [`${file}.js`, `${file}.d.ts`];
|
||||
}
|
||||
|
||||
type OutputFileStamp = [string, Date | undefined];
|
||||
function getOutputStamps(host: WatchedSystem, subProject: SubProject, baseFileNameWithoutExtension: string): OutputFileStamp[] {
|
||||
return getOutputFileNames(subProject, baseFileNameWithoutExtension).map(f => [f, host.getModifiedTime(f)] as OutputFileStamp);
|
||||
}
|
||||
|
||||
function getOutputFileStamps(host: WatchedSystem): OutputFileStamp[] {
|
||||
return [
|
||||
...getOutputStamps(host, SubProject.core, "anotherModule"),
|
||||
...getOutputStamps(host, SubProject.core, "index"),
|
||||
...getOutputStamps(host, SubProject.logic, "index"),
|
||||
...getOutputStamps(host, SubProject.tests, "index"),
|
||||
];
|
||||
}
|
||||
|
||||
function verifyChangedFiles(actualStamps: OutputFileStamp[], oldTimeStamps: OutputFileStamp[], changedFiles: string[]) {
|
||||
for (let i = 0; i < oldTimeStamps.length; i++) {
|
||||
const actual = actualStamps[i];
|
||||
const old = oldTimeStamps[i];
|
||||
if (contains(changedFiles, actual[0])) {
|
||||
assert.isTrue((actual[1] || 0) > (old[1] || 0), `${actual[0]} expected to written`);
|
||||
}
|
||||
else {
|
||||
assert.equal(actual[1], old[1], `${actual[0]} expected to not change`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true);
|
||||
const logic = subProjectFiles(SubProject.logic);
|
||||
const tests = subProjectFiles(SubProject.tests);
|
||||
const ui = subProjectFiles(SubProject.ui);
|
||||
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
|
||||
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
|
||||
|
||||
function createSolutionInWatchMode() {
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
|
||||
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true); // TODO: #26524
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
}
|
||||
return { host, outputFileStamps };
|
||||
}
|
||||
it("creates solution in watch mode", () => {
|
||||
createSolutionInWatchMode();
|
||||
});
|
||||
|
||||
it("change builds changes and reports found errors message", () => {
|
||||
const { host, outputFileStamps } = createSolutionInWatchMode();
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
export class someClass { }`);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, outputFileStamps, [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"), // This should not be written really
|
||||
...getOutputFileNames(SubProject.core, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
|
||||
const changedTests = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedTests, changedCore, [
|
||||
...getOutputFileNames(SubProject.tests, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, changedTests, [
|
||||
...getOutputFileNames(SubProject.logic, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
});
|
||||
|
||||
// TODO: write tests reporting errors but that will have more involved work since file
|
||||
});
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
namespace ts.tscWatch {
|
||||
import WatchedSystem = TestFSWithWatch.TestServerHost;
|
||||
type File = TestFSWithWatch.File;
|
||||
type SymLink = TestFSWithWatch.SymLink;
|
||||
import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
|
||||
import checkArray = TestFSWithWatch.checkArray;
|
||||
import libFile = TestFSWithWatch.libFile;
|
||||
import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
|
||||
import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
|
||||
import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
|
||||
import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
|
||||
import checkOutputContains = TestFSWithWatch.checkOutputContains;
|
||||
import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
|
||||
import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
|
||||
export import WatchedSystem = TestFSWithWatch.TestServerHost;
|
||||
export type File = TestFSWithWatch.File;
|
||||
export type SymLink = TestFSWithWatch.SymLink;
|
||||
export import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
|
||||
export import checkArray = TestFSWithWatch.checkArray;
|
||||
export import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
|
||||
export import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
|
||||
export import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
|
||||
export import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
|
||||
export import checkOutputContains = TestFSWithWatch.checkOutputContains;
|
||||
export import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
|
||||
export import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
|
||||
|
||||
export function checkProgramActualFiles(program: Program, expectedFiles: string[]) {
|
||||
checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles);
|
||||
@@ -111,7 +110,7 @@ namespace ts.tscWatch {
|
||||
|
||||
function assertWatchDiagnostic(diagnostic: Diagnostic) {
|
||||
const expected = getWatchDiagnosticWithoutDate(diagnostic);
|
||||
if (!disableConsoleClears && !contains(nonClearingMessageCodes, diagnostic.code)) {
|
||||
if (!disableConsoleClears && contains(screenStartingMessageCodes, diagnostic.code)) {
|
||||
assert.equal(host.screenClears[screenClears], index, `Expected screen clear at this diagnostic: ${expected}`);
|
||||
screenClears++;
|
||||
}
|
||||
@@ -137,7 +136,7 @@ namespace ts.tscWatch {
|
||||
: createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length);
|
||||
}
|
||||
|
||||
function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
/*logsBeforeWatchDiagnostic*/ undefined,
|
||||
@@ -148,7 +147,7 @@ namespace ts.tscWatch {
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
|
||||
@@ -642,37 +642,54 @@ namespace ts.projectSystem {
|
||||
checkWatchedDirectories(host, [combinePaths(getDirectoryPath(appFile.path), nodeModulesAtTypes)], /*recursive*/ true);
|
||||
});
|
||||
|
||||
it("can handle tsconfig file name with difference casing", () => {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1"
|
||||
};
|
||||
const config = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
include: []
|
||||
})
|
||||
};
|
||||
describe("can handle tsconfig file name with difference casing", () => {
|
||||
function verifyConfigFileCasing(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1"
|
||||
};
|
||||
const config = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
include: []
|
||||
})
|
||||
};
|
||||
|
||||
const host = createServerHost([f1, config], { useCaseSensitiveFileNames: false });
|
||||
const service = createProjectService(host);
|
||||
const upperCaseConfigFilePath = combinePaths(getDirectoryPath(config.path).toUpperCase(), getBaseFileName(config.path));
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName: "/a/b/project.csproj",
|
||||
rootFiles: toExternalFiles([f1.path, upperCaseConfigFilePath]),
|
||||
options: {}
|
||||
const host = createServerHost([f1, config], { useCaseSensitiveFileNames: false });
|
||||
const service = createProjectService(host);
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
const upperCaseConfigFilePath = combinePaths(getDirectoryPath(config.path).toUpperCase(), getBaseFileName(config.path));
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName: "/a/b/project.csproj",
|
||||
rootFiles: toExternalFiles([f1.path, upperCaseConfigFilePath]),
|
||||
options: {}
|
||||
});
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(config.path)!;
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded
|
||||
checkProjectActualFiles(project, emptyArray);
|
||||
}
|
||||
else {
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
|
||||
checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
}
|
||||
|
||||
service.openClientFile(f1.path);
|
||||
service.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 });
|
||||
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project is updated
|
||||
checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [f1.path]);
|
||||
}
|
||||
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyConfigFileCasing(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(config.path)!;
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded
|
||||
checkProjectActualFiles(project, emptyArray);
|
||||
|
||||
service.openClientFile(f1.path);
|
||||
service.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 });
|
||||
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project is updated
|
||||
checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [f1.path]);
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyConfigFileCasing(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
});
|
||||
|
||||
it("create configured project without file list", () => {
|
||||
@@ -2950,45 +2967,56 @@ namespace ts.projectSystem {
|
||||
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);
|
||||
describe("deleting config file opened from the external project works", () => {
|
||||
function verifyDeletingConfigFile(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
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);
|
||||
projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
|
||||
const externalProject: protocol.ExternalProject = {
|
||||
projectFileName,
|
||||
rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)],
|
||||
options: { allowJs: false },
|
||||
typeAcquisition: { include: [] }
|
||||
};
|
||||
const externalProject: protocol.ExternalProject = {
|
||||
projectFileName,
|
||||
rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)],
|
||||
options: { allowJs: false },
|
||||
typeAcquisition: { include: [] }
|
||||
};
|
||||
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
|
||||
let knownProjects = projectService.synchronizeProjectList([]);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, externalProjects: 0, inferredProjects: 0 });
|
||||
let knownProjects = projectService.synchronizeProjectList([]);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, externalProjects: 0, inferredProjects: 0 });
|
||||
|
||||
const configProject = configuredProjectAt(projectService, 0);
|
||||
checkProjectActualFiles(configProject, []); // Since no files opened from this project, its not loaded
|
||||
const configProject = configuredProjectAt(projectService, 0);
|
||||
checkProjectActualFiles(configProject, lazyConfiguredProjectsFromExternalProject ?
|
||||
emptyArray : // Since no files opened from this project, its not loaded
|
||||
[libFile.path, configFile.path]);
|
||||
|
||||
host.reloadFS([libFile, site]);
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
host.reloadFS([libFile, site]);
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
|
||||
knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info!)); // TODO: GH#18217 GH#20039
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 });
|
||||
knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info!)); // TODO: GH#18217 GH#20039
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 });
|
||||
|
||||
externalProject.rootFiles.length = 1;
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
externalProject.rootFiles.length = 1;
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 1, inferredProjects: 0 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [site.path, libFile.path]);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 1, inferredProjects: 0 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [site.path, libFile.path]);
|
||||
}
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyDeletingConfigFile(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyDeletingConfigFile(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
});
|
||||
|
||||
it("Getting errors from closed script info does not throw exception (because of getting project from orphan script info)", () => {
|
||||
@@ -3298,49 +3326,64 @@ namespace ts.projectSystem {
|
||||
|
||||
});
|
||||
|
||||
it("includes deferred files in the project context", () => {
|
||||
const file1 = {
|
||||
path: "/a.deferred",
|
||||
content: "const a = 1;"
|
||||
};
|
||||
// Deferred extensions should not affect JS files.
|
||||
const file2 = {
|
||||
path: "/b.js",
|
||||
content: "const b = 1;"
|
||||
};
|
||||
const tsconfig = {
|
||||
path: "/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
describe("includes deferred files in the project context", () => {
|
||||
function verifyDeferredContext(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
const file1 = {
|
||||
path: "/a.deferred",
|
||||
content: "const a = 1;"
|
||||
};
|
||||
// Deferred extensions should not affect JS files.
|
||||
const file2 = {
|
||||
path: "/b.js",
|
||||
content: "const b = 1;"
|
||||
};
|
||||
const tsconfig = {
|
||||
path: "/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
|
||||
const host = createServerHost([file1, file2, tsconfig]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
const host = createServerHost([file1, file2, tsconfig]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
session.executeCommandSeq<protocol.ConfigureRequest>({
|
||||
command: protocol.CommandTypes.Configure,
|
||||
arguments: { preferences: { lazyConfiguredProjectsFromExternalProject } }
|
||||
});
|
||||
|
||||
// Configure the deferred extension.
|
||||
const extraFileExtensions = [{ extension: ".deferred", scriptKind: ScriptKind.Deferred, isMixedContent: true }];
|
||||
const configureHostRequest = makeSessionRequest<protocol.ConfigureRequestArguments>(CommandNames.Configure, { extraFileExtensions });
|
||||
session.executeCommand(configureHostRequest);
|
||||
// Configure the deferred extension.
|
||||
const extraFileExtensions = [{ extension: ".deferred", scriptKind: ScriptKind.Deferred, isMixedContent: true }];
|
||||
const configureHostRequest = makeSessionRequest<protocol.ConfigureRequestArguments>(CommandNames.Configure, { extraFileExtensions });
|
||||
session.executeCommand(configureHostRequest);
|
||||
|
||||
// Open external project
|
||||
const projectName = "/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([file1.path, file2.path, tsconfig.path]),
|
||||
options: {}
|
||||
// Open external project
|
||||
const projectName = "/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([file1.path, file2.path, tsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
// Assert
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
|
||||
const configuredProject = configuredProjectAt(projectService, 0);
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
// configured project is just created and not yet loaded
|
||||
checkProjectActualFiles(configuredProject, emptyArray);
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
checkProjectActualFiles(configuredProject, [file1.path, tsconfig.path]);
|
||||
|
||||
// Allow allowNonTsExtensions will be set to true for deferred extensions.
|
||||
assert.isTrue(configuredProject.getCompilerOptions().allowNonTsExtensions);
|
||||
}
|
||||
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyDeferredContext(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyDeferredContext(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
|
||||
// Assert
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
|
||||
const configuredProject = configuredProjectAt(projectService, 0);
|
||||
// configured project is just created and not yet loaded
|
||||
checkProjectActualFiles(configuredProject, emptyArray);
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
checkProjectActualFiles(configuredProject, [file1.path, tsconfig.path]);
|
||||
|
||||
// Allow allowNonTsExtensions will be set to true for deferred extensions.
|
||||
assert.isTrue(configuredProject.getCompilerOptions().allowNonTsExtensions);
|
||||
});
|
||||
|
||||
it("Orphan source files are handled correctly on watch trigger", () => {
|
||||
@@ -3943,143 +3986,167 @@ namespace ts.projectSystem {
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem external projects", () => {
|
||||
it("correctly handling add/remove tsconfig - 1", () => {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1;"
|
||||
};
|
||||
const f2 = {
|
||||
path: "/a/b/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const tsconfig = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
const host = createServerHost([f1, f2]);
|
||||
const projectService = createProjectService(host);
|
||||
describe("correctly handling add/remove tsconfig - 1", () => {
|
||||
function verifyAddRemoveConfig(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1;"
|
||||
};
|
||||
const f2 = {
|
||||
path: "/a/b/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const tsconfig = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
const host = createServerHost([f1, f2]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.openClientFile(f1.path);
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
|
||||
// rename lib.ts to tsconfig.json
|
||||
host.reloadFS([f1, tsconfig]);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, tsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]);
|
||||
|
||||
// rename tsconfig.json back to lib.ts
|
||||
host.reloadFS([f1, f2]);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
}
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
projectService.openClientFile(f1.path);
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
|
||||
// rename lib.ts to tsconfig.json
|
||||
host.reloadFS([f1, tsconfig]);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, tsconfig.path]),
|
||||
options: {}
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]);
|
||||
|
||||
// rename tsconfig.json back to lib.ts
|
||||
host.reloadFS([f1, f2]);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
});
|
||||
|
||||
describe("correctly handling add/remove tsconfig - 2", () => {
|
||||
function verifyAddRemoveConfig(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1;"
|
||||
};
|
||||
const cLib = {
|
||||
path: "/a/b/c/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const cTsconfig = {
|
||||
path: "/a/b/c/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const dLib = {
|
||||
path: "/a/b/d/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const dTsconfig = {
|
||||
path: "/a/b/d/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const host = createServerHost([f1, cLib, cTsconfig, dLib, dTsconfig]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
|
||||
it("correctly handling add/remove tsconfig - 2", () => {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1;"
|
||||
};
|
||||
const cLib = {
|
||||
path: "/a/b/c/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const cTsconfig = {
|
||||
path: "/a/b/c/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const dLib = {
|
||||
path: "/a/b/d/lib.ts",
|
||||
content: ""
|
||||
};
|
||||
const dTsconfig = {
|
||||
path: "/a/b/d/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const host = createServerHost([f1, cLib, cTsconfig, dLib, dTsconfig]);
|
||||
const projectService = createProjectService(host);
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove one config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove second config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// open two config files
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// close all projects - no projects should be opened
|
||||
projectService.closeExternalProject(projectName);
|
||||
projectService.checkNumberOfProjects({});
|
||||
}
|
||||
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
it("when lazyConfiguredProjectsFromExternalProject is set", () => {
|
||||
verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove one config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove second config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// open two config files
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// close all projects - no projects should be opened
|
||||
projectService.closeExternalProject(projectName);
|
||||
projectService.checkNumberOfProjects({});
|
||||
});
|
||||
|
||||
it("correctly handles changes in lib section of config file", () => {
|
||||
@@ -4174,6 +4241,47 @@ namespace ts.projectSystem {
|
||||
assert.isTrue(project.hasOpenRef()); // f
|
||||
assert.isFalse(project.isClosed());
|
||||
});
|
||||
|
||||
it("handles loads existing configured projects of external projects when lazyConfiguredProjectsFromExternalProject is disabled", () => {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 1"
|
||||
};
|
||||
const config = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({})
|
||||
};
|
||||
const projectFileName = "/a/b/project.csproj";
|
||||
const host = createServerHost([f1, config]);
|
||||
const service = createProjectService(host);
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: true } });
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName,
|
||||
rootFiles: toExternalFiles([f1.path, config.path]),
|
||||
options: {}
|
||||
});
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(config.path)!;
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded
|
||||
checkProjectActualFiles(project, emptyArray);
|
||||
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: false } });
|
||||
assert.equal(project.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
|
||||
checkProjectActualFiles(project, [config.path, f1.path]);
|
||||
|
||||
service.closeExternalProject(projectFileName);
|
||||
service.checkNumberOfProjects({});
|
||||
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName,
|
||||
rootFiles: toExternalFiles([f1.path, config.path]),
|
||||
options: {}
|
||||
});
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project2 = service.configuredProjects.get(config.path)!;
|
||||
assert.equal(project2.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
|
||||
checkProjectActualFiles(project2, [config.path, f1.path]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem prefer typings to js", () => {
|
||||
@@ -8257,7 +8365,7 @@ new C();`
|
||||
|
||||
verifyProjectWithResolvedModule(session);
|
||||
|
||||
host.removeFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.deleteFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
@@ -9173,7 +9281,7 @@ describe("Test Suite 1", () => {
|
||||
checkProjectActualFiles(project, expectedFilesWithUnitTest1);
|
||||
|
||||
const navBarResultUnitTest1 = navBarFull(session, unitTest1);
|
||||
host.removeFile(unitTest1.path);
|
||||
host.deleteFile(unitTest1.path);
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkProjectActualFiles(project, expectedFilesWithoutUnitTest1);
|
||||
|
||||
@@ -9210,6 +9318,128 @@ export function Test2() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem completions", () => {
|
||||
it("works", () => {
|
||||
const aTs: File = {
|
||||
path: "/a.ts",
|
||||
content: "export const foo = 0;",
|
||||
};
|
||||
const bTs: File = {
|
||||
path: "/b.ts",
|
||||
content: "foo",
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: "/tsconfig.json",
|
||||
content: "{}",
|
||||
};
|
||||
|
||||
const host = createServerHost([aTs, bTs, tsconfig]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([aTs, bTs], session);
|
||||
|
||||
const requestLocation: protocol.FileLocationRequestArgs = {
|
||||
file: bTs.path,
|
||||
line: 1,
|
||||
offset: 3,
|
||||
};
|
||||
|
||||
const response = executeSessionRequest<protocol.CompletionsRequest, protocol.CompletionInfoResponse>(session, protocol.CommandTypes.CompletionInfo, {
|
||||
...requestLocation,
|
||||
includeExternalModuleExports: true,
|
||||
prefix: "foo",
|
||||
});
|
||||
const entry: protocol.CompletionEntry = {
|
||||
hasAction: true,
|
||||
insertText: undefined,
|
||||
isRecommended: undefined,
|
||||
kind: ScriptElementKind.constElement,
|
||||
kindModifiers: ScriptElementKindModifier.exportedModifier,
|
||||
name: "foo",
|
||||
replacementSpan: undefined,
|
||||
sortText: "0",
|
||||
source: "/a",
|
||||
};
|
||||
assert.deepEqual<protocol.CompletionInfo | undefined>(response, {
|
||||
isGlobalCompletion: true,
|
||||
isMemberCompletion: false,
|
||||
isNewIdentifierLocation: false,
|
||||
entries: [entry],
|
||||
});
|
||||
|
||||
const detailsRequestArgs: protocol.CompletionDetailsRequestArgs = {
|
||||
...requestLocation,
|
||||
entryNames: [{ name: "foo", source: "/a" }],
|
||||
};
|
||||
|
||||
const detailsResponse = executeSessionRequest<protocol.CompletionDetailsRequest, protocol.CompletionDetailsResponse>(session, protocol.CommandTypes.CompletionDetails, detailsRequestArgs);
|
||||
const detailsCommon: protocol.CompletionEntryDetails & CompletionEntryDetails = {
|
||||
displayParts: [
|
||||
keywordPart(SyntaxKind.ConstKeyword),
|
||||
spacePart(),
|
||||
displayPart("foo", SymbolDisplayPartKind.localName),
|
||||
punctuationPart(SyntaxKind.ColonToken),
|
||||
spacePart(),
|
||||
displayPart("0", SymbolDisplayPartKind.stringLiteral),
|
||||
],
|
||||
documentation: emptyArray,
|
||||
kind: ScriptElementKind.constElement,
|
||||
kindModifiers: ScriptElementKindModifier.exportedModifier,
|
||||
name: "foo",
|
||||
source: [{ text: "./a", kind: "text" }],
|
||||
tags: emptyArray,
|
||||
};
|
||||
assert.deepEqual<ReadonlyArray<protocol.CompletionEntryDetails> | undefined>(detailsResponse, [
|
||||
{
|
||||
codeActions: [
|
||||
{
|
||||
description: `Import 'foo' from module "./a"`,
|
||||
changes: [
|
||||
{
|
||||
fileName: "/b.ts",
|
||||
textChanges: [
|
||||
{
|
||||
start: { line: 1, offset: 1 },
|
||||
end: { line: 1, offset: 1 },
|
||||
newText: 'import { foo } from "./a";\n\n',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
commands: undefined,
|
||||
},
|
||||
],
|
||||
...detailsCommon,
|
||||
},
|
||||
]);
|
||||
|
||||
interface CompletionDetailsFullRequest extends protocol.FileLocationRequest {
|
||||
readonly command: protocol.CommandTypes.CompletionDetailsFull;
|
||||
readonly arguments: protocol.CompletionDetailsRequestArgs;
|
||||
}
|
||||
interface CompletionDetailsFullResponse extends protocol.Response {
|
||||
readonly body?: ReadonlyArray<CompletionEntryDetails>;
|
||||
}
|
||||
const detailsFullResponse = executeSessionRequest<CompletionDetailsFullRequest, CompletionDetailsFullResponse>(session, protocol.CommandTypes.CompletionDetailsFull, detailsRequestArgs);
|
||||
assert.deepEqual<ReadonlyArray<CompletionEntryDetails> | undefined>(detailsFullResponse, [
|
||||
{
|
||||
codeActions: [
|
||||
{
|
||||
description: `Import 'foo' from module "./a"`,
|
||||
changes: [
|
||||
{
|
||||
fileName: "/b.ts",
|
||||
textChanges: [createTextChange(createTextSpan(0, 0), 'import { foo } from "./a";\n\n')],
|
||||
},
|
||||
],
|
||||
commands: undefined,
|
||||
}
|
||||
],
|
||||
...detailsCommon,
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem project references", () => {
|
||||
const aTs: File = {
|
||||
path: "/a/a.ts",
|
||||
@@ -9297,7 +9527,7 @@ export function Test2() {
|
||||
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
|
||||
|
||||
// Testing what happens if we delete the original sources.
|
||||
host.removeFile(bTs.path);
|
||||
host.deleteFile(bTs.path);
|
||||
|
||||
openFilesForSession([userTs], session);
|
||||
const service = session.getProjectService();
|
||||
|
||||
+145
-13
@@ -13,7 +13,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
let reportDiagnostic = createDiagnosticReporter(sys);
|
||||
function updateReportDiagnostic(options: CompilerOptions) {
|
||||
function updateReportDiagnostic(options?: CompilerOptions) {
|
||||
if (shouldBePretty(options)) {
|
||||
reportDiagnostic = createDiagnosticReporter(sys, /*pretty*/ true);
|
||||
}
|
||||
@@ -23,8 +23,8 @@ namespace ts {
|
||||
return !!sys.writeOutputIsTTY && sys.writeOutputIsTTY();
|
||||
}
|
||||
|
||||
function shouldBePretty(options: CompilerOptions) {
|
||||
if (typeof options.pretty === "undefined") {
|
||||
function shouldBePretty(options?: CompilerOptions) {
|
||||
if (!options || typeof options.pretty === "undefined") {
|
||||
return defaultIsPretty();
|
||||
}
|
||||
return options.pretty;
|
||||
@@ -54,15 +54,7 @@ namespace ts {
|
||||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
if (args.length > 0 && ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b"))) {
|
||||
const reportDiag = createDiagnosticReporter(sys, defaultIsPretty());
|
||||
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiag(createCompilerDiagnostic(message, ...args));
|
||||
const buildHost: BuildHost = {
|
||||
error: report,
|
||||
verbose: report,
|
||||
message: report,
|
||||
errorDiagnostic: d => reportDiag(d)
|
||||
};
|
||||
const result = performBuild(args.slice(1), createCompilerHost({}), buildHost, sys);
|
||||
const result = performBuild(args.slice(1));
|
||||
// undefined = in watch mode, do not exit
|
||||
if (result !== undefined) {
|
||||
return sys.exit(result);
|
||||
@@ -172,6 +164,146 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function performBuild(args: string[]): number | undefined {
|
||||
const buildOpts: CommandLineOption[] = [
|
||||
{
|
||||
name: "help",
|
||||
shortName: "h",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Print_this_message,
|
||||
},
|
||||
{
|
||||
name: "help",
|
||||
shortName: "?",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "verbose",
|
||||
shortName: "v",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Enable_verbose_logging,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "dry",
|
||||
shortName: "d",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "force",
|
||||
shortName: "f",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "clean",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Delete_the_outputs_of_all_projects,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Watch_input_files,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "preserveWatchOutput",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
|
||||
},
|
||||
];
|
||||
let buildOptionNameMap: OptionNameMap | undefined;
|
||||
const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts)));
|
||||
|
||||
const buildOptions: BuildOptions = {};
|
||||
const projects: string[] = [];
|
||||
for (const arg of args) {
|
||||
if (arg.charCodeAt(0) === CharacterCodes.minus) {
|
||||
const opt = getOptionDeclarationFromName(returnBuildOptionNameMap, arg.slice(arg.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
if (opt) {
|
||||
buildOptions[opt.name as keyof BuildOptions] = true;
|
||||
}
|
||||
else {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Unknown_build_option_0, arg));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not a flag, parse as filename
|
||||
addProject(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (buildOptions.help) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
// Update to pretty if host supports it
|
||||
updateReportDiagnostic();
|
||||
|
||||
if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.watch) {
|
||||
reportWatchModeWithoutSysSupport();
|
||||
}
|
||||
|
||||
// Nonsensical combinations
|
||||
if (buildOptions.clean && buildOptions.force) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.verbose) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.watch) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.watch && buildOptions.dry) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
|
||||
if (projects.length === 0) {
|
||||
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
|
||||
addProject(".");
|
||||
}
|
||||
|
||||
// TODO: change this to host if watch => watchHost otherwiue without wathc
|
||||
const builder = createSolutionBuilder(createSolutionBuilderWithWatchHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createWatchStatusReporter()), projects, buildOptions);
|
||||
if (buildOptions.clean) {
|
||||
return builder.cleanAllProjects();
|
||||
}
|
||||
|
||||
if (buildOptions.watch) {
|
||||
builder.buildAllProjects();
|
||||
builder.startWatching();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return builder.buildAllProjects();
|
||||
|
||||
function addProject(projectSpecification: string) {
|
||||
const fileName = resolvePath(sys.getCurrentDirectory(), projectSpecification);
|
||||
const refPath = resolveProjectReferencePath(sys, { path: fileName });
|
||||
if (!sys.fileExists(refPath)) {
|
||||
return reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, fileName));
|
||||
}
|
||||
projects.push(refPath);
|
||||
}
|
||||
}
|
||||
|
||||
function performCompilation(rootNames: string[], projectReferences: ReadonlyArray<ProjectReference> | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
const host = createCompilerHost(options);
|
||||
enableStatistics(options);
|
||||
@@ -205,7 +337,7 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createWatchStatusReporter(options: CompilerOptions) {
|
||||
function createWatchStatusReporter(options?: CompilerOptions) {
|
||||
return ts.createWatchStatusReporter(sys, shouldBePretty(options));
|
||||
}
|
||||
|
||||
|
||||
+31
-28
@@ -2690,9 +2690,6 @@ declare namespace ts {
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
createHash?(data: string): string;
|
||||
getModifiedTime?(fileName: string): Date | undefined;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
interface SourceMapRange extends TextRange {
|
||||
source?: SourceMapSource;
|
||||
@@ -2993,6 +2990,16 @@ declare namespace ts {
|
||||
Parameters = 1296,
|
||||
IndexSignatureParameters = 4432
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
}
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
@@ -4312,15 +4319,26 @@ declare namespace ts {
|
||||
type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
/**
|
||||
* Used to create the program when need for program creation or recreation detected
|
||||
*/
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
@@ -4353,14 +4371,6 @@ declare namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
@@ -4636,14 +4646,6 @@ declare namespace ts {
|
||||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
interface LanguageService {
|
||||
cleanupSemanticCache(): void;
|
||||
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
@@ -6948,7 +6950,7 @@ declare namespace ts.server.protocol {
|
||||
* begin with prefix.
|
||||
*/
|
||||
interface CompletionsRequest extends FileLocationRequest {
|
||||
command: CommandTypes.Completions;
|
||||
command: CommandTypes.Completions | CommandTypes.CompletionInfo;
|
||||
arguments: CompletionsRequestArgs;
|
||||
}
|
||||
/**
|
||||
@@ -7795,6 +7797,7 @@ declare namespace ts.server.protocol {
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
}
|
||||
interface CompilerOptions {
|
||||
allowJs?: boolean;
|
||||
@@ -7926,14 +7929,14 @@ declare namespace ts.server {
|
||||
getSnapshot(): IScriptSnapshot;
|
||||
private ensureRealPath;
|
||||
getFormatCodeSettings(): FormatCodeSettings | undefined;
|
||||
getPreferences(): UserPreferences | undefined;
|
||||
getPreferences(): protocol.UserPreferences | undefined;
|
||||
attachToProject(project: Project): boolean;
|
||||
isAttached(project: Project): boolean;
|
||||
detachFromProject(project: Project): void;
|
||||
detachAllProjects(): void;
|
||||
getDefaultProject(): Project;
|
||||
registerFileUpdate(): void;
|
||||
setOptions(formatSettings: FormatCodeSettings, preferences: UserPreferences | undefined): void;
|
||||
setOptions(formatSettings: FormatCodeSettings, preferences: protocol.UserPreferences | undefined): void;
|
||||
getLatestVersion(): string;
|
||||
saveTo(fileName: string): void;
|
||||
reloadFromFile(tempFileName?: NormalizedPath): boolean;
|
||||
@@ -8311,7 +8314,7 @@ declare namespace ts.server {
|
||||
function convertScriptKindName(scriptKindName: protocol.ScriptKindName): ScriptKind.Unknown | ScriptKind.JS | ScriptKind.JSX | ScriptKind.TS | ScriptKind.TSX;
|
||||
interface HostConfiguration {
|
||||
formatCodeOptions: FormatCodeSettings;
|
||||
preferences: UserPreferences;
|
||||
preferences: protocol.UserPreferences;
|
||||
hostInfo: string;
|
||||
extraFileExtensions?: FileExtensionInfo[];
|
||||
}
|
||||
@@ -8430,9 +8433,9 @@ declare namespace ts.server {
|
||||
*/
|
||||
private ensureProjectStructuresUptoDate;
|
||||
getFormatCodeOptions(file: NormalizedPath): FormatCodeSettings;
|
||||
getPreferences(file: NormalizedPath): UserPreferences;
|
||||
getPreferences(file: NormalizedPath): protocol.UserPreferences;
|
||||
getHostFormatCodeOptions(): FormatCodeSettings;
|
||||
getHostPreferences(): UserPreferences;
|
||||
getHostPreferences(): protocol.UserPreferences;
|
||||
private onSourceFileChanged;
|
||||
private handleDeletedFile;
|
||||
private onConfigChangedForConfiguredProject;
|
||||
|
||||
+24
-22
@@ -2690,9 +2690,6 @@ declare namespace ts {
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
createHash?(data: string): string;
|
||||
getModifiedTime?(fileName: string): Date | undefined;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
interface SourceMapRange extends TextRange {
|
||||
source?: SourceMapSource;
|
||||
@@ -2993,6 +2990,16 @@ declare namespace ts {
|
||||
Parameters = 1296,
|
||||
IndexSignatureParameters = 4432
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
}
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
@@ -4312,15 +4319,26 @@ declare namespace ts {
|
||||
type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
/**
|
||||
* Used to create the program when need for program creation or recreation detected
|
||||
*/
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
@@ -4353,14 +4371,6 @@ declare namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
@@ -4636,14 +4646,6 @@ declare namespace ts {
|
||||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
interface LanguageService {
|
||||
cleanupSemanticCache(): void;
|
||||
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
|
||||
@@ -23,7 +23,7 @@ function foo() {
|
||||
|
||||
var x: TokenType = list['one'];
|
||||
>x : TokenType
|
||||
>list['one'] : any
|
||||
>list['one'] : error
|
||||
>list : {}
|
||||
>'one' : "one"
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ interface Function {
|
||||
}
|
||||
|
||||
var a = {}[0]; // Should be Foo
|
||||
>a : any
|
||||
>{}[0] : any
|
||||
>a : error
|
||||
>{}[0] : error
|
||||
>{} : {}
|
||||
>0 : 0
|
||||
|
||||
var b = (() => { })[0]; // Should be Bar
|
||||
>b : any
|
||||
>(() => { })[0] : any
|
||||
>b : error
|
||||
>(() => { })[0] : error
|
||||
>(() => { }) : () => void
|
||||
>() => { } : () => void
|
||||
>0 : 0
|
||||
|
||||
@@ -22,8 +22,8 @@ var r1 = o['data']; // Should be number
|
||||
>'data' : "data"
|
||||
|
||||
var r2 = o['functionData']; // Should be any (no property found)
|
||||
>r2 : any
|
||||
>o['functionData'] : any
|
||||
>r2 : error
|
||||
>o['functionData'] : error
|
||||
>o : {}
|
||||
>'functionData' : "functionData"
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
//// [badInferenceLowerPriorityThanGoodInference.ts]
|
||||
// Repro from #13118
|
||||
|
||||
interface Foo<A> {
|
||||
a: A;
|
||||
b: (x: A) => void;
|
||||
@@ -11,11 +13,24 @@ const result = canYouInferThis(() => ({
|
||||
b: x => { }
|
||||
}))
|
||||
|
||||
result.BLAH;
|
||||
result.BLAH;
|
||||
|
||||
// Repro from #26629
|
||||
|
||||
function goofus <ARGS extends any[]> (f: (...args: ARGS) => any ) {}
|
||||
|
||||
goofus((a: string) => ({ dog() { return a; } }));
|
||||
goofus((a: string) => ({ dog: function() { return a; } }));
|
||||
|
||||
|
||||
//// [badInferenceLowerPriorityThanGoodInference.js]
|
||||
// Repro from #13118
|
||||
var result = canYouInferThis(function () { return ({
|
||||
a: { BLAH: 33 },
|
||||
b: function (x) { }
|
||||
}); });
|
||||
result.BLAH;
|
||||
// Repro from #26629
|
||||
function goofus(f) { }
|
||||
goofus(function (a) { return ({ dog: function () { return a; } }); });
|
||||
goofus(function (a) { return ({ dog: function () { return a; } }); });
|
||||
|
||||
@@ -1,42 +1,65 @@
|
||||
=== tests/cases/compiler/badInferenceLowerPriorityThanGoodInference.ts ===
|
||||
// Repro from #13118
|
||||
|
||||
interface Foo<A> {
|
||||
>Foo : Symbol(Foo, Decl(badInferenceLowerPriorityThanGoodInference.ts, 0, 0))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 0, 14))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 2, 14))
|
||||
|
||||
a: A;
|
||||
>a : Symbol(Foo.a, Decl(badInferenceLowerPriorityThanGoodInference.ts, 0, 18))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 0, 14))
|
||||
>a : Symbol(Foo.a, Decl(badInferenceLowerPriorityThanGoodInference.ts, 2, 18))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 2, 14))
|
||||
|
||||
b: (x: A) => void;
|
||||
>b : Symbol(Foo.b, Decl(badInferenceLowerPriorityThanGoodInference.ts, 1, 9))
|
||||
>x : Symbol(x, Decl(badInferenceLowerPriorityThanGoodInference.ts, 2, 8))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 0, 14))
|
||||
>b : Symbol(Foo.b, Decl(badInferenceLowerPriorityThanGoodInference.ts, 3, 9))
|
||||
>x : Symbol(x, Decl(badInferenceLowerPriorityThanGoodInference.ts, 4, 8))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 2, 14))
|
||||
}
|
||||
|
||||
declare function canYouInferThis<A>(fn: () => Foo<A>): A;
|
||||
>canYouInferThis : Symbol(canYouInferThis, Decl(badInferenceLowerPriorityThanGoodInference.ts, 3, 1))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 5, 33))
|
||||
>fn : Symbol(fn, Decl(badInferenceLowerPriorityThanGoodInference.ts, 5, 36))
|
||||
>canYouInferThis : Symbol(canYouInferThis, Decl(badInferenceLowerPriorityThanGoodInference.ts, 5, 1))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 7, 33))
|
||||
>fn : Symbol(fn, Decl(badInferenceLowerPriorityThanGoodInference.ts, 7, 36))
|
||||
>Foo : Symbol(Foo, Decl(badInferenceLowerPriorityThanGoodInference.ts, 0, 0))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 5, 33))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 5, 33))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 7, 33))
|
||||
>A : Symbol(A, Decl(badInferenceLowerPriorityThanGoodInference.ts, 7, 33))
|
||||
|
||||
const result = canYouInferThis(() => ({
|
||||
>result : Symbol(result, Decl(badInferenceLowerPriorityThanGoodInference.ts, 7, 5))
|
||||
>canYouInferThis : Symbol(canYouInferThis, Decl(badInferenceLowerPriorityThanGoodInference.ts, 3, 1))
|
||||
>result : Symbol(result, Decl(badInferenceLowerPriorityThanGoodInference.ts, 9, 5))
|
||||
>canYouInferThis : Symbol(canYouInferThis, Decl(badInferenceLowerPriorityThanGoodInference.ts, 5, 1))
|
||||
|
||||
a: { BLAH: 33 },
|
||||
>a : Symbol(a, Decl(badInferenceLowerPriorityThanGoodInference.ts, 7, 39))
|
||||
>BLAH : Symbol(BLAH, Decl(badInferenceLowerPriorityThanGoodInference.ts, 8, 8))
|
||||
>a : Symbol(a, Decl(badInferenceLowerPriorityThanGoodInference.ts, 9, 39))
|
||||
>BLAH : Symbol(BLAH, Decl(badInferenceLowerPriorityThanGoodInference.ts, 10, 8))
|
||||
|
||||
b: x => { }
|
||||
>b : Symbol(b, Decl(badInferenceLowerPriorityThanGoodInference.ts, 8, 20))
|
||||
>x : Symbol(x, Decl(badInferenceLowerPriorityThanGoodInference.ts, 9, 6))
|
||||
>b : Symbol(b, Decl(badInferenceLowerPriorityThanGoodInference.ts, 10, 20))
|
||||
>x : Symbol(x, Decl(badInferenceLowerPriorityThanGoodInference.ts, 11, 6))
|
||||
|
||||
}))
|
||||
|
||||
result.BLAH;
|
||||
>result.BLAH : Symbol(BLAH, Decl(badInferenceLowerPriorityThanGoodInference.ts, 8, 8))
|
||||
>result : Symbol(result, Decl(badInferenceLowerPriorityThanGoodInference.ts, 7, 5))
|
||||
>BLAH : Symbol(BLAH, Decl(badInferenceLowerPriorityThanGoodInference.ts, 8, 8))
|
||||
>result.BLAH : Symbol(BLAH, Decl(badInferenceLowerPriorityThanGoodInference.ts, 10, 8))
|
||||
>result : Symbol(result, Decl(badInferenceLowerPriorityThanGoodInference.ts, 9, 5))
|
||||
>BLAH : Symbol(BLAH, Decl(badInferenceLowerPriorityThanGoodInference.ts, 10, 8))
|
||||
|
||||
// Repro from #26629
|
||||
|
||||
function goofus <ARGS extends any[]> (f: (...args: ARGS) => any ) {}
|
||||
>goofus : Symbol(goofus, Decl(badInferenceLowerPriorityThanGoodInference.ts, 14, 12))
|
||||
>ARGS : Symbol(ARGS, Decl(badInferenceLowerPriorityThanGoodInference.ts, 18, 17))
|
||||
>f : Symbol(f, Decl(badInferenceLowerPriorityThanGoodInference.ts, 18, 38))
|
||||
>args : Symbol(args, Decl(badInferenceLowerPriorityThanGoodInference.ts, 18, 42))
|
||||
>ARGS : Symbol(ARGS, Decl(badInferenceLowerPriorityThanGoodInference.ts, 18, 17))
|
||||
|
||||
goofus((a: string) => ({ dog() { return a; } }));
|
||||
>goofus : Symbol(goofus, Decl(badInferenceLowerPriorityThanGoodInference.ts, 14, 12))
|
||||
>a : Symbol(a, Decl(badInferenceLowerPriorityThanGoodInference.ts, 20, 8))
|
||||
>dog : Symbol(dog, Decl(badInferenceLowerPriorityThanGoodInference.ts, 20, 24))
|
||||
>a : Symbol(a, Decl(badInferenceLowerPriorityThanGoodInference.ts, 20, 8))
|
||||
|
||||
goofus((a: string) => ({ dog: function() { return a; } }));
|
||||
>goofus : Symbol(goofus, Decl(badInferenceLowerPriorityThanGoodInference.ts, 14, 12))
|
||||
>a : Symbol(a, Decl(badInferenceLowerPriorityThanGoodInference.ts, 21, 8))
|
||||
>dog : Symbol(dog, Decl(badInferenceLowerPriorityThanGoodInference.ts, 21, 24))
|
||||
>a : Symbol(a, Decl(badInferenceLowerPriorityThanGoodInference.ts, 21, 8))
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
=== tests/cases/compiler/badInferenceLowerPriorityThanGoodInference.ts ===
|
||||
// Repro from #13118
|
||||
|
||||
interface Foo<A> {
|
||||
a: A;
|
||||
>a : A
|
||||
@@ -38,3 +40,31 @@ result.BLAH;
|
||||
>result : { BLAH: number; }
|
||||
>BLAH : number
|
||||
|
||||
// Repro from #26629
|
||||
|
||||
function goofus <ARGS extends any[]> (f: (...args: ARGS) => any ) {}
|
||||
>goofus : <ARGS extends any[]>(f: (...args: ARGS) => any) => void
|
||||
>f : (...args: ARGS) => any
|
||||
>args : ARGS
|
||||
|
||||
goofus((a: string) => ({ dog() { return a; } }));
|
||||
>goofus((a: string) => ({ dog() { return a; } })) : void
|
||||
>goofus : <ARGS extends any[]>(f: (...args: ARGS) => any) => void
|
||||
>(a: string) => ({ dog() { return a; } }) : (a: string) => { dog(): string; }
|
||||
>a : string
|
||||
>({ dog() { return a; } }) : { dog(): string; }
|
||||
>{ dog() { return a; } } : { dog(): string; }
|
||||
>dog : () => string
|
||||
>a : string
|
||||
|
||||
goofus((a: string) => ({ dog: function() { return a; } }));
|
||||
>goofus((a: string) => ({ dog: function() { return a; } })) : void
|
||||
>goofus : <ARGS extends any[]>(f: (...args: ARGS) => any) => void
|
||||
>(a: string) => ({ dog: function() { return a; } }) : (a: string) => { dog: () => string; }
|
||||
>a : string
|
||||
>({ dog: function() { return a; } }) : { dog: () => string; }
|
||||
>{ dog: function() { return a; } } : { dog: () => string; }
|
||||
>dog : () => string
|
||||
>function() { return a; } : () => string
|
||||
>a : string
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ obj1["26"]; // string
|
||||
>"26" : "26"
|
||||
|
||||
obj1["0b11010"]; // any
|
||||
>obj1["0b11010"] : any
|
||||
>obj1["0b11010"] : error
|
||||
>obj1 : { 0b11010: string; a: number; bin1: number; b: number; 0B111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111101001010100000010111110001111111111: boolean; }
|
||||
>"0b11010" : "0b11010"
|
||||
|
||||
@@ -119,7 +119,7 @@ obj2["26"]; // string
|
||||
>"26" : "26"
|
||||
|
||||
obj2["0B11010"]; // any
|
||||
>obj2["0B11010"] : any
|
||||
>obj2["0B11010"] : error
|
||||
>obj2 : { 0B11010: string; a: number; bin2: number; b: number; 0B11111111111111111111111111111111111111111111111101001010100000010111110001111111111: boolean; }
|
||||
>"0B11010" : "0B11010"
|
||||
|
||||
@@ -149,7 +149,7 @@ obj2["9.671406556917009e+24"]; // boolean
|
||||
>"9.671406556917009e+24" : "9.671406556917009e+24"
|
||||
|
||||
obj2["Infinity"]; // any
|
||||
>obj2["Infinity"] : any
|
||||
>obj2["Infinity"] : error
|
||||
>obj2 : { 0B11010: string; a: number; bin2: number; b: number; 0B11111111111111111111111111111111111111111111111101001010100000010111110001111111111: boolean; }
|
||||
>"Infinity" : "Infinity"
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ obj1["26"]; // string
|
||||
>"26" : "26"
|
||||
|
||||
obj1["0b11010"]; // any
|
||||
>obj1["0b11010"] : any
|
||||
>obj1["0b11010"] : error
|
||||
>obj1 : { 0b11010: string; a: number; bin1: number; b: number; 0B111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111101001010100000010111110001111111111: boolean; }
|
||||
>"0b11010" : "0b11010"
|
||||
|
||||
@@ -119,7 +119,7 @@ obj2["26"]; // string
|
||||
>"26" : "26"
|
||||
|
||||
obj2["0B11010"]; // any
|
||||
>obj2["0B11010"] : any
|
||||
>obj2["0B11010"] : error
|
||||
>obj2 : { 0B11010: string; a: number; bin2: number; b: number; 0B11111111111111111111111111111111111111111111111101001010100000010111110001111111111: boolean; }
|
||||
>"0B11010" : "0B11010"
|
||||
|
||||
@@ -149,7 +149,7 @@ obj2["9.671406556917009e+24"]; // boolean
|
||||
>"9.671406556917009e+24" : "9.671406556917009e+24"
|
||||
|
||||
obj2["Infinity"]; // any
|
||||
>obj2["Infinity"] : any
|
||||
>obj2["Infinity"] : error
|
||||
>obj2 : { 0B11010: string; a: number; bin2: number; b: number; 0B11111111111111111111111111111111111111111111111101001010100000010111110001111111111: boolean; }
|
||||
>"Infinity" : "Infinity"
|
||||
|
||||
|
||||
@@ -111,6 +111,16 @@ for (const y = 0; y < 1;) {
|
||||
const x = 1;
|
||||
(function() { return x + y});
|
||||
(() => x + y);
|
||||
}
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/20594
|
||||
declare const sobj: { [x: string]: any };
|
||||
for (let sx in sobj) {
|
||||
(() => sobj[sx]);
|
||||
}
|
||||
declare const iobj: { [x: number]: any };
|
||||
for (let ix in iobj) {
|
||||
(() => iobj[ix]);
|
||||
}
|
||||
|
||||
//// [capturedLetConstInLoop1.js]
|
||||
@@ -270,3 +280,15 @@ var _loop_20 = function (y) {
|
||||
for (var y = 0; y < 1;) {
|
||||
_loop_20(y);
|
||||
}
|
||||
var _loop_21 = function (sx) {
|
||||
(function () { return sobj[sx]; });
|
||||
};
|
||||
for (var sx in sobj) {
|
||||
_loop_21(sx);
|
||||
}
|
||||
var _loop_22 = function (ix) {
|
||||
(function () { return iobj[ix]; });
|
||||
};
|
||||
for (var ix in iobj) {
|
||||
_loop_22(ix);
|
||||
}
|
||||
|
||||
@@ -258,3 +258,29 @@ for (const y = 0; y < 1;) {
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 109, 9))
|
||||
>y : Symbol(y, Decl(capturedLetConstInLoop1.ts, 108, 10))
|
||||
}
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/20594
|
||||
declare const sobj: { [x: string]: any };
|
||||
>sobj : Symbol(sobj, Decl(capturedLetConstInLoop1.ts, 115, 13))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 115, 23))
|
||||
|
||||
for (let sx in sobj) {
|
||||
>sx : Symbol(sx, Decl(capturedLetConstInLoop1.ts, 116, 8))
|
||||
>sobj : Symbol(sobj, Decl(capturedLetConstInLoop1.ts, 115, 13))
|
||||
|
||||
(() => sobj[sx]);
|
||||
>sobj : Symbol(sobj, Decl(capturedLetConstInLoop1.ts, 115, 13))
|
||||
>sx : Symbol(sx, Decl(capturedLetConstInLoop1.ts, 116, 8))
|
||||
}
|
||||
declare const iobj: { [x: number]: any };
|
||||
>iobj : Symbol(iobj, Decl(capturedLetConstInLoop1.ts, 119, 13))
|
||||
>x : Symbol(x, Decl(capturedLetConstInLoop1.ts, 119, 23))
|
||||
|
||||
for (let ix in iobj) {
|
||||
>ix : Symbol(ix, Decl(capturedLetConstInLoop1.ts, 120, 8))
|
||||
>iobj : Symbol(iobj, Decl(capturedLetConstInLoop1.ts, 119, 13))
|
||||
|
||||
(() => iobj[ix]);
|
||||
>iobj : Symbol(iobj, Decl(capturedLetConstInLoop1.ts, 119, 13))
|
||||
>ix : Symbol(ix, Decl(capturedLetConstInLoop1.ts, 120, 8))
|
||||
}
|
||||
|
||||
@@ -426,3 +426,35 @@ for (const y = 0; y < 1;) {
|
||||
>x : 1
|
||||
>y : 0
|
||||
}
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/20594
|
||||
declare const sobj: { [x: string]: any };
|
||||
>sobj : { [x: string]: any; }
|
||||
>x : string
|
||||
|
||||
for (let sx in sobj) {
|
||||
>sx : string
|
||||
>sobj : { [x: string]: any; }
|
||||
|
||||
(() => sobj[sx]);
|
||||
>(() => sobj[sx]) : () => any
|
||||
>() => sobj[sx] : () => any
|
||||
>sobj[sx] : any
|
||||
>sobj : { [x: string]: any; }
|
||||
>sx : string
|
||||
}
|
||||
declare const iobj: { [x: number]: any };
|
||||
>iobj : { [x: number]: any; }
|
||||
>x : number
|
||||
|
||||
for (let ix in iobj) {
|
||||
>ix : string
|
||||
>iobj : { [x: number]: any; }
|
||||
|
||||
(() => iobj[ix]);
|
||||
>(() => iobj[ix]) : () => any
|
||||
>() => iobj[ix] : () => any
|
||||
>iobj[ix] : any
|
||||
>iobj : { [x: number]: any; }
|
||||
>ix : string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
//// [circularlySimplifyingConditionalTypesNoCrash.ts]
|
||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
|
||||
type Shared< // Circularly self constraining type, defered thanks to mapping
|
||||
InjectedProps,
|
||||
DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
|
||||
> = {
|
||||
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
|
||||
};
|
||||
|
||||
interface ComponentClass<P> {
|
||||
defaultProps?: Partial<P>; // Inference target is also mapped _and_ optional
|
||||
}
|
||||
|
||||
interface InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> {
|
||||
<P extends Shared<TInjectedProps, P>>(
|
||||
component: ComponentClass<P>
|
||||
): ComponentClass<Omit<P, keyof Shared<TInjectedProps, P>> & TNeedsProps> & { WrappedComponent: ComponentClass<P> }
|
||||
} // Then intersected with and indexed via Omit and &
|
||||
|
||||
interface Connect { // Then strictly compared with another signature in its context
|
||||
<TStateProps, TOwnProps>(
|
||||
mapStateToProps: unknown,
|
||||
): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>;
|
||||
|
||||
<TDispatchProps, TOwnProps>(
|
||||
mapStateToProps: null | undefined,
|
||||
mapDispatchToProps: unknown,
|
||||
mergeProps: null | undefined,
|
||||
options: unknown
|
||||
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
|
||||
}
|
||||
|
||||
declare var connect: Connect;
|
||||
|
||||
const myStoreConnect: Connect = function(
|
||||
mapStateToProps?: any,
|
||||
mapDispatchToProps?: any,
|
||||
mergeProps?: any,
|
||||
options: unknown = {},
|
||||
) {
|
||||
return connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
mergeProps,
|
||||
options,
|
||||
);
|
||||
};
|
||||
|
||||
//// [circularlySimplifyingConditionalTypesNoCrash.js]
|
||||
"use strict";
|
||||
var myStoreConnect = function (mapStateToProps, mapDispatchToProps, mergeProps, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
return connect(mapStateToProps, mapDispatchToProps, mergeProps, options);
|
||||
};
|
||||
@@ -0,0 +1,154 @@
|
||||
=== tests/cases/compiler/circularlySimplifyingConditionalTypesNoCrash.ts ===
|
||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
>Omit : Symbol(Omit, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
|
||||
>K : Symbol(K, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 12))
|
||||
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
|
||||
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
|
||||
>K : Symbol(K, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 12))
|
||||
|
||||
type Shared< // Circularly self constraining type, defered thanks to mapping
|
||||
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
|
||||
|
||||
InjectedProps,
|
||||
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
|
||||
|
||||
DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
|
||||
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
|
||||
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
|
||||
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
|
||||
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
|
||||
|
||||
> = {
|
||||
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
|
||||
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
|
||||
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
|
||||
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
|
||||
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
|
||||
|
||||
};
|
||||
|
||||
interface ComponentClass<P> {
|
||||
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 9, 25))
|
||||
|
||||
defaultProps?: Partial<P>; // Inference target is also mapped _and_ optional
|
||||
>defaultProps : Symbol(ComponentClass.defaultProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 9, 29))
|
||||
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 9, 25))
|
||||
}
|
||||
|
||||
interface InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> {
|
||||
>InferableComponentEnhancerWithProps : Symbol(InferableComponentEnhancerWithProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 11, 1))
|
||||
>TInjectedProps : Symbol(TInjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 46))
|
||||
>TNeedsProps : Symbol(TNeedsProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 61))
|
||||
|
||||
<P extends Shared<TInjectedProps, P>>(
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
|
||||
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
|
||||
>TInjectedProps : Symbol(TInjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 46))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
|
||||
|
||||
component: ComponentClass<P>
|
||||
>component : Symbol(component, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 42))
|
||||
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
|
||||
|
||||
): ComponentClass<Omit<P, keyof Shared<TInjectedProps, P>> & TNeedsProps> & { WrappedComponent: ComponentClass<P> }
|
||||
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
|
||||
>Omit : Symbol(Omit, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 0))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
|
||||
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
|
||||
>TInjectedProps : Symbol(TInjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 46))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
|
||||
>TNeedsProps : Symbol(TNeedsProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 61))
|
||||
>WrappedComponent : Symbol(WrappedComponent, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 16, 81))
|
||||
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
|
||||
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
|
||||
|
||||
} // Then intersected with and indexed via Omit and &
|
||||
|
||||
interface Connect { // Then strictly compared with another signature in its context
|
||||
>Connect : Symbol(Connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 17, 1))
|
||||
|
||||
<TStateProps, TOwnProps>(
|
||||
>TStateProps : Symbol(TStateProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 5))
|
||||
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 17))
|
||||
|
||||
mapStateToProps: unknown,
|
||||
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 29))
|
||||
|
||||
): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>;
|
||||
>InferableComponentEnhancerWithProps : Symbol(InferableComponentEnhancerWithProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 11, 1))
|
||||
>TStateProps : Symbol(TStateProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 5))
|
||||
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 17))
|
||||
|
||||
<TDispatchProps, TOwnProps>(
|
||||
>TDispatchProps : Symbol(TDispatchProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 5))
|
||||
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 20))
|
||||
|
||||
mapStateToProps: null | undefined,
|
||||
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 32))
|
||||
|
||||
mapDispatchToProps: unknown,
|
||||
>mapDispatchToProps : Symbol(mapDispatchToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 25, 42))
|
||||
|
||||
mergeProps: null | undefined,
|
||||
>mergeProps : Symbol(mergeProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 26, 36))
|
||||
|
||||
options: unknown
|
||||
>options : Symbol(options, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 27, 37))
|
||||
|
||||
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
|
||||
>InferableComponentEnhancerWithProps : Symbol(InferableComponentEnhancerWithProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 11, 1))
|
||||
>TDispatchProps : Symbol(TDispatchProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 5))
|
||||
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 20))
|
||||
}
|
||||
|
||||
declare var connect: Connect;
|
||||
>connect : Symbol(connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 32, 11))
|
||||
>Connect : Symbol(Connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 17, 1))
|
||||
|
||||
const myStoreConnect: Connect = function(
|
||||
>myStoreConnect : Symbol(myStoreConnect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 34, 5))
|
||||
>Connect : Symbol(Connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 17, 1))
|
||||
|
||||
mapStateToProps?: any,
|
||||
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 34, 41))
|
||||
|
||||
mapDispatchToProps?: any,
|
||||
>mapDispatchToProps : Symbol(mapDispatchToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 35, 26))
|
||||
|
||||
mergeProps?: any,
|
||||
>mergeProps : Symbol(mergeProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 36, 29))
|
||||
|
||||
options: unknown = {},
|
||||
>options : Symbol(options, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 37, 21))
|
||||
|
||||
) {
|
||||
return connect(
|
||||
>connect : Symbol(connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 32, 11))
|
||||
|
||||
mapStateToProps,
|
||||
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 34, 41))
|
||||
|
||||
mapDispatchToProps,
|
||||
>mapDispatchToProps : Symbol(mapDispatchToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 35, 26))
|
||||
|
||||
mergeProps,
|
||||
>mergeProps : Symbol(mergeProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 36, 29))
|
||||
|
||||
options,
|
||||
>options : Symbol(options, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 37, 21))
|
||||
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
=== tests/cases/compiler/circularlySimplifyingConditionalTypesNoCrash.ts ===
|
||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
>Omit : Pick<T, Exclude<keyof T, K>>
|
||||
|
||||
type Shared< // Circularly self constraining type, defered thanks to mapping
|
||||
>Shared : Shared<InjectedProps, DecorationTargetProps>
|
||||
|
||||
InjectedProps,
|
||||
DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
|
||||
> = {
|
||||
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
|
||||
};
|
||||
|
||||
interface ComponentClass<P> {
|
||||
defaultProps?: Partial<P>; // Inference target is also mapped _and_ optional
|
||||
>defaultProps : Partial<P> | undefined
|
||||
}
|
||||
|
||||
interface InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> {
|
||||
<P extends Shared<TInjectedProps, P>>(
|
||||
component: ComponentClass<P>
|
||||
>component : ComponentClass<P>
|
||||
|
||||
): ComponentClass<Omit<P, keyof Shared<TInjectedProps, P>> & TNeedsProps> & { WrappedComponent: ComponentClass<P> }
|
||||
>WrappedComponent : ComponentClass<P>
|
||||
|
||||
} // Then intersected with and indexed via Omit and &
|
||||
|
||||
interface Connect { // Then strictly compared with another signature in its context
|
||||
<TStateProps, TOwnProps>(
|
||||
mapStateToProps: unknown,
|
||||
>mapStateToProps : unknown
|
||||
|
||||
): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>;
|
||||
|
||||
<TDispatchProps, TOwnProps>(
|
||||
mapStateToProps: null | undefined,
|
||||
>mapStateToProps : null | undefined
|
||||
>null : null
|
||||
|
||||
mapDispatchToProps: unknown,
|
||||
>mapDispatchToProps : unknown
|
||||
|
||||
mergeProps: null | undefined,
|
||||
>mergeProps : null | undefined
|
||||
>null : null
|
||||
|
||||
options: unknown
|
||||
>options : unknown
|
||||
|
||||
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
|
||||
}
|
||||
|
||||
declare var connect: Connect;
|
||||
>connect : Connect
|
||||
|
||||
const myStoreConnect: Connect = function(
|
||||
>myStoreConnect : Connect
|
||||
>function( mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options: unknown = {},) { return connect( mapStateToProps, mapDispatchToProps, mergeProps, options, );} : (mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options?: unknown) => InferableComponentEnhancerWithProps<{}, {}>
|
||||
|
||||
mapStateToProps?: any,
|
||||
>mapStateToProps : any
|
||||
|
||||
mapDispatchToProps?: any,
|
||||
>mapDispatchToProps : any
|
||||
|
||||
mergeProps?: any,
|
||||
>mergeProps : any
|
||||
|
||||
options: unknown = {},
|
||||
>options : unknown
|
||||
>{} : {}
|
||||
|
||||
) {
|
||||
return connect(
|
||||
>connect( mapStateToProps, mapDispatchToProps, mergeProps, options, ) : InferableComponentEnhancerWithProps<{}, {}>
|
||||
>connect : Connect
|
||||
|
||||
mapStateToProps,
|
||||
>mapStateToProps : any
|
||||
|
||||
mapDispatchToProps,
|
||||
>mapDispatchToProps : any
|
||||
|
||||
mergeProps,
|
||||
>mergeProps : any
|
||||
|
||||
options,
|
||||
>options : unknown
|
||||
|
||||
);
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(8,5): error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'Something<A>'.
|
||||
Type '{ test: string; arg: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'.
|
||||
tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,33): error TS2322: Type 'A' is not assignable to type 'Something<A>["arr"]'.
|
||||
Type 'object' is not assignable to type 'Something<A>["arr"]'.
|
||||
tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,33): error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'Something<A>'.
|
||||
Object literal may only specify known properties, and 'arr' does not exist in type 'Something<A>'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts (2 errors) ====
|
||||
@@ -17,8 +17,8 @@ tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,
|
||||
!!! error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'Something<A>'.
|
||||
!!! error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'.
|
||||
sa = { test: 'bye', arg: a, arr: a } // excess
|
||||
~~~
|
||||
!!! error TS2322: Type 'A' is not assignable to type 'Something<A>["arr"]'.
|
||||
!!! error TS2322: Type 'object' is not assignable to type 'Something<A>["arr"]'.
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'Something<A>'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'arr' does not exist in type 'Something<A>'.
|
||||
}
|
||||
|
||||
@@ -184,4 +184,24 @@ tests/cases/compiler/controlFlowSelfReferentialLoop.ts(17,29): error TS7006: Par
|
||||
b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
|
||||
}
|
||||
}
|
||||
export default md5;
|
||||
export default md5;
|
||||
|
||||
// Repro from #26655
|
||||
|
||||
interface DataShape {
|
||||
message: { id: string }
|
||||
}
|
||||
|
||||
function getObject(id: string | number) {
|
||||
return {} as any
|
||||
}
|
||||
|
||||
;(() => {
|
||||
let id: string | number = 'a'
|
||||
while (1) {
|
||||
const data = getObject(id) as DataShape
|
||||
const message = data.message
|
||||
id = message.id
|
||||
}
|
||||
})()
|
||||
|
||||
@@ -98,7 +98,27 @@ function md5(string:string): void {
|
||||
b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
|
||||
}
|
||||
}
|
||||
export default md5;
|
||||
export default md5;
|
||||
|
||||
// Repro from #26655
|
||||
|
||||
interface DataShape {
|
||||
message: { id: string }
|
||||
}
|
||||
|
||||
function getObject(id: string | number) {
|
||||
return {} as any
|
||||
}
|
||||
|
||||
;(() => {
|
||||
let id: string | number = 'a'
|
||||
while (1) {
|
||||
const data = getObject(id) as DataShape
|
||||
const message = data.message
|
||||
id = message.id
|
||||
}
|
||||
})()
|
||||
|
||||
|
||||
//// [controlFlowSelfReferentialLoop.js]
|
||||
"use strict";
|
||||
@@ -204,3 +224,15 @@ function md5(string) {
|
||||
}
|
||||
}
|
||||
exports["default"] = md5;
|
||||
function getObject(id) {
|
||||
return {};
|
||||
}
|
||||
;
|
||||
(function () {
|
||||
var id = 'a';
|
||||
while (1) {
|
||||
var data = getObject(id);
|
||||
var message = data.message;
|
||||
id = message.id;
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -831,3 +831,45 @@ function md5(string:string): void {
|
||||
export default md5;
|
||||
>md5 : Symbol(md5, Decl(controlFlowSelfReferentialLoop.ts, 0, 0))
|
||||
|
||||
// Repro from #26655
|
||||
|
||||
interface DataShape {
|
||||
>DataShape : Symbol(DataShape, Decl(controlFlowSelfReferentialLoop.ts, 99, 19))
|
||||
|
||||
message: { id: string }
|
||||
>message : Symbol(DataShape.message, Decl(controlFlowSelfReferentialLoop.ts, 103, 21))
|
||||
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 104, 12))
|
||||
}
|
||||
|
||||
function getObject(id: string | number) {
|
||||
>getObject : Symbol(getObject, Decl(controlFlowSelfReferentialLoop.ts, 105, 1))
|
||||
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 107, 19))
|
||||
|
||||
return {} as any
|
||||
}
|
||||
|
||||
;(() => {
|
||||
let id: string | number = 'a'
|
||||
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 112, 5))
|
||||
|
||||
while (1) {
|
||||
const data = getObject(id) as DataShape
|
||||
>data : Symbol(data, Decl(controlFlowSelfReferentialLoop.ts, 114, 9))
|
||||
>getObject : Symbol(getObject, Decl(controlFlowSelfReferentialLoop.ts, 105, 1))
|
||||
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 112, 5))
|
||||
>DataShape : Symbol(DataShape, Decl(controlFlowSelfReferentialLoop.ts, 99, 19))
|
||||
|
||||
const message = data.message
|
||||
>message : Symbol(message, Decl(controlFlowSelfReferentialLoop.ts, 115, 9))
|
||||
>data.message : Symbol(DataShape.message, Decl(controlFlowSelfReferentialLoop.ts, 103, 21))
|
||||
>data : Symbol(data, Decl(controlFlowSelfReferentialLoop.ts, 114, 9))
|
||||
>message : Symbol(DataShape.message, Decl(controlFlowSelfReferentialLoop.ts, 103, 21))
|
||||
|
||||
id = message.id
|
||||
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 112, 5))
|
||||
>message.id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 104, 12))
|
||||
>message : Symbol(message, Decl(controlFlowSelfReferentialLoop.ts, 115, 9))
|
||||
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 104, 12))
|
||||
}
|
||||
})()
|
||||
|
||||
|
||||
@@ -1260,3 +1260,54 @@ function md5(string:string): void {
|
||||
export default md5;
|
||||
>md5 : (string: string) => void
|
||||
|
||||
// Repro from #26655
|
||||
|
||||
interface DataShape {
|
||||
message: { id: string }
|
||||
>message : { id: string; }
|
||||
>id : string
|
||||
}
|
||||
|
||||
function getObject(id: string | number) {
|
||||
>getObject : (id: string | number) => any
|
||||
>id : string | number
|
||||
|
||||
return {} as any
|
||||
>{} as any : any
|
||||
>{} : {}
|
||||
}
|
||||
|
||||
;(() => {
|
||||
>(() => { let id: string | number = 'a' while (1) { const data = getObject(id) as DataShape const message = data.message id = message.id }})() : void
|
||||
>(() => { let id: string | number = 'a' while (1) { const data = getObject(id) as DataShape const message = data.message id = message.id }}) : () => void
|
||||
>() => { let id: string | number = 'a' while (1) { const data = getObject(id) as DataShape const message = data.message id = message.id }} : () => void
|
||||
|
||||
let id: string | number = 'a'
|
||||
>id : string | number
|
||||
>'a' : "a"
|
||||
|
||||
while (1) {
|
||||
>1 : 1
|
||||
|
||||
const data = getObject(id) as DataShape
|
||||
>data : DataShape
|
||||
>getObject(id) as DataShape : DataShape
|
||||
>getObject(id) : any
|
||||
>getObject : (id: string | number) => any
|
||||
>id : string
|
||||
|
||||
const message = data.message
|
||||
>message : { id: string; }
|
||||
>data.message : { id: string; }
|
||||
>data : DataShape
|
||||
>message : { id: string; }
|
||||
|
||||
id = message.id
|
||||
>id = message.id : string
|
||||
>id : string | number
|
||||
>message.id : string
|
||||
>message : { id: string; }
|
||||
>id : string
|
||||
}
|
||||
})()
|
||||
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
=== tests/cases/compiler/foo.js ===
|
||||
// repro from #26031
|
||||
function build() {
|
||||
>build : Symbol(build, Decl(foo.js, 0, 0))
|
||||
|
||||
var arr = [];
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>arr : Symbol(arr, Decl(foo.js, 2, 7))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
=== tests/cases/compiler/foo.js ===
|
||||
// repro from #26031
|
||||
function build() {
|
||||
>build : () => void
|
||||
|
||||
var arr = [];
|
||||
>arr : any[]
|
||||
>[] : undefined[]
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
|
||||
arr[arr.length] = 'value';
|
||||
>arr[arr.length] = 'value' : "value"
|
||||
>arr[arr.length] : any
|
||||
>arr : any[]
|
||||
>arr.length : number
|
||||
>arr : any[]
|
||||
>length : number
|
||||
>'value' : "value"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@ var o = {v:"Yo2"};
|
||||
// WScript.Echo(o[0]);
|
||||
|
||||
1[0];
|
||||
>1[0] : any
|
||||
>1[0] : error
|
||||
>1 : 1
|
||||
>0 : 0
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
tests/cases/compiler/deferredLookupTypeResolution2.ts(14,13): error TS2536: Type '({ [K in Extract<keyof T, string>]: "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 Extract<keyof T, string>]: "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<Extract<keyof O, string>, 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 Extract<keyof T, string>]: "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 Extract<keyof T, string>]: "true"; } & { [key: string]: "false"; })["1"]]' cannot be used to index type '{ true: "true"; }'.
|
||||
|
||||
type DeepOK<T> = { true: 'true', otherwise: 'false' }[Juxtapose<T>];
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
tests/cases/compiler/destructureComputedProperty.ts(7,7): error TS2341: Property 'p' is private and only accessible within class 'C'.
|
||||
tests/cases/compiler/destructureComputedProperty.ts(8,7): error TS2341: Property 'p' is private and only accessible within class 'C'.
|
||||
tests/cases/compiler/destructureComputedProperty.ts(10,7): error TS2341: Property 'p' is private and only accessible within class 'C'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/destructureComputedProperty.ts (2 errors) ====
|
||||
==== tests/cases/compiler/destructureComputedProperty.ts (3 errors) ====
|
||||
declare const ab: { n: number } | { n: string };
|
||||
const nameN = "n";
|
||||
const { [nameN]: n } = ab;
|
||||
@@ -13,6 +14,8 @@ tests/cases/compiler/destructureComputedProperty.ts(10,7): error TS2341: Propert
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2341: Property 'p' is private and only accessible within class 'C'.
|
||||
const { ["p"]: p1 } = new C();
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2341: Property 'p' is private and only accessible within class 'C'.
|
||||
const { [nameP]: p2 } = new C();
|
||||
const { p: p3 } = new C();
|
||||
~~~~~~~~~
|
||||
|
||||
@@ -141,7 +141,7 @@ enum E7 {
|
||||
|
||||
A = 'foo'['foo']
|
||||
>A : E7
|
||||
>'foo'['foo'] : any
|
||||
>'foo'['foo'] : error
|
||||
>'foo' : "foo"
|
||||
>'foo' : "foo"
|
||||
}
|
||||
@@ -152,7 +152,7 @@ enum E8 {
|
||||
|
||||
B = 'foo'['foo']
|
||||
>B : E8
|
||||
>'foo'['foo'] : any
|
||||
>'foo'['foo'] : error
|
||||
>'foo' : "foo"
|
||||
>'foo' : "foo"
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ var x = _arr.map(o => MyEnumType[o.key] === enumValue); // these are not same ty
|
||||
>o => MyEnumType[o.key] === enumValue : (o: { key: string; }) => boolean
|
||||
>o : { key: string; }
|
||||
>MyEnumType[o.key] === enumValue : boolean
|
||||
>MyEnumType[o.key] : any
|
||||
>MyEnumType[o.key] : error
|
||||
>MyEnumType : typeof MyEnumType
|
||||
>o.key : string
|
||||
>o : { key: string; }
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//// [genericIndexedAccessMethodIntersectionCanBeAccessed.ts]
|
||||
type ExtendedService<T> = {
|
||||
[K in keyof T]: T[K] & {
|
||||
__$daemonMode?: string;
|
||||
__$action?: string;
|
||||
};
|
||||
};
|
||||
|
||||
type Service<T> = {
|
||||
[K in keyof T]: T[K] & {id?: string};
|
||||
};
|
||||
|
||||
export const createService = <T>(
|
||||
ServiceCtr: ExtendedService<T> & Service<T>
|
||||
) => {
|
||||
Object.keys(ServiceCtr).forEach(key => {
|
||||
const method = (ServiceCtr)[key as keyof T];
|
||||
const {__$daemonMode, __$action, id} = method;
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//// [genericIndexedAccessMethodIntersectionCanBeAccessed.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.createService = function (ServiceCtr) {
|
||||
Object.keys(ServiceCtr).forEach(function (key) {
|
||||
var method = (ServiceCtr)[key];
|
||||
var __$daemonMode = method.__$daemonMode, __$action = method.__$action, id = method.id;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
=== tests/cases/compiler/genericIndexedAccessMethodIntersectionCanBeAccessed.ts ===
|
||||
type ExtendedService<T> = {
|
||||
>ExtendedService : Symbol(ExtendedService, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 0, 21))
|
||||
|
||||
[K in keyof T]: T[K] & {
|
||||
>K : Symbol(K, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 1, 5))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 0, 21))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 0, 21))
|
||||
>K : Symbol(K, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 1, 5))
|
||||
|
||||
__$daemonMode?: string;
|
||||
>__$daemonMode : Symbol(__$daemonMode, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 1, 28))
|
||||
|
||||
__$action?: string;
|
||||
>__$action : Symbol(__$action, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 2, 31))
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
type Service<T> = {
|
||||
>Service : Symbol(Service, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 5, 2))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 7, 13))
|
||||
|
||||
[K in keyof T]: T[K] & {id?: string};
|
||||
>K : Symbol(K, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 8, 5))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 7, 13))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 7, 13))
|
||||
>K : Symbol(K, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 8, 5))
|
||||
>id : Symbol(id, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 8, 28))
|
||||
|
||||
};
|
||||
|
||||
export const createService = <T>(
|
||||
>createService : Symbol(createService, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 11, 12))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 11, 30))
|
||||
|
||||
ServiceCtr: ExtendedService<T> & Service<T>
|
||||
>ServiceCtr : Symbol(ServiceCtr, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 11, 33))
|
||||
>ExtendedService : Symbol(ExtendedService, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 11, 30))
|
||||
>Service : Symbol(Service, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 5, 2))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 11, 30))
|
||||
|
||||
) => {
|
||||
Object.keys(ServiceCtr).forEach(key => {
|
||||
>Object.keys(ServiceCtr).forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
|
||||
>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --))
|
||||
>ServiceCtr : Symbol(ServiceCtr, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 11, 33))
|
||||
>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
|
||||
>key : Symbol(key, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 14, 36))
|
||||
|
||||
const method = (ServiceCtr)[key as keyof T];
|
||||
>method : Symbol(method, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 15, 13))
|
||||
>ServiceCtr : Symbol(ServiceCtr, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 11, 33))
|
||||
>key : Symbol(key, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 14, 36))
|
||||
>T : Symbol(T, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 11, 30))
|
||||
|
||||
const {__$daemonMode, __$action, id} = method;
|
||||
>__$daemonMode : Symbol(__$daemonMode, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 16, 15))
|
||||
>__$action : Symbol(__$action, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 16, 29))
|
||||
>id : Symbol(id, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 16, 40))
|
||||
>method : Symbol(method, Decl(genericIndexedAccessMethodIntersectionCanBeAccessed.ts, 15, 13))
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
=== tests/cases/compiler/genericIndexedAccessMethodIntersectionCanBeAccessed.ts ===
|
||||
type ExtendedService<T> = {
|
||||
>ExtendedService : ExtendedService<T>
|
||||
|
||||
[K in keyof T]: T[K] & {
|
||||
__$daemonMode?: string;
|
||||
>__$daemonMode : string | undefined
|
||||
|
||||
__$action?: string;
|
||||
>__$action : string | undefined
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
type Service<T> = {
|
||||
>Service : Service<T>
|
||||
|
||||
[K in keyof T]: T[K] & {id?: string};
|
||||
>id : string | undefined
|
||||
|
||||
};
|
||||
|
||||
export const createService = <T>(
|
||||
>createService : <T>(ServiceCtr: ExtendedService<T> & Service<T>) => void
|
||||
><T>( ServiceCtr: ExtendedService<T> & Service<T>) => { Object.keys(ServiceCtr).forEach(key => { const method = (ServiceCtr)[key as keyof T]; const {__$daemonMode, __$action, id} = method; })} : <T>(ServiceCtr: ExtendedService<T> & Service<T>) => void
|
||||
|
||||
ServiceCtr: ExtendedService<T> & Service<T>
|
||||
>ServiceCtr : ExtendedService<T> & Service<T>
|
||||
|
||||
) => {
|
||||
Object.keys(ServiceCtr).forEach(key => {
|
||||
>Object.keys(ServiceCtr).forEach(key => { const method = (ServiceCtr)[key as keyof T]; const {__$daemonMode, __$action, id} = method; }) : void
|
||||
>Object.keys(ServiceCtr).forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void
|
||||
>Object.keys(ServiceCtr) : string[]
|
||||
>Object.keys : (o: {}) => string[]
|
||||
>Object : ObjectConstructor
|
||||
>keys : (o: {}) => string[]
|
||||
>ServiceCtr : ExtendedService<T> & Service<T>
|
||||
>forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void
|
||||
>key => { const method = (ServiceCtr)[key as keyof T]; const {__$daemonMode, __$action, id} = method; } : (key: string) => void
|
||||
>key : string
|
||||
|
||||
const method = (ServiceCtr)[key as keyof T];
|
||||
>method : (ExtendedService<T> & Service<T>)[keyof T]
|
||||
>(ServiceCtr)[key as keyof T] : (ExtendedService<T> & Service<T>)[keyof T]
|
||||
>(ServiceCtr) : ExtendedService<T> & Service<T>
|
||||
>ServiceCtr : ExtendedService<T> & Service<T>
|
||||
>key as keyof T : keyof T
|
||||
>key : string
|
||||
|
||||
const {__$daemonMode, __$action, id} = method;
|
||||
>__$daemonMode : string | undefined
|
||||
>__$action : string | undefined
|
||||
>id : string | undefined
|
||||
>method : (ExtendedService<T> & Service<T>)[keyof T]
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ var f = new foo();
|
||||
|
||||
f[0] = 4; // Shouldn't be allowed
|
||||
>f[0] = 4 : 4
|
||||
>f[0] : any
|
||||
>f[0] : error
|
||||
>f : foo
|
||||
>0 : 0
|
||||
>4 : 4
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
tests/cases/compiler/indexedAccessRelation.ts(16,23): error TS2345: Argument of type '{ a: T; }' is not assignable to parameter of type 'Pick<S & State<T>, "a">'.
|
||||
Types of property 'a' are incompatible.
|
||||
Type 'T' is not assignable to type 'S["a"] & T'.
|
||||
Type 'Foo' is not assignable to type 'S["a"] & T'.
|
||||
Type 'Foo' is not assignable to type 'S["a"]'.
|
||||
Type 'T' is not assignable to type 'S["a"]'.
|
||||
Type 'Foo' is not assignable to type 'S["a"]'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/indexedAccessRelation.ts (1 errors) ====
|
||||
// Repro from #14723
|
||||
|
||||
class Component<S> {
|
||||
setState<K extends keyof S>(state: Pick<S, K>) {}
|
||||
}
|
||||
|
||||
export interface State<T> {
|
||||
a?: T;
|
||||
}
|
||||
|
||||
class Foo {}
|
||||
|
||||
class Comp<T extends Foo, S> extends Component<S & State<T>>
|
||||
{
|
||||
foo(a: T) {
|
||||
this.setState({ a: a });
|
||||
~~~~~~~~
|
||||
!!! error TS2345: Argument of type '{ a: T; }' is not assignable to parameter of type 'Pick<S & State<T>, "a">'.
|
||||
!!! error TS2345: Types of property 'a' are incompatible.
|
||||
!!! error TS2345: Type 'T' is not assignable to type 'S["a"] & T'.
|
||||
!!! error TS2345: Type 'Foo' is not assignable to type 'S["a"] & T'.
|
||||
!!! error TS2345: Type 'Foo' is not assignable to type 'S["a"]'.
|
||||
!!! error TS2345: Type 'T' is not assignable to type 'S["a"]'.
|
||||
!!! error TS2345: Type 'Foo' is not assignable to type 'S["a"]'.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class Comp<T extends Foo, S> extends Component<S & State<T>>
|
||||
>a : T
|
||||
|
||||
this.setState({ a: a });
|
||||
>this.setState({ a: a }) : void
|
||||
>this.setState({ a: a }) : any
|
||||
>this.setState : <K extends keyof S | "a">(state: Pick<S & State<T>, K>) => void
|
||||
>this : this
|
||||
>setState : <K extends keyof S | "a">(state: Pick<S & State<T>, K>) => void
|
||||
|
||||
@@ -69,8 +69,8 @@ declare function genericFn3<
|
||||
|
||||
// Should be never
|
||||
const result5 = genericFn3({ g: "gtest", h: "htest" }, "g", "h"); // 'g' & 'h' will reduce to never
|
||||
>result5 : error
|
||||
>genericFn3({ g: "gtest", h: "htest" }, "g", "h") : error
|
||||
>result5 : unknown
|
||||
>genericFn3({ g: "gtest", h: "htest" }, "g", "h") : unknown
|
||||
>genericFn3 : <T extends { [K in keyof T]: T[K]; }, U extends keyof T, V extends keyof T>(obj: T, u: U, v: V) => T[U & V]
|
||||
>{ g: "gtest", h: "htest" } : { g: string; h: string; }
|
||||
>g : string
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
tests/cases/compiler/infiniteConstraints.ts(4,37): error TS2536: Type '"val"' cannot be used to index type 'B[Exclude<keyof B, K>]'.
|
||||
tests/cases/compiler/infiniteConstraints.ts(31,42): error TS2345: Argument of type '{ main: Record<"val", "dup">; alternate: Record<"val", "dup">; }' is not assignable to parameter of type '{ main: never; alternate: never; }'.
|
||||
Types of property 'main' are incompatible.
|
||||
Type 'Record<"val", "dup">' is not assignable to type 'never'.
|
||||
tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/infiniteConstraints.ts (3 errors) ====
|
||||
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
||||
|
||||
type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
|
||||
type T2<B extends { [K in keyof B]: B[Exclude<keyof B, K>]["val"] }> = B;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2536: Type '"val"' cannot be used to index type 'B[Exclude<keyof B, K>]'.
|
||||
|
||||
// Repros from #22950
|
||||
|
||||
type AProp<T extends { a: string }> = T
|
||||
|
||||
declare function myBug<
|
||||
T extends { [K in keyof T]: T[K] extends AProp<infer U> ? U : never }
|
||||
>(arg: T): T
|
||||
|
||||
const out = myBug({obj1: {a: "test"}})
|
||||
|
||||
type Value<V extends string = string> = Record<"val", V>;
|
||||
declare function value<V extends string>(val: V): Value<V>;
|
||||
|
||||
declare function ensureNoDuplicates<
|
||||
T extends {
|
||||
[K in keyof T]: Extract<T[K], Value>["val"] extends Extract<T[Exclude<keyof T, K>], Value>["val"]
|
||||
? never
|
||||
: any
|
||||
}
|
||||
>(vals: T): void;
|
||||
|
||||
const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2")});
|
||||
|
||||
const shouldBeNoError = ensureNoDuplicates({main: value("test")});
|
||||
|
||||
const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("dup")});
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '{ main: Record<"val", "dup">; alternate: Record<"val", "dup">; }' is not assignable to parameter of type '{ main: never; alternate: never; }'.
|
||||
!!! error TS2345: Types of property 'main' are incompatible.
|
||||
!!! error TS2345: Type 'Record<"val", "dup">' is not assignable to type 'never'.
|
||||
|
||||
// Repro from #26448
|
||||
|
||||
type Cond<T> = T extends number ? number : never;
|
||||
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
//// [infiniteConstraints.ts]
|
||||
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
||||
|
||||
type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
|
||||
type T2<B extends { [K in keyof B]: B[Exclude<keyof B, K>]["val"] }> = B;
|
||||
|
||||
// Repros from #22950
|
||||
|
||||
type AProp<T extends { a: string }> = T
|
||||
|
||||
declare function myBug<
|
||||
T extends { [K in keyof T]: T[K] extends AProp<infer U> ? U : never }
|
||||
>(arg: T): T
|
||||
|
||||
const out = myBug({obj1: {a: "test"}})
|
||||
|
||||
type Value<V extends string = string> = Record<"val", V>;
|
||||
declare function value<V extends string>(val: V): Value<V>;
|
||||
|
||||
declare function ensureNoDuplicates<
|
||||
T extends {
|
||||
[K in keyof T]: Extract<T[K], Value>["val"] extends Extract<T[Exclude<keyof T, K>], Value>["val"]
|
||||
? never
|
||||
: any
|
||||
}
|
||||
>(vals: T): void;
|
||||
|
||||
const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2")});
|
||||
|
||||
const shouldBeNoError = ensureNoDuplicates({main: value("test")});
|
||||
|
||||
const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("dup")});
|
||||
|
||||
// Repro from #26448
|
||||
|
||||
type Cond<T> = T extends number ? number : never;
|
||||
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
||||
|
||||
|
||||
//// [infiniteConstraints.js]
|
||||
"use strict";
|
||||
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
||||
var out = myBug({ obj1: { a: "test" } });
|
||||
var noError = ensureNoDuplicates({ main: value("test"), alternate: value("test2") });
|
||||
var shouldBeNoError = ensureNoDuplicates({ main: value("test") });
|
||||
var shouldBeError = ensureNoDuplicates({ main: value("dup"), alternate: value("dup") });
|
||||
@@ -0,0 +1,140 @@
|
||||
=== tests/cases/compiler/infiniteConstraints.ts ===
|
||||
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
||||
|
||||
type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
|
||||
>T1 : Symbol(T1, Decl(infiniteConstraints.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 2, 8))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 2, 21))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 2, 8))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 2, 8))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 2, 8))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 2, 21))
|
||||
>val : Symbol(val, Decl(infiniteConstraints.ts, 2, 69))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 2, 8))
|
||||
|
||||
type T2<B extends { [K in keyof B]: B[Exclude<keyof B, K>]["val"] }> = B;
|
||||
>T2 : Symbol(T2, Decl(infiniteConstraints.ts, 2, 99))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 3, 8))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 3, 21))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 3, 8))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 3, 8))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 3, 8))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 3, 21))
|
||||
>B : Symbol(B, Decl(infiniteConstraints.ts, 3, 8))
|
||||
|
||||
// Repros from #22950
|
||||
|
||||
type AProp<T extends { a: string }> = T
|
||||
>AProp : Symbol(AProp, Decl(infiniteConstraints.ts, 3, 73))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 7, 11))
|
||||
>a : Symbol(a, Decl(infiniteConstraints.ts, 7, 22))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 7, 11))
|
||||
|
||||
declare function myBug<
|
||||
>myBug : Symbol(myBug, Decl(infiniteConstraints.ts, 7, 39))
|
||||
|
||||
T extends { [K in keyof T]: T[K] extends AProp<infer U> ? U : never }
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 9, 23))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 10, 15))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 9, 23))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 9, 23))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 10, 15))
|
||||
>AProp : Symbol(AProp, Decl(infiniteConstraints.ts, 3, 73))
|
||||
>U : Symbol(U, Decl(infiniteConstraints.ts, 10, 54))
|
||||
>U : Symbol(U, Decl(infiniteConstraints.ts, 10, 54))
|
||||
|
||||
>(arg: T): T
|
||||
>arg : Symbol(arg, Decl(infiniteConstraints.ts, 11, 2))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 9, 23))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 9, 23))
|
||||
|
||||
const out = myBug({obj1: {a: "test"}})
|
||||
>out : Symbol(out, Decl(infiniteConstraints.ts, 13, 5))
|
||||
>myBug : Symbol(myBug, Decl(infiniteConstraints.ts, 7, 39))
|
||||
>obj1 : Symbol(obj1, Decl(infiniteConstraints.ts, 13, 19))
|
||||
>a : Symbol(a, Decl(infiniteConstraints.ts, 13, 26))
|
||||
|
||||
type Value<V extends string = string> = Record<"val", V>;
|
||||
>Value : Symbol(Value, Decl(infiniteConstraints.ts, 13, 38))
|
||||
>V : Symbol(V, Decl(infiniteConstraints.ts, 15, 11))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
>V : Symbol(V, Decl(infiniteConstraints.ts, 15, 11))
|
||||
|
||||
declare function value<V extends string>(val: V): Value<V>;
|
||||
>value : Symbol(value, Decl(infiniteConstraints.ts, 15, 57))
|
||||
>V : Symbol(V, Decl(infiniteConstraints.ts, 16, 23))
|
||||
>val : Symbol(val, Decl(infiniteConstraints.ts, 16, 41))
|
||||
>V : Symbol(V, Decl(infiniteConstraints.ts, 16, 23))
|
||||
>Value : Symbol(Value, Decl(infiniteConstraints.ts, 13, 38))
|
||||
>V : Symbol(V, Decl(infiniteConstraints.ts, 16, 23))
|
||||
|
||||
declare function ensureNoDuplicates<
|
||||
>ensureNoDuplicates : Symbol(ensureNoDuplicates, Decl(infiniteConstraints.ts, 16, 59))
|
||||
|
||||
T extends {
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 18, 36))
|
||||
|
||||
[K in keyof T]: Extract<T[K], Value>["val"] extends Extract<T[Exclude<keyof T, K>], Value>["val"]
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 20, 5))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 18, 36))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 18, 36))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 20, 5))
|
||||
>Value : Symbol(Value, Decl(infiniteConstraints.ts, 13, 38))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 18, 36))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 18, 36))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 20, 5))
|
||||
>Value : Symbol(Value, Decl(infiniteConstraints.ts, 13, 38))
|
||||
|
||||
? never
|
||||
: any
|
||||
}
|
||||
>(vals: T): void;
|
||||
>vals : Symbol(vals, Decl(infiniteConstraints.ts, 24, 2))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 18, 36))
|
||||
|
||||
const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2")});
|
||||
>noError : Symbol(noError, Decl(infiniteConstraints.ts, 26, 5))
|
||||
>ensureNoDuplicates : Symbol(ensureNoDuplicates, Decl(infiniteConstraints.ts, 16, 59))
|
||||
>main : Symbol(main, Decl(infiniteConstraints.ts, 26, 36))
|
||||
>value : Symbol(value, Decl(infiniteConstraints.ts, 15, 57))
|
||||
>alternate : Symbol(alternate, Decl(infiniteConstraints.ts, 26, 56))
|
||||
>value : Symbol(value, Decl(infiniteConstraints.ts, 15, 57))
|
||||
|
||||
const shouldBeNoError = ensureNoDuplicates({main: value("test")});
|
||||
>shouldBeNoError : Symbol(shouldBeNoError, Decl(infiniteConstraints.ts, 28, 5))
|
||||
>ensureNoDuplicates : Symbol(ensureNoDuplicates, Decl(infiniteConstraints.ts, 16, 59))
|
||||
>main : Symbol(main, Decl(infiniteConstraints.ts, 28, 44))
|
||||
>value : Symbol(value, Decl(infiniteConstraints.ts, 15, 57))
|
||||
|
||||
const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("dup")});
|
||||
>shouldBeError : Symbol(shouldBeError, Decl(infiniteConstraints.ts, 30, 5))
|
||||
>ensureNoDuplicates : Symbol(ensureNoDuplicates, Decl(infiniteConstraints.ts, 16, 59))
|
||||
>main : Symbol(main, Decl(infiniteConstraints.ts, 30, 42))
|
||||
>value : Symbol(value, Decl(infiniteConstraints.ts, 15, 57))
|
||||
>alternate : Symbol(alternate, Decl(infiniteConstraints.ts, 30, 61))
|
||||
>value : Symbol(value, Decl(infiniteConstraints.ts, 15, 57))
|
||||
|
||||
// Repro from #26448
|
||||
|
||||
type Cond<T> = T extends number ? number : never;
|
||||
>Cond : Symbol(Cond, Decl(infiniteConstraints.ts, 30, 88))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 34, 10))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 34, 10))
|
||||
|
||||
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
||||
>function1 : Symbol(function1, Decl(infiniteConstraints.ts, 34, 49))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 35, 27))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 35, 39))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 35, 27))
|
||||
>Cond : Symbol(Cond, Decl(infiniteConstraints.ts, 30, 88))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 35, 27))
|
||||
>K : Symbol(K, Decl(infiniteConstraints.ts, 35, 39))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 35, 27))
|
||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 35, 27))
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
=== tests/cases/compiler/infiniteConstraints.ts ===
|
||||
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
||||
|
||||
type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
|
||||
>T1 : B
|
||||
>val : string
|
||||
|
||||
type T2<B extends { [K in keyof B]: B[Exclude<keyof B, K>]["val"] }> = B;
|
||||
>T2 : B
|
||||
|
||||
// Repros from #22950
|
||||
|
||||
type AProp<T extends { a: string }> = T
|
||||
>AProp : T
|
||||
>a : string
|
||||
|
||||
declare function myBug<
|
||||
>myBug : <T extends { [K in keyof T]: T[K]; }>(arg: T) => T
|
||||
|
||||
T extends { [K in keyof T]: T[K] extends AProp<infer U> ? U : never }
|
||||
>(arg: T): T
|
||||
>arg : T
|
||||
|
||||
const out = myBug({obj1: {a: "test"}})
|
||||
>out : { obj1: { a: string; }; }
|
||||
>myBug({obj1: {a: "test"}}) : { obj1: { a: string; }; }
|
||||
>myBug : <T extends { [K in keyof T]: T[K]; }>(arg: T) => T
|
||||
>{obj1: {a: "test"}} : { obj1: { a: string; }; }
|
||||
>obj1 : { a: string; }
|
||||
>{a: "test"} : { a: string; }
|
||||
>a : string
|
||||
>"test" : "test"
|
||||
|
||||
type Value<V extends string = string> = Record<"val", V>;
|
||||
>Value : Record<"val", V>
|
||||
|
||||
declare function value<V extends string>(val: V): Value<V>;
|
||||
>value : <V extends string>(val: V) => Record<"val", V>
|
||||
>val : V
|
||||
|
||||
declare function ensureNoDuplicates<
|
||||
>ensureNoDuplicates : <T extends { [K in keyof T]: Extract<T[K], Record<"val", string>>["val"] extends Extract<T[Exclude<keyof T, K>], Record<"val", string>>["val"] ? never : any; }>(vals: T) => void
|
||||
|
||||
T extends {
|
||||
[K in keyof T]: Extract<T[K], Value>["val"] extends Extract<T[Exclude<keyof T, K>], Value>["val"]
|
||||
? never
|
||||
: any
|
||||
}
|
||||
>(vals: T): void;
|
||||
>vals : T
|
||||
|
||||
const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2")});
|
||||
>noError : void
|
||||
>ensureNoDuplicates({main: value("test"), alternate: value("test2")}) : void
|
||||
>ensureNoDuplicates : <T extends { [K in keyof T]: Extract<T[K], Record<"val", string>>["val"] extends Extract<T[Exclude<keyof T, K>], Record<"val", string>>["val"] ? never : any; }>(vals: T) => void
|
||||
>{main: value("test"), alternate: value("test2")} : { main: Record<"val", "test">; alternate: Record<"val", "test2">; }
|
||||
>main : Record<"val", "test">
|
||||
>value("test") : Record<"val", "test">
|
||||
>value : <V extends string>(val: V) => Record<"val", V>
|
||||
>"test" : "test"
|
||||
>alternate : Record<"val", "test2">
|
||||
>value("test2") : Record<"val", "test2">
|
||||
>value : <V extends string>(val: V) => Record<"val", V>
|
||||
>"test2" : "test2"
|
||||
|
||||
const shouldBeNoError = ensureNoDuplicates({main: value("test")});
|
||||
>shouldBeNoError : void
|
||||
>ensureNoDuplicates({main: value("test")}) : void
|
||||
>ensureNoDuplicates : <T extends { [K in keyof T]: Extract<T[K], Record<"val", string>>["val"] extends Extract<T[Exclude<keyof T, K>], Record<"val", string>>["val"] ? never : any; }>(vals: T) => void
|
||||
>{main: value("test")} : { main: Record<"val", "test">; }
|
||||
>main : Record<"val", "test">
|
||||
>value("test") : Record<"val", "test">
|
||||
>value : <V extends string>(val: V) => Record<"val", V>
|
||||
>"test" : "test"
|
||||
|
||||
const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("dup")});
|
||||
>shouldBeError : any
|
||||
>ensureNoDuplicates({main: value("dup"), alternate: value("dup")}) : any
|
||||
>ensureNoDuplicates : <T extends { [K in keyof T]: Extract<T[K], Record<"val", string>>["val"] extends Extract<T[Exclude<keyof T, K>], Record<"val", string>>["val"] ? never : any; }>(vals: T) => void
|
||||
>{main: value("dup"), alternate: value("dup")} : { main: Record<"val", "dup">; alternate: Record<"val", "dup">; }
|
||||
>main : Record<"val", "dup">
|
||||
>value("dup") : Record<"val", "dup">
|
||||
>value : <V extends string>(val: V) => Record<"val", V>
|
||||
>"dup" : "dup"
|
||||
>alternate : Record<"val", "dup">
|
||||
>value("dup") : Record<"val", "dup">
|
||||
>value : <V extends string>(val: V) => Record<"val", V>
|
||||
>"dup" : "dup"
|
||||
|
||||
// Repro from #26448
|
||||
|
||||
type Cond<T> = T extends number ? number : never;
|
||||
>Cond : Cond<T>
|
||||
|
||||
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
||||
>function1 : <T extends { [K in keyof T]: Cond<T[K]>; }>() => T[keyof T]["foo"]
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts(8,7): error TS2559: Type 'XY' has no properties in common with type 'Z'.
|
||||
tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts(18,7): error TS2322: Type 'Brand<{ view: number; styleMedia: string; }>' is not assignable to type 'ViewStyle'.
|
||||
Property 'view' is missing in type 'Number & { __brand: { view: number; styleMedia: string; }; }'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts (2 errors) ====
|
||||
interface X { x: string }
|
||||
interface Y { y: number }
|
||||
interface Z { z?: boolean }
|
||||
|
||||
type XY = X & Y;
|
||||
const xy: XY = {x: 'x', y: 10};
|
||||
|
||||
const z1: Z = xy; // error, {xy} doesn't overlap with {z}
|
||||
~~
|
||||
!!! error TS2559: Type 'XY' has no properties in common with type 'Z'.
|
||||
|
||||
|
||||
interface ViewStyle {
|
||||
view: number
|
||||
styleMedia: string
|
||||
}
|
||||
type Brand<T> = number & { __brand: T }
|
||||
declare function create<T extends { [s: string]: ViewStyle }>(styles: T): { [P in keyof T]: Brand<T[P]> };
|
||||
const wrapped = create({ first: { view: 0, styleMedia: "???" } });
|
||||
const vs: ViewStyle = wrapped.first // error, first is a branded number
|
||||
~~
|
||||
!!! error TS2322: Type 'Brand<{ view: number; styleMedia: string; }>' is not assignable to type 'ViewStyle'.
|
||||
!!! error TS2322: Property 'view' is missing in type 'Number & { __brand: { view: number; styleMedia: string; }; }'.
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
//// [intersectionAsWeakTypeSource.ts]
|
||||
interface X { x: string }
|
||||
interface Y { y: number }
|
||||
interface Z { z?: boolean }
|
||||
|
||||
type XY = X & Y;
|
||||
const xy: XY = {x: 'x', y: 10};
|
||||
|
||||
const z1: Z = xy; // error, {xy} doesn't overlap with {z}
|
||||
|
||||
|
||||
interface ViewStyle {
|
||||
view: number
|
||||
styleMedia: string
|
||||
}
|
||||
type Brand<T> = number & { __brand: T }
|
||||
declare function create<T extends { [s: string]: ViewStyle }>(styles: T): { [P in keyof T]: Brand<T[P]> };
|
||||
const wrapped = create({ first: { view: 0, styleMedia: "???" } });
|
||||
const vs: ViewStyle = wrapped.first // error, first is a branded number
|
||||
|
||||
|
||||
//// [intersectionAsWeakTypeSource.js]
|
||||
var xy = { x: 'x', y: 10 };
|
||||
var z1 = xy; // error, {xy} doesn't overlap with {z}
|
||||
var wrapped = create({ first: { view: 0, styleMedia: "???" } });
|
||||
var vs = wrapped.first; // error, first is a branded number
|
||||
@@ -0,0 +1,72 @@
|
||||
=== tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts ===
|
||||
interface X { x: string }
|
||||
>X : Symbol(X, Decl(intersectionAsWeakTypeSource.ts, 0, 0))
|
||||
>x : Symbol(X.x, Decl(intersectionAsWeakTypeSource.ts, 0, 13))
|
||||
|
||||
interface Y { y: number }
|
||||
>Y : Symbol(Y, Decl(intersectionAsWeakTypeSource.ts, 0, 25))
|
||||
>y : Symbol(Y.y, Decl(intersectionAsWeakTypeSource.ts, 1, 13))
|
||||
|
||||
interface Z { z?: boolean }
|
||||
>Z : Symbol(Z, Decl(intersectionAsWeakTypeSource.ts, 1, 25))
|
||||
>z : Symbol(Z.z, Decl(intersectionAsWeakTypeSource.ts, 2, 13))
|
||||
|
||||
type XY = X & Y;
|
||||
>XY : Symbol(XY, Decl(intersectionAsWeakTypeSource.ts, 2, 27))
|
||||
>X : Symbol(X, Decl(intersectionAsWeakTypeSource.ts, 0, 0))
|
||||
>Y : Symbol(Y, Decl(intersectionAsWeakTypeSource.ts, 0, 25))
|
||||
|
||||
const xy: XY = {x: 'x', y: 10};
|
||||
>xy : Symbol(xy, Decl(intersectionAsWeakTypeSource.ts, 5, 5))
|
||||
>XY : Symbol(XY, Decl(intersectionAsWeakTypeSource.ts, 2, 27))
|
||||
>x : Symbol(x, Decl(intersectionAsWeakTypeSource.ts, 5, 16))
|
||||
>y : Symbol(y, Decl(intersectionAsWeakTypeSource.ts, 5, 23))
|
||||
|
||||
const z1: Z = xy; // error, {xy} doesn't overlap with {z}
|
||||
>z1 : Symbol(z1, Decl(intersectionAsWeakTypeSource.ts, 7, 5))
|
||||
>Z : Symbol(Z, Decl(intersectionAsWeakTypeSource.ts, 1, 25))
|
||||
>xy : Symbol(xy, Decl(intersectionAsWeakTypeSource.ts, 5, 5))
|
||||
|
||||
|
||||
interface ViewStyle {
|
||||
>ViewStyle : Symbol(ViewStyle, Decl(intersectionAsWeakTypeSource.ts, 7, 17))
|
||||
|
||||
view: number
|
||||
>view : Symbol(ViewStyle.view, Decl(intersectionAsWeakTypeSource.ts, 10, 21))
|
||||
|
||||
styleMedia: string
|
||||
>styleMedia : Symbol(ViewStyle.styleMedia, Decl(intersectionAsWeakTypeSource.ts, 11, 16))
|
||||
}
|
||||
type Brand<T> = number & { __brand: T }
|
||||
>Brand : Symbol(Brand, Decl(intersectionAsWeakTypeSource.ts, 13, 1))
|
||||
>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 14, 11))
|
||||
>__brand : Symbol(__brand, Decl(intersectionAsWeakTypeSource.ts, 14, 26))
|
||||
>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 14, 11))
|
||||
|
||||
declare function create<T extends { [s: string]: ViewStyle }>(styles: T): { [P in keyof T]: Brand<T[P]> };
|
||||
>create : Symbol(create, Decl(intersectionAsWeakTypeSource.ts, 14, 39))
|
||||
>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 15, 24))
|
||||
>s : Symbol(s, Decl(intersectionAsWeakTypeSource.ts, 15, 37))
|
||||
>ViewStyle : Symbol(ViewStyle, Decl(intersectionAsWeakTypeSource.ts, 7, 17))
|
||||
>styles : Symbol(styles, Decl(intersectionAsWeakTypeSource.ts, 15, 62))
|
||||
>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 15, 24))
|
||||
>P : Symbol(P, Decl(intersectionAsWeakTypeSource.ts, 15, 77))
|
||||
>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 15, 24))
|
||||
>Brand : Symbol(Brand, Decl(intersectionAsWeakTypeSource.ts, 13, 1))
|
||||
>T : Symbol(T, Decl(intersectionAsWeakTypeSource.ts, 15, 24))
|
||||
>P : Symbol(P, Decl(intersectionAsWeakTypeSource.ts, 15, 77))
|
||||
|
||||
const wrapped = create({ first: { view: 0, styleMedia: "???" } });
|
||||
>wrapped : Symbol(wrapped, Decl(intersectionAsWeakTypeSource.ts, 16, 5))
|
||||
>create : Symbol(create, Decl(intersectionAsWeakTypeSource.ts, 14, 39))
|
||||
>first : Symbol(first, Decl(intersectionAsWeakTypeSource.ts, 16, 24))
|
||||
>view : Symbol(view, Decl(intersectionAsWeakTypeSource.ts, 16, 33))
|
||||
>styleMedia : Symbol(styleMedia, Decl(intersectionAsWeakTypeSource.ts, 16, 42))
|
||||
|
||||
const vs: ViewStyle = wrapped.first // error, first is a branded number
|
||||
>vs : Symbol(vs, Decl(intersectionAsWeakTypeSource.ts, 17, 5))
|
||||
>ViewStyle : Symbol(ViewStyle, Decl(intersectionAsWeakTypeSource.ts, 7, 17))
|
||||
>wrapped.first : Symbol(first, Decl(intersectionAsWeakTypeSource.ts, 16, 24))
|
||||
>wrapped : Symbol(wrapped, Decl(intersectionAsWeakTypeSource.ts, 16, 5))
|
||||
>first : Symbol(first, Decl(intersectionAsWeakTypeSource.ts, 16, 24))
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
=== tests/cases/conformance/types/intersection/intersectionAsWeakTypeSource.ts ===
|
||||
interface X { x: string }
|
||||
>x : string
|
||||
|
||||
interface Y { y: number }
|
||||
>y : number
|
||||
|
||||
interface Z { z?: boolean }
|
||||
>z : boolean
|
||||
|
||||
type XY = X & Y;
|
||||
>XY : XY
|
||||
|
||||
const xy: XY = {x: 'x', y: 10};
|
||||
>xy : XY
|
||||
>{x: 'x', y: 10} : { x: string; y: number; }
|
||||
>x : string
|
||||
>'x' : "x"
|
||||
>y : number
|
||||
>10 : 10
|
||||
|
||||
const z1: Z = xy; // error, {xy} doesn't overlap with {z}
|
||||
>z1 : Z
|
||||
>xy : XY
|
||||
|
||||
|
||||
interface ViewStyle {
|
||||
view: number
|
||||
>view : number
|
||||
|
||||
styleMedia: string
|
||||
>styleMedia : string
|
||||
}
|
||||
type Brand<T> = number & { __brand: T }
|
||||
>Brand : Brand<T>
|
||||
>__brand : T
|
||||
|
||||
declare function create<T extends { [s: string]: ViewStyle }>(styles: T): { [P in keyof T]: Brand<T[P]> };
|
||||
>create : <T extends { [s: string]: ViewStyle; }>(styles: T) => { [P in keyof T]: Brand<T[P]>; }
|
||||
>s : string
|
||||
>styles : T
|
||||
|
||||
const wrapped = create({ first: { view: 0, styleMedia: "???" } });
|
||||
>wrapped : { first: Brand<{ view: number; styleMedia: string; }>; }
|
||||
>create({ first: { view: 0, styleMedia: "???" } }) : { first: Brand<{ view: number; styleMedia: string; }>; }
|
||||
>create : <T extends { [s: string]: ViewStyle; }>(styles: T) => { [P in keyof T]: Brand<T[P]>; }
|
||||
>{ first: { view: 0, styleMedia: "???" } } : { first: { view: number; styleMedia: string; }; }
|
||||
>first : { view: number; styleMedia: string; }
|
||||
>{ view: 0, styleMedia: "???" } : { view: number; styleMedia: string; }
|
||||
>view : number
|
||||
>0 : 0
|
||||
>styleMedia : string
|
||||
>"???" : "???"
|
||||
|
||||
const vs: ViewStyle = wrapped.first // error, first is a branded number
|
||||
>vs : ViewStyle
|
||||
>wrapped.first : Brand<{ view: number; styleMedia: string; }>
|
||||
>wrapped : { first: Brand<{ view: number; styleMedia: string; }>; }
|
||||
>first : Brand<{ view: number; styleMedia: string; }>
|
||||
|
||||
@@ -649,6 +649,20 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
|
||||
const d: Dict<T> = dd[k1];
|
||||
return d[k2];
|
||||
}
|
||||
|
||||
// Repro from #26409
|
||||
|
||||
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
|
||||
{
|
||||
const s: string = t[k];
|
||||
t.cool;
|
||||
};
|
||||
|
||||
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
|
||||
{
|
||||
const s: string = t[k];
|
||||
t.cool;
|
||||
};
|
||||
|
||||
|
||||
//// [keyofAndIndexedAccess.js]
|
||||
@@ -1078,6 +1092,15 @@ function ff2(dd, k1, k2) {
|
||||
var d = dd[k1];
|
||||
return d[k2];
|
||||
}
|
||||
// Repro from #26409
|
||||
var cf1 = function (t, k) {
|
||||
var s = t[k];
|
||||
t.cool;
|
||||
};
|
||||
var cf2 = function (t, k) {
|
||||
var s = t[k];
|
||||
t.cool;
|
||||
};
|
||||
|
||||
|
||||
//// [keyofAndIndexedAccess.d.ts]
|
||||
@@ -1413,3 +1436,7 @@ declare type DictDict<V extends string, T extends string> = {
|
||||
};
|
||||
declare function ff1<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2: T): number;
|
||||
declare function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2: T): number;
|
||||
declare const cf1: <T extends { [P in K]: string; } & {
|
||||
cool: string;
|
||||
}, K extends keyof T>(t: T, k: K) => void;
|
||||
declare const cf2: <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) => void;
|
||||
|
||||
@@ -2319,3 +2319,54 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
|
||||
>k2 : Symbol(k2, Decl(keyofAndIndexedAccess.ts, 646, 75))
|
||||
}
|
||||
|
||||
// Repro from #26409
|
||||
|
||||
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
|
||||
>cf1 : Symbol(cf1, Decl(keyofAndIndexedAccess.ts, 653, 5))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13))
|
||||
>P : Symbol(P, Decl(keyofAndIndexedAccess.ts, 653, 26))
|
||||
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65))
|
||||
>cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48))
|
||||
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13))
|
||||
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13))
|
||||
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 653, 90))
|
||||
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65))
|
||||
{
|
||||
const s: string = t[k];
|
||||
>s : Symbol(s, Decl(keyofAndIndexedAccess.ts, 655, 9))
|
||||
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85))
|
||||
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 653, 90))
|
||||
|
||||
t.cool;
|
||||
>t.cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48))
|
||||
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85))
|
||||
>cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48))
|
||||
|
||||
};
|
||||
|
||||
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
|
||||
>cf2 : Symbol(cf2, Decl(keyofAndIndexedAccess.ts, 659, 5))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13))
|
||||
>P : Symbol(P, Decl(keyofAndIndexedAccess.ts, 659, 26))
|
||||
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54))
|
||||
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13))
|
||||
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13))
|
||||
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 659, 79))
|
||||
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54))
|
||||
{
|
||||
const s: string = t[k];
|
||||
>s : Symbol(s, Decl(keyofAndIndexedAccess.ts, 661, 9))
|
||||
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74))
|
||||
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 659, 79))
|
||||
|
||||
t.cool;
|
||||
>t.cool : Symbol(cool)
|
||||
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74))
|
||||
>cool : Symbol(cool)
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -2184,3 +2184,44 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
|
||||
>k2 : T
|
||||
}
|
||||
|
||||
// Repro from #26409
|
||||
|
||||
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
|
||||
>cf1 : <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) => void
|
||||
><T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>{ const s: string = t[k]; t.cool;} : <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) => void
|
||||
>cool : string
|
||||
>t : T
|
||||
>k : K
|
||||
{
|
||||
const s: string = t[k];
|
||||
>s : string
|
||||
>t[k] : T[K]
|
||||
>t : T
|
||||
>k : K
|
||||
|
||||
t.cool;
|
||||
>t.cool : string
|
||||
>t : T
|
||||
>cool : string
|
||||
|
||||
};
|
||||
|
||||
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
|
||||
>cf2 : <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) => void
|
||||
><T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>{ const s: string = t[k]; t.cool;} : <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) => void
|
||||
>t : T
|
||||
>k : K
|
||||
{
|
||||
const s: string = t[k];
|
||||
>s : string
|
||||
>t[k] : T[K]
|
||||
>t : T
|
||||
>k : K
|
||||
|
||||
t.cool;
|
||||
>t.cool : string
|
||||
>t : T
|
||||
>cool : string
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
tests/cases/compiler/limitDeepInstantiations.ts(3,35): error TS2502: '"true"' is referenced directly or indirectly in its own type annotation.
|
||||
tests/cases/compiler/limitDeepInstantiations.ts(5,13): error TS2344: Type '"false"' does not satisfy the constraint '"true"'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/limitDeepInstantiations.ts (1 errors) ====
|
||||
==== tests/cases/compiler/limitDeepInstantiations.ts (2 errors) ====
|
||||
// Repro from #14837
|
||||
|
||||
type Foo<T extends "true", B> = { "true": Foo<T, Foo<T, B>> }[T];
|
||||
@@ -9,4 +10,6 @@ tests/cases/compiler/limitDeepInstantiations.ts(3,35): error TS2502: '"true"' is
|
||||
!!! error TS2502: '"true"' is referenced directly or indirectly in its own type annotation.
|
||||
let f1: Foo<"true", {}>;
|
||||
let f2: Foo<"false", {}>;
|
||||
~~~~~~~
|
||||
!!! error TS2344: Type '"false"' does not satisfy the constraint '"true"'.
|
||||
|
||||
@@ -9,5 +9,5 @@ let f1: Foo<"true", {}>;
|
||||
>f1 : any
|
||||
|
||||
let f2: Foo<"false", {}>;
|
||||
>f2 : any
|
||||
>f2 : unknown
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
=== tests/cases/compiler/mappedTypeNoTypeNoCrash.ts ===
|
||||
type T0<T> = ({[K in keyof T]}) extends ({[key in K]: T[K]}) ? number : never;
|
||||
>T0 : number
|
||||
>T0 : T0<T>
|
||||
|
||||
|
||||
@@ -83,6 +83,14 @@ declare function mapArray<T extends any[]>(arr: T): Mapped<T>;
|
||||
function acceptMappedArray<T extends any[]>(arr: T) {
|
||||
acceptArray(mapArray(arr));
|
||||
}
|
||||
|
||||
// Repro from #26163
|
||||
|
||||
type Unconstrained<T> = ElementType<Mapped<T>>;
|
||||
type T1 = Unconstrained<[string, number, boolean]>; // string | number | boolean
|
||||
|
||||
type Constrained<T extends any[]> = ElementType<Mapped<T>>;
|
||||
type T2 = Constrained<[string, number, boolean]>; // string | number | boolean
|
||||
|
||||
|
||||
//// [mappedTypesArraysTuples.js]
|
||||
@@ -182,3 +190,7 @@ declare type R2 = ElementType<Mapped<[string, number, boolean]>>;
|
||||
declare function acceptArray(arr: any[]): void;
|
||||
declare function mapArray<T extends any[]>(arr: T): Mapped<T>;
|
||||
declare function acceptMappedArray<T extends any[]>(arr: T): void;
|
||||
declare type Unconstrained<T> = ElementType<Mapped<T>>;
|
||||
declare type T1 = Unconstrained<[string, number, boolean]>;
|
||||
declare type Constrained<T extends any[]> = ElementType<Mapped<T>>;
|
||||
declare type T2 = Constrained<[string, number, boolean]>;
|
||||
|
||||
@@ -328,3 +328,27 @@ function acceptMappedArray<T extends any[]>(arr: T) {
|
||||
>arr : Symbol(arr, Decl(mappedTypesArraysTuples.ts, 81, 44))
|
||||
}
|
||||
|
||||
// Repro from #26163
|
||||
|
||||
type Unconstrained<T> = ElementType<Mapped<T>>;
|
||||
>Unconstrained : Symbol(Unconstrained, Decl(mappedTypesArraysTuples.ts, 83, 1))
|
||||
>T : Symbol(T, Decl(mappedTypesArraysTuples.ts, 87, 19))
|
||||
>ElementType : Symbol(ElementType, Decl(mappedTypesArraysTuples.ts, 66, 1))
|
||||
>Mapped : Symbol(Mapped, Decl(mappedTypesArraysTuples.ts, 70, 59))
|
||||
>T : Symbol(T, Decl(mappedTypesArraysTuples.ts, 87, 19))
|
||||
|
||||
type T1 = Unconstrained<[string, number, boolean]>; // string | number | boolean
|
||||
>T1 : Symbol(T1, Decl(mappedTypesArraysTuples.ts, 87, 47))
|
||||
>Unconstrained : Symbol(Unconstrained, Decl(mappedTypesArraysTuples.ts, 83, 1))
|
||||
|
||||
type Constrained<T extends any[]> = ElementType<Mapped<T>>;
|
||||
>Constrained : Symbol(Constrained, Decl(mappedTypesArraysTuples.ts, 88, 51))
|
||||
>T : Symbol(T, Decl(mappedTypesArraysTuples.ts, 90, 17))
|
||||
>ElementType : Symbol(ElementType, Decl(mappedTypesArraysTuples.ts, 66, 1))
|
||||
>Mapped : Symbol(Mapped, Decl(mappedTypesArraysTuples.ts, 70, 59))
|
||||
>T : Symbol(T, Decl(mappedTypesArraysTuples.ts, 90, 17))
|
||||
|
||||
type T2 = Constrained<[string, number, boolean]>; // string | number | boolean
|
||||
>T2 : Symbol(T2, Decl(mappedTypesArraysTuples.ts, 90, 59))
|
||||
>Constrained : Symbol(Constrained, Decl(mappedTypesArraysTuples.ts, 88, 51))
|
||||
|
||||
|
||||
@@ -241,3 +241,17 @@ function acceptMappedArray<T extends any[]>(arr: T) {
|
||||
>arr : T
|
||||
}
|
||||
|
||||
// Repro from #26163
|
||||
|
||||
type Unconstrained<T> = ElementType<Mapped<T>>;
|
||||
>Unconstrained : ElementType<Mapped<T>>
|
||||
|
||||
type T1 = Unconstrained<[string, number, boolean]>; // string | number | boolean
|
||||
>T1 : string | number | boolean
|
||||
|
||||
type Constrained<T extends any[]> = ElementType<Mapped<T>>;
|
||||
>Constrained : ElementType<Mapped<T>>
|
||||
|
||||
type T2 = Constrained<[string, number, boolean]>; // string | number | boolean
|
||||
>T2 : string | number | boolean
|
||||
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ let a = ['c', 'd'];
|
||||
|
||||
a[Symbol.isConcatSpreadable] = false;
|
||||
>a[Symbol.isConcatSpreadable] = false : false
|
||||
>a[Symbol.isConcatSpreadable] : any
|
||||
>a[Symbol.isConcatSpreadable] : error
|
||||
>a : string[]
|
||||
>Symbol.isConcatSpreadable : symbol
|
||||
>Symbol : SymbolConstructor
|
||||
|
||||
@@ -445,9 +445,9 @@ new h["a-b"]["a-b"](1, 2, ...a, "string");
|
||||
|
||||
// Element access expression with a number
|
||||
new i["a-b"][1](1, 2, "string");
|
||||
>new i["a-b"][1](1, 2, "string") : any
|
||||
>i["a-b"][1] : any
|
||||
>i["a-b"] : any
|
||||
>new i["a-b"][1](1, 2, "string") : error
|
||||
>i["a-b"][1] : error
|
||||
>i["a-b"] : error
|
||||
>i : C[][]
|
||||
>"a-b" : "a-b"
|
||||
>1 : 1
|
||||
@@ -456,9 +456,9 @@ new i["a-b"][1](1, 2, "string");
|
||||
>"string" : "string"
|
||||
|
||||
new i["a-b"][1](1, 2, ...a);
|
||||
>new i["a-b"][1](1, 2, ...a) : any
|
||||
>i["a-b"][1] : any
|
||||
>i["a-b"] : any
|
||||
>new i["a-b"][1](1, 2, ...a) : error
|
||||
>i["a-b"][1] : error
|
||||
>i["a-b"] : error
|
||||
>i : C[][]
|
||||
>"a-b" : "a-b"
|
||||
>1 : 1
|
||||
@@ -468,9 +468,9 @@ new i["a-b"][1](1, 2, ...a);
|
||||
>a : string[]
|
||||
|
||||
new i["a-b"][1](1, 2, ...a, "string");
|
||||
>new i["a-b"][1](1, 2, ...a, "string") : any
|
||||
>i["a-b"][1] : any
|
||||
>i["a-b"] : any
|
||||
>new i["a-b"][1](1, 2, ...a, "string") : error
|
||||
>i["a-b"][1] : error
|
||||
>i["a-b"] : error
|
||||
>i : C[][]
|
||||
>"a-b" : "a-b"
|
||||
>1 : 1
|
||||
|
||||
@@ -446,9 +446,9 @@ new h["a-b"]["a-b"](1, 2, ...a, "string");
|
||||
|
||||
// Element access expression with a number
|
||||
new i["a-b"][1](1, 2, "string");
|
||||
>new i["a-b"][1](1, 2, "string") : any
|
||||
>i["a-b"][1] : any
|
||||
>i["a-b"] : any
|
||||
>new i["a-b"][1](1, 2, "string") : error
|
||||
>i["a-b"][1] : error
|
||||
>i["a-b"] : error
|
||||
>i : C[][]
|
||||
>"a-b" : "a-b"
|
||||
>1 : 1
|
||||
@@ -457,9 +457,9 @@ new i["a-b"][1](1, 2, "string");
|
||||
>"string" : "string"
|
||||
|
||||
new i["a-b"][1](1, 2, ...a);
|
||||
>new i["a-b"][1](1, 2, ...a) : any
|
||||
>i["a-b"][1] : any
|
||||
>i["a-b"] : any
|
||||
>new i["a-b"][1](1, 2, ...a) : error
|
||||
>i["a-b"][1] : error
|
||||
>i["a-b"] : error
|
||||
>i : C[][]
|
||||
>"a-b" : "a-b"
|
||||
>1 : 1
|
||||
@@ -469,9 +469,9 @@ new i["a-b"][1](1, 2, ...a);
|
||||
>a : string[]
|
||||
|
||||
new i["a-b"][1](1, 2, ...a, "string");
|
||||
>new i["a-b"][1](1, 2, ...a, "string") : any
|
||||
>i["a-b"][1] : any
|
||||
>i["a-b"] : any
|
||||
>new i["a-b"][1](1, 2, ...a, "string") : error
|
||||
>i["a-b"][1] : error
|
||||
>i["a-b"] : error
|
||||
>i : C[][]
|
||||
>"a-b" : "a-b"
|
||||
>1 : 1
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
tests/cases/conformance/jsdoc/bug26693.js(1,15): error TS2304: Cannot find name 'module'.
|
||||
tests/cases/conformance/jsdoc/bug26693.js(1,21): error TS1005: '}' expected.
|
||||
tests/cases/conformance/jsdoc/bug26693.js(2,22): error TS2307: Cannot find module 'nope'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/bug26693.js (3 errors) ====
|
||||
/** @typedef {module:locale} hi */
|
||||
~~~~~~
|
||||
!!! error TS2304: Cannot find name 'module'.
|
||||
~
|
||||
!!! error TS1005: '}' expected.
|
||||
import { nope } from 'nope';
|
||||
~~~~~~
|
||||
!!! error TS2307: Cannot find module 'nope'.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
=== tests/cases/conformance/jsdoc/bug26693.js ===
|
||||
/** @typedef {module:locale} hi */
|
||||
import { nope } from 'nope';
|
||||
>nope : Symbol(nope, Decl(bug26693.js, 1, 8))
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
=== tests/cases/conformance/jsdoc/bug26693.js ===
|
||||
/** @typedef {module:locale} hi */
|
||||
import { nope } from 'nope';
|
||||
>nope : any
|
||||
|
||||
@@ -24,8 +24,8 @@ var strRepresentation2 = MyEmusEnum[MyEmusEnum.emu]
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var strRepresentation3 = MyEmusEnum["monehh"];
|
||||
>strRepresentation3 : any
|
||||
>MyEmusEnum["monehh"] : any
|
||||
>strRepresentation3 : error
|
||||
>MyEmusEnum["monehh"] : error
|
||||
>MyEmusEnum : typeof MyEmusEnum
|
||||
>"monehh" : "monehh"
|
||||
|
||||
@@ -39,15 +39,15 @@ var strRepresentation4 = MyEmusEnum["emu"];
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var x = {}["hi"];
|
||||
>x : any
|
||||
>{}["hi"] : any
|
||||
>x : error
|
||||
>{}["hi"] : error
|
||||
>{} : {}
|
||||
>"hi" : "hi"
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var y = {}[10];
|
||||
>y : any
|
||||
>{}[10] : any
|
||||
>y : error
|
||||
>{}[10] : error
|
||||
>{} : {}
|
||||
>10 : 10
|
||||
|
||||
@@ -61,8 +61,8 @@ var emptyObj = {};
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var z1 = emptyObj[hi];
|
||||
>z1 : any
|
||||
>emptyObj[hi] : any
|
||||
>z1 : error
|
||||
>emptyObj[hi] : error
|
||||
>emptyObj : {}
|
||||
>hi : any
|
||||
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
tests/cases/compiler/noUnusedLocals_writeOnly.ts(1,12): error TS6133: 'x' is declared but its value is never read.
|
||||
tests/cases/compiler/noUnusedLocals_writeOnly.ts(10,9): error TS6133: 'z' is declared but its value is never read.
|
||||
tests/cases/compiler/noUnusedLocals_writeOnly.ts(18,9): error TS6133: 'z' is declared but its value is never read.
|
||||
|
||||
|
||||
==== tests/cases/compiler/noUnusedLocals_writeOnly.ts (2 errors) ====
|
||||
function f(x = 0) {
|
||||
function f(x = 0, b = false) {
|
||||
~
|
||||
!!! error TS6133: 'x' is declared but its value is never read.
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
x++;
|
||||
x /= 2;
|
||||
([x] = [1]);
|
||||
({ x } = { x: 1 });
|
||||
({ x: x } = { x: 1 });
|
||||
({ a: [{ b: x }] } = { a: [{ b: 1 }] });
|
||||
({ x = 2 } = { x: b ? 1 : undefined });
|
||||
let used = 1;
|
||||
({ x = used } = { x: b ? 1 : undefined });
|
||||
|
||||
let y = 0;
|
||||
// This is a write access to y, but not a write-*only* access.
|
||||
@@ -19,4 +27,5 @@ tests/cases/compiler/noUnusedLocals_writeOnly.ts(10,9): error TS6133: 'z' is dec
|
||||
!!! error TS6133: 'z' is declared but its value is never read.
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
}
|
||||
function f2(_: ReadonlyArray<number>): void {}
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
//// [noUnusedLocals_writeOnly.ts]
|
||||
function f(x = 0) {
|
||||
function f(x = 0, b = false) {
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
x++;
|
||||
x /= 2;
|
||||
([x] = [1]);
|
||||
({ x } = { x: 1 });
|
||||
({ x: x } = { x: 1 });
|
||||
({ a: [{ b: x }] } = { a: [{ b: 1 }] });
|
||||
({ x = 2 } = { x: b ? 1 : undefined });
|
||||
let used = 1;
|
||||
({ x = used } = { x: b ? 1 : undefined });
|
||||
|
||||
let y = 0;
|
||||
// This is a write access to y, but not a write-*only* access.
|
||||
@@ -11,17 +19,30 @@ function f(x = 0) {
|
||||
let z = 0;
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
}
|
||||
function f2(_: ReadonlyArray<number>): void {}
|
||||
|
||||
|
||||
//// [noUnusedLocals_writeOnly.js]
|
||||
function f(x) {
|
||||
"use strict";
|
||||
function f(x, b) {
|
||||
if (x === void 0) { x = 0; }
|
||||
if (b === void 0) { b = false; }
|
||||
var _a, _b;
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
x++;
|
||||
x /= 2;
|
||||
(x = [1][0]);
|
||||
(x = { x: 1 }.x);
|
||||
(x = { x: 1 }.x);
|
||||
(x = { a: [{ b: 1 }] }.a[0].b);
|
||||
(_a = { x: b ? 1 : undefined }.x, x = _a === void 0 ? 2 : _a);
|
||||
var used = 1;
|
||||
(_b = { x: b ? 1 : undefined }.x, x = _b === void 0 ? used : _b);
|
||||
var y = 0;
|
||||
// This is a write access to y, but not a write-*only* access.
|
||||
f(y++);
|
||||
var z = 0;
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
}
|
||||
function f2(_) { }
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
=== tests/cases/compiler/noUnusedLocals_writeOnly.ts ===
|
||||
function f(x = 0) {
|
||||
function f(x = 0, b = false) {
|
||||
>f : Symbol(f, Decl(noUnusedLocals_writeOnly.ts, 0, 0))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 0, 17))
|
||||
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
|
||||
@@ -12,19 +14,58 @@ function f(x = 0) {
|
||||
x /= 2;
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
|
||||
([x] = [1]);
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
|
||||
({ x } = { x: 1 });
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 6, 6))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 6, 14))
|
||||
|
||||
({ x: x } = { x: 1 });
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 7, 6))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 7, 17))
|
||||
|
||||
({ a: [{ b: x }] } = { a: [{ b: 1 }] });
|
||||
>a : Symbol(a, Decl(noUnusedLocals_writeOnly.ts, 8, 6))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 8, 12))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
>a : Symbol(a, Decl(noUnusedLocals_writeOnly.ts, 8, 26))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 8, 32))
|
||||
|
||||
({ x = 2 } = { x: b ? 1 : undefined });
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 9, 6))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 9, 18))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 0, 17))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
let used = 1;
|
||||
>used : Symbol(used, Decl(noUnusedLocals_writeOnly.ts, 10, 7))
|
||||
|
||||
({ x = used } = { x: b ? 1 : undefined });
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 11, 6))
|
||||
>used : Symbol(used, Decl(noUnusedLocals_writeOnly.ts, 10, 7))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 11, 21))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 0, 17))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
let y = 0;
|
||||
>y : Symbol(y, Decl(noUnusedLocals_writeOnly.ts, 5, 7))
|
||||
>y : Symbol(y, Decl(noUnusedLocals_writeOnly.ts, 13, 7))
|
||||
|
||||
// This is a write access to y, but not a write-*only* access.
|
||||
f(y++);
|
||||
>f : Symbol(f, Decl(noUnusedLocals_writeOnly.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(noUnusedLocals_writeOnly.ts, 5, 7))
|
||||
>y : Symbol(y, Decl(noUnusedLocals_writeOnly.ts, 13, 7))
|
||||
|
||||
let z = 0;
|
||||
>z : Symbol(z, Decl(noUnusedLocals_writeOnly.ts, 9, 7))
|
||||
>z : Symbol(z, Decl(noUnusedLocals_writeOnly.ts, 17, 7))
|
||||
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
>f : Symbol(f, Decl(noUnusedLocals_writeOnly.ts, 0, 0))
|
||||
>z : Symbol(z, Decl(noUnusedLocals_writeOnly.ts, 9, 7))
|
||||
>z : Symbol(z, Decl(noUnusedLocals_writeOnly.ts, 17, 7))
|
||||
}
|
||||
function f2(_: ReadonlyArray<number>): void {}
|
||||
>f2 : Symbol(f2, Decl(noUnusedLocals_writeOnly.ts, 19, 1))
|
||||
>_ : Symbol(_, Decl(noUnusedLocals_writeOnly.ts, 20, 12))
|
||||
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user