Implement 'unknown' type in checker
This commit is contained in:
parent
d225065cf4
commit
2003b2a3e2
1 changed files with 34 additions and 20 deletions
|
@ -354,6 +354,7 @@ namespace ts {
|
|||
const autoType = createIntrinsicType(TypeFlags.Any, "any");
|
||||
const wildcardType = createIntrinsicType(TypeFlags.Any, "any");
|
||||
const errorType = createIntrinsicType(TypeFlags.Any, "error");
|
||||
const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown");
|
||||
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
|
||||
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined");
|
||||
const nullType = createIntrinsicType(TypeFlags.Null, "null");
|
||||
|
@ -3099,6 +3100,9 @@ namespace ts {
|
|||
if (type.flags & TypeFlags.Any) {
|
||||
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.Unknown) {
|
||||
return createKeywordTypeNode(SyntaxKind.UnknownKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.String) {
|
||||
return createKeywordTypeNode(SyntaxKind.StringKeyword);
|
||||
}
|
||||
|
@ -5720,6 +5724,7 @@ namespace ts {
|
|||
function isThislessType(node: TypeNode): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.UnknownKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
|
@ -8293,7 +8298,7 @@ namespace ts {
|
|||
// easier to reason about their origin.
|
||||
if (!(flags & TypeFlags.Never || flags & TypeFlags.Intersection && isEmptyIntersectionType(<IntersectionType>type))) {
|
||||
includes |= flags & ~TypeFlags.ConstructionFlags;
|
||||
if (flags & TypeFlags.Any) {
|
||||
if (flags & TypeFlags.AnyOrUnknown) {
|
||||
if (type === wildcardType) includes |= TypeFlags.Wildcard;
|
||||
}
|
||||
else if (!strictNullChecks && flags & TypeFlags.Nullable) {
|
||||
|
@ -8404,8 +8409,8 @@ namespace ts {
|
|||
}
|
||||
const typeSet: Type[] = [];
|
||||
const includes = addTypesToUnion(typeSet, 0, types);
|
||||
if (includes & TypeFlags.Any) {
|
||||
return includes & TypeFlags.Wildcard ? wildcardType : anyType;
|
||||
if (includes & TypeFlags.AnyOrUnknown) {
|
||||
return includes & TypeFlags.Any ? includes & TypeFlags.Wildcard ? wildcardType : anyType : unknownType;
|
||||
}
|
||||
switch (unionReduction) {
|
||||
case UnionReduction.Literal:
|
||||
|
@ -8508,7 +8513,7 @@ namespace ts {
|
|||
}
|
||||
else {
|
||||
includes |= flags & ~TypeFlags.ConstructionFlags;
|
||||
if (flags & TypeFlags.Any) {
|
||||
if (flags & TypeFlags.AnyOrUnknown) {
|
||||
if (type === wildcardType) includes |= TypeFlags.Wildcard;
|
||||
}
|
||||
else if ((strictNullChecks || !(flags & TypeFlags.Nullable)) && !contains(typeSet, type) &&
|
||||
|
@ -8579,9 +8584,6 @@ namespace ts {
|
|||
// Also, unlike union types, the order of the constituent types is preserved in order that overload resolution
|
||||
// for intersections of types with signatures can be deterministic.
|
||||
function getIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
|
||||
if (types.length === 0) {
|
||||
return emptyObjectType;
|
||||
}
|
||||
const typeSet: Type[] = [];
|
||||
const includes = addTypesToIntersection(typeSet, 0, types);
|
||||
if (includes & TypeFlags.Never) {
|
||||
|
@ -8598,6 +8600,9 @@ namespace ts {
|
|||
if (includes & TypeFlags.EmptyObject && !(includes & TypeFlags.Object)) {
|
||||
typeSet.push(emptyObjectType);
|
||||
}
|
||||
if (typeSet.length === 0) {
|
||||
return unknownType;
|
||||
}
|
||||
if (typeSet.length === 1) {
|
||||
return typeSet[0];
|
||||
}
|
||||
|
@ -8893,7 +8898,7 @@ namespace ts {
|
|||
// an expression. This is to preserve backwards compatibility. For example, an element access 'this["foo"]'
|
||||
// has always been resolved eagerly using the constraint type of 'this' at the given location.
|
||||
if (isGenericIndexType(indexType) || !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) && isGenericObjectType(objectType)) {
|
||||
if (objectType.flags & TypeFlags.Any) {
|
||||
if (objectType.flags & TypeFlags.AnyOrUnknown) {
|
||||
return objectType;
|
||||
}
|
||||
// Defer the operation by creating an indexed access type.
|
||||
|
@ -8961,6 +8966,9 @@ namespace ts {
|
|||
if (checkType === wildcardType || extendsType === wildcardType) {
|
||||
return wildcardType;
|
||||
}
|
||||
if (extendsType.flags & TypeFlags.AnyOrUnknown) {
|
||||
return instantiateType(root.trueType, mapper);
|
||||
}
|
||||
// If this is a distributive conditional type and the check type is generic we need to defer
|
||||
// resolution of the conditional type such that a later instantiation will properly distribute
|
||||
// over union types.
|
||||
|
@ -9195,6 +9203,9 @@ namespace ts {
|
|||
if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) {
|
||||
return anyType;
|
||||
}
|
||||
if (left.flags & TypeFlags.Unknown || right.flags & TypeFlags.Unknown) {
|
||||
return unknownType;
|
||||
}
|
||||
if (left.flags & TypeFlags.Never) {
|
||||
return right;
|
||||
}
|
||||
|
@ -9388,6 +9399,8 @@ namespace ts {
|
|||
case SyntaxKind.JSDocAllType:
|
||||
case SyntaxKind.JSDocUnknownType:
|
||||
return anyType;
|
||||
case SyntaxKind.UnknownKeyword:
|
||||
return unknownType;
|
||||
case SyntaxKind.StringKeyword:
|
||||
return stringType;
|
||||
case SyntaxKind.NumberKeyword:
|
||||
|
@ -9756,7 +9769,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function isMappableType(type: Type) {
|
||||
return type.flags & (TypeFlags.Any | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection);
|
||||
return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection);
|
||||
}
|
||||
|
||||
function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper): AnonymousType {
|
||||
|
@ -9855,7 +9868,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function getWildcardInstantiation(type: Type) {
|
||||
return type.flags & (TypeFlags.Primitive | TypeFlags.Any | TypeFlags.Never) ? type :
|
||||
return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type :
|
||||
type.wildcardInstantiation || (type.wildcardInstantiation = instantiateType(type, wildcardMapper));
|
||||
}
|
||||
|
||||
|
@ -10269,7 +10282,7 @@ namespace ts {
|
|||
function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map<RelationComparisonResult>, errorReporter?: ErrorReporter) {
|
||||
const s = source.flags;
|
||||
const t = target.flags;
|
||||
if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) return true;
|
||||
if (t & TypeFlags.AnyOrUnknown || s & TypeFlags.Never || source === wildcardType) return true;
|
||||
if (t & TypeFlags.Never) return false;
|
||||
if (s & TypeFlags.StringLike && t & TypeFlags.String) return true;
|
||||
if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral &&
|
||||
|
@ -10995,7 +11008,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
const constraint = getConstraintForRelation(<TypeParameter>source);
|
||||
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
|
||||
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.AnyOrUnknown)) {
|
||||
// A type variable with no constraint is not related to the non-primitive object type.
|
||||
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
|
||||
errorInfo = saveErrorInfo;
|
||||
|
@ -11438,7 +11451,7 @@ namespace ts {
|
|||
return indexTypesIdenticalTo(source, target, kind);
|
||||
}
|
||||
const targetInfo = getIndexInfoOfType(target, kind);
|
||||
if (!targetInfo || targetInfo.type.flags & TypeFlags.Any && !sourceIsPrimitive) {
|
||||
if (!targetInfo || targetInfo.type.flags & TypeFlags.AnyOrUnknown && !sourceIsPrimitive) {
|
||||
// Index signature of type any permits assignment from everything but primitives
|
||||
return Ternary.True;
|
||||
}
|
||||
|
@ -14467,7 +14480,7 @@ namespace ts {
|
|||
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
|
||||
// declaration container are the same).
|
||||
const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAsignmentTarget ||
|
||||
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 ||
|
||||
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.AnyOrUnknown) !== 0 ||
|
||||
isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) ||
|
||||
node.parent.kind === SyntaxKind.NonNullExpression ||
|
||||
declaration.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>declaration).exclamationToken ||
|
||||
|
@ -16071,7 +16084,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function isValidSpreadType(type: Type): boolean {
|
||||
return !!(type.flags & (TypeFlags.Any | TypeFlags.NonPrimitive) ||
|
||||
return !!(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.NonPrimitive) ||
|
||||
getFalsyFlags(type) & TypeFlags.DefinitelyFalsy && isValidSpreadType(removeDefinitelyFalsyTypes(type)) ||
|
||||
type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
|
||||
type.flags & TypeFlags.UnionOrIntersection && !forEach((<UnionOrIntersectionType>type).types, t => !isValidSpreadType(t)));
|
||||
|
@ -19624,7 +19637,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
// Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions.
|
||||
if (returnType && maybeTypeOfKind(returnType, TypeFlags.Any | TypeFlags.Void)) {
|
||||
if (returnType && maybeTypeOfKind(returnType, TypeFlags.AnyOrUnknown | TypeFlags.Void)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -19952,7 +19965,7 @@ namespace ts {
|
|||
if (source.flags & kind) {
|
||||
return true;
|
||||
}
|
||||
if (strict && source.flags & (TypeFlags.Any | TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null)) {
|
||||
if (strict && source.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null)) {
|
||||
return false;
|
||||
}
|
||||
return !!(kind & TypeFlags.NumberLike) && isTypeAssignableTo(source, numberType) ||
|
||||
|
@ -23849,7 +23862,7 @@ namespace ts {
|
|||
const unwrappedReturnType = (getFunctionFlags(func) & FunctionFlags.AsyncGenerator) === FunctionFlags.Async
|
||||
? getPromisedTypeOfPromise(returnType) // Async function
|
||||
: returnType; // AsyncGenerator function, Generator function, or normal function
|
||||
return !!unwrappedReturnType && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.Any);
|
||||
return !!unwrappedReturnType && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.AnyOrUnknown);
|
||||
}
|
||||
|
||||
function checkReturnStatement(node: ReturnStatement) {
|
||||
|
@ -24143,6 +24156,7 @@ namespace ts {
|
|||
// The predefined type keywords are reserved and cannot be used as names of user defined types.
|
||||
switch (name.escapedText) {
|
||||
case "any":
|
||||
case "unknown":
|
||||
case "number":
|
||||
case "boolean":
|
||||
case "string":
|
||||
|
@ -24563,7 +24577,7 @@ namespace ts {
|
|||
const propName = (<PropertyDeclaration>member).name;
|
||||
if (isIdentifier(propName)) {
|
||||
const type = getTypeOfSymbol(getSymbolOfNode(member));
|
||||
if (!(type.flags & TypeFlags.Any || getFalsyFlags(type) & TypeFlags.Undefined)) {
|
||||
if (!(type.flags & TypeFlags.AnyOrUnknown || getFalsyFlags(type) & TypeFlags.Undefined)) {
|
||||
if (!constructor || !isPropertyInitializedInConstructor(propName, type, constructor)) {
|
||||
error(member.name, Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, declarationNameToString(propName));
|
||||
}
|
||||
|
@ -26735,7 +26749,7 @@ namespace ts {
|
|||
if (type === errorType) {
|
||||
return TypeReferenceSerializationKind.Unknown;
|
||||
}
|
||||
else if (type.flags & TypeFlags.Any) {
|
||||
else if (type.flags & TypeFlags.AnyOrUnknown) {
|
||||
return TypeReferenceSerializationKind.ObjectType;
|
||||
}
|
||||
else if (isTypeAssignableToKind(type, TypeFlags.Void | TypeFlags.Nullable | TypeFlags.Never)) {
|
||||
|
|
Loading…
Reference in a new issue