diff --git a/src/linter/Utils.ts b/src/linter/Utils.ts index b837e082400815f9872a9282fe9148191eca02fa..11e61b27439ba39db2def7b3820c622846df6fed 100644 --- a/src/linter/Utils.ts +++ b/src/linter/Utils.ts @@ -780,67 +780,52 @@ function findProperty(type: Type, name: string): Symbol | undefined { return undefined; } -/* -function findDeclaration(type: ClassDeclaration | InterfaceDeclaration, name: string): NamedDeclaration | undefined { - const members: NodeArray | NodeArray = type.members; - let declFound: NamedDeclaration | undefined; - - for(const m of members) { - if (m.name && m.name.getText() === name) { - declFound = m; - break; - } - } - - if (declFound || !type.heritageClauses) return declFound; - - // Search in base classes/interfaces - for (let i1 = 0; i1 < type.heritageClauses.length; i1++) { - const v1 = type.heritageClauses[i1]; - for (let i2 = 0; i2 < v1.types.length; i2++) { - const v2 = v1.types[i2]; - const symbol = typeChecker.getTypeAtLocation(v2.expression).symbol; - if ( - (symbol.flags === SymbolFlags.Class || symbol.flags === SymbolFlags.Interface) && - symbol.declarations && symbol.declarations.length > 0 - ) { - declFound = findDelaration(symbol.declarations[0] as (ClassDeclaration | InterfaceDeclaration), name); - } - if (declFound) break; - }; - - if (declFound) break; - }; - - return declFound; +function getNonNullableType(t: ts.Type) { + if (t.isUnion()) { + return t.getNonNullableType(); + } + return t; } -*/ export function isExpressionAssignableToType(lhsType: ts.Type | undefined, rhsExpr: ts.Expression): boolean { if (lhsType === undefined) { return false; } + let nonNullableLhs = getNonNullableType(lhsType); + // Allow initializing with anything when the type // originates from the library. - if (isAnyType(lhsType) || isLibraryType(lhsType)) { + if (isAnyType(nonNullableLhs) || isLibraryType(nonNullableLhs)) { return true; } - // Always compare the non-nullable variant of types. - lhsType = lhsType.getNonNullableType(); - let rhsType = typeChecker.getTypeAtLocation(rhsExpr).getNonNullableType(); + // issue 13412: + // Allow initializing with a dynamic object when the LHS type + // is primitive or defined in standard library. + if (isDynamicObjectAssignedToStdType(nonNullableLhs, rhsExpr)) { + return true; + } + + // Allow initializing Record objects with object initializer. + // Record supports any type for a its value, but the key value + // must be either a string or number literal. + if (isStdRecordType(nonNullableLhs) && ts.isObjectLiteralExpression(rhsExpr)) { + return validateRecordObjectKeys(rhsExpr); + } - // For Partial, Required, Readonly types, validate its argument type. - if (isStdPartialType(lhsType) || isStdRequiredType(lhsType) || isStdReadonlyType(lhsType)) { - if (lhsType.aliasTypeArguments && lhsType.aliasTypeArguments.length === 1) { - lhsType = lhsType.aliasTypeArguments[0]; + // For Partial, Required, Readonly types, validate their argument type. + if (isStdPartialType(nonNullableLhs) || isStdRequiredType(nonNullableLhs) || isStdReadonlyType(nonNullableLhs)) { + if (nonNullableLhs.aliasTypeArguments && nonNullableLhs.aliasTypeArguments.length === 1) { + nonNullableLhs = nonNullableLhs.aliasTypeArguments[0]; } else { return false; } } + let rhsType = getNonNullableType(typeChecker.getTypeAtLocation(rhsExpr)); + if (rhsType.isUnion()) { let res = true; for (const compType of rhsType.types) { @@ -857,34 +842,20 @@ export function isExpressionAssignableToType(lhsType: ts.Type | undefined, rhsEx } } - // issue 13412: - // Allow initializing with a dynamic object when the LHS type - // is primitive or defined in standard library. - if (isDynamicObjectAssignedToStdType(lhsType, rhsExpr)) { - return true; - } - - // Allow initializing Record objects with object initializer. - // Record supports any type for a its value, but the key value - // must be either a string or number literal. - if (isStdRecordType(lhsType) && ts.isObjectLiteralExpression(rhsExpr)) { - return validateRecordObjectKeys(rhsExpr); - } - if (ts.isObjectLiteralExpression(rhsExpr)) { - return isObjectLiteralAssignable(lhsType, rhsExpr); + return isObjectLiteralAssignable(nonNullableLhs, rhsExpr); } - + return areTypesAssignable(lhsType, rhsType) } function areTypesAssignable(lhsType: ts.Type, rhsType: ts.Type): boolean { if (rhsType.isUnion()) { + let res = true; for (const compType of rhsType.types) { - if (areTypesAssignable(lhsType, compType)) { - return true; - } + res &&= areTypesAssignable(lhsType, compType) } + return res; } if (lhsType.isUnion()) { @@ -1232,7 +1203,6 @@ export function isStdReadonlyType(type: Type): boolean { return !!sym && sym.getName() === "Readonly" && isGlobalSymbol(sym); } - export function isLibraryType(type: Type): boolean { const nonNullableType = type.getNonNullableType(); if (nonNullableType.isUnion()) {