Skip to content

Commit 68465f8

Browse files
Merge remote-tracking branch 'origin/master' into release-3.8
2 parents 7745f86 + f807b57 commit 68465f8

29 files changed

+348
-102
lines changed

src/compiler/checker.ts

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6981,7 +6981,7 @@ namespace ts {
69816981
getTypeWithFacts(type, TypeFacts.NEUndefined) :
69826982
type;
69836983
}
6984-
return getUnionType([getTypeWithFacts(type, TypeFacts.NEUndefined), checkDeclarationInitializer(declaration)], UnionReduction.Subtype);
6984+
return widenTypeInferredFromInitializer(declaration, getUnionType([getTypeWithFacts(type, TypeFacts.NEUndefined), checkDeclarationInitializer(declaration)], UnionReduction.Subtype));
69856985
}
69866986

69876987
function getTypeForDeclarationFromJSDocComment(declaration: Node) {
@@ -7098,7 +7098,7 @@ namespace ts {
70987098
// Use the type of the initializer expression if one is present and the declaration is
70997099
// not a parameter of a contextually typed function
71007100
if (declaration.initializer && !isParameterOfContextuallyTypedFunction(declaration)) {
7101-
const type = checkDeclarationInitializer(declaration);
7101+
const type = widenTypeInferredFromInitializer(declaration, checkDeclarationInitializer(declaration));
71027102
return addOptionality(type, isOptional);
71037103
}
71047104

@@ -7330,7 +7330,11 @@ namespace ts {
73307330
// pattern. Otherwise, it is the type any.
73317331
function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type {
73327332
if (element.initializer) {
7333-
return addOptionality(checkDeclarationInitializer(element));
7333+
// The type implied by a binding pattern is independent of context, so we check the initializer with no
7334+
// contextual type or, if the element itself is a binding pattern, with the type implied by that binding
7335+
// pattern.
7336+
const contextualType = isBindingPattern(element.name) ? getTypeFromBindingPattern(element.name, /*includePatternInType*/ true, /*reportErrors*/ false) : unknownType;
7337+
return addOptionality(widenTypeInferredFromInitializer(element, checkDeclarationInitializer(element, contextualType)));
73347338
}
73357339
if (isBindingPattern(element.name)) {
73367340
return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors);
@@ -21195,9 +21199,10 @@ namespace ts {
2119521199
}
2119621200

2119721201
function getContextualTypeForBindingElement(declaration: BindingElement): Type | undefined {
21198-
const parentDeclaration = declaration.parent.parent;
21202+
const parent = declaration.parent.parent;
2119921203
const name = declaration.propertyName || declaration.name;
21200-
const parentType = getContextualTypeForVariableLikeDeclaration(parentDeclaration);
21204+
const parentType = getContextualTypeForVariableLikeDeclaration(parent) ||
21205+
parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent);
2120121206
if (parentType && !isBindingPattern(name) && !isComputedNonLiteralName(name)) {
2120221207
const nameType = getLiteralTypeFromPropertyName(name);
2120321208
if (isTypeUsableAsPropertyName(nameType)) {
@@ -27661,27 +27666,13 @@ namespace ts {
2766127666
return node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression;
2766227667
}
2766327668

27664-
function checkDeclarationInitializer(declaration: HasExpressionInitializer) {
27669+
function checkDeclarationInitializer(declaration: HasExpressionInitializer, contextualType?: Type | undefined) {
2766527670
const initializer = getEffectiveInitializer(declaration)!;
27666-
const type = getQuickTypeOfExpression(initializer) || checkExpressionCached(initializer);
27667-
const padded = isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern &&
27671+
const type = getQuickTypeOfExpression(initializer) ||
27672+
(contextualType ? checkExpressionWithContextualType(initializer, contextualType, /*inferenceContext*/ undefined, CheckMode.Normal) : checkExpressionCached(initializer));
27673+
return isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern &&
2766827674
isTupleType(type) && !type.target.hasRestElement && getTypeReferenceArity(type) < declaration.name.elements.length ?
2766927675
padTupleType(type, declaration.name) : type;
27670-
const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const ||
27671-
isDeclarationReadonly(declaration) ||
27672-
isTypeAssertion(initializer) ||
27673-
isLiteralOfContextualType(padded, getContextualType(initializer)) ? padded : getWidenedLiteralType(padded);
27674-
if (isInJSFile(declaration)) {
27675-
if (widened.flags & TypeFlags.Nullable) {
27676-
reportImplicitAny(declaration, anyType);
27677-
return anyType;
27678-
}
27679-
else if (isEmptyArrayLiteralType(widened)) {
27680-
reportImplicitAny(declaration, anyArrayType);
27681-
return anyArrayType;
27682-
}
27683-
}
27684-
return widened;
2768527676
}
2768627677

2768727678
function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) {
@@ -27700,6 +27691,21 @@ namespace ts {
2770027691
return createTupleType(elementTypes, type.target.minLength, /*hasRestElement*/ false, type.target.readonly);
2770127692
}
2770227693

27694+
function widenTypeInferredFromInitializer(declaration: HasExpressionInitializer, type: Type) {
27695+
const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const || isDeclarationReadonly(declaration) ? type : getWidenedLiteralType(type);
27696+
if (isInJSFile(declaration)) {
27697+
if (widened.flags & TypeFlags.Nullable) {
27698+
reportImplicitAny(declaration, anyType);
27699+
return anyType;
27700+
}
27701+
else if (isEmptyArrayLiteralType(widened)) {
27702+
reportImplicitAny(declaration, anyArrayType);
27703+
return anyArrayType;
27704+
}
27705+
}
27706+
return widened;
27707+
}
27708+
2770327709
function isLiteralOfContextualType(candidateType: Type, contextualType: Type | undefined): boolean {
2770427710
if (contextualType) {
2770527711
if (contextualType.flags & TypeFlags.UnionOrIntersection) {
@@ -33128,12 +33134,12 @@ namespace ts {
3312833134
importClauseContainsReferencedImport(statement.importClause) &&
3312933135
!isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true)
3313033136
) {
33131-
const isError = compilerOptions.importsNotUsedAsValue === ImportsNotUsedAsValue.Error;
33137+
const isError = compilerOptions.importsNotUsedAsValues === importsNotUsedAsValues.Error;
3313233138
errorOrSuggestion(
3313333139
isError,
3313433140
statement,
3313533141
isError
33136-
? Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_the_importsNotUsedAsValue_is_set_to_error
33142+
? Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_the_importsNotUsedAsValues_is_set_to_error
3313733143
: Diagnostics.This_import_may_be_converted_to_a_type_only_import);
3313833144
}
3313933145
}

src/compiler/commandLineParser.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -473,11 +473,11 @@ namespace ts {
473473
description: Diagnostics.Import_emit_helpers_from_tslib
474474
},
475475
{
476-
name: "importsNotUsedAsValue",
476+
name: "importsNotUsedAsValues",
477477
type: createMapFromTemplate({
478-
remove: ImportsNotUsedAsValue.Remove,
479-
preserve: ImportsNotUsedAsValue.Preserve,
480-
error: ImportsNotUsedAsValue.Error
478+
remove: importsNotUsedAsValues.Remove,
479+
preserve: importsNotUsedAsValues.Preserve,
480+
error: importsNotUsedAsValues.Error
481481
}),
482482
affectsEmit: true,
483483
category: Diagnostics.Advanced_Options,

src/compiler/diagnosticMessages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@
10991099
"category": "Error",
11001100
"code": 1370
11011101
},
1102-
"This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValue' is set to 'error'.": {
1102+
"This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.": {
11031103
"category": "Error",
11041104
"code": 1371
11051105
},

src/compiler/transformers/ts.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2760,7 +2760,7 @@ namespace ts {
27602760
}
27612761

27622762
/**
2763-
* Visits an import declaration, eliding it if it is not referenced and `importsNotUsedAsValue` is not 'preserve'.
2763+
* Visits an import declaration, eliding it if it is not referenced and `importsNotUsedAsValues` is not 'preserve'.
27642764
*
27652765
* @param node The import declaration node.
27662766
*/
@@ -2778,8 +2778,8 @@ namespace ts {
27782778
// Elide the declaration if the import clause was elided.
27792779
const importClause = visitNode(node.importClause, visitImportClause, isImportClause);
27802780
return importClause ||
2781-
compilerOptions.importsNotUsedAsValue === ImportsNotUsedAsValue.Preserve ||
2782-
compilerOptions.importsNotUsedAsValue === ImportsNotUsedAsValue.Error
2781+
compilerOptions.importsNotUsedAsValues === importsNotUsedAsValues.Preserve ||
2782+
compilerOptions.importsNotUsedAsValues === importsNotUsedAsValues.Error
27832783
? updateImportDeclaration(
27842784
node,
27852785
/*decorators*/ undefined,
@@ -2931,7 +2931,7 @@ namespace ts {
29312931
if (isExternalModuleImportEqualsDeclaration(node)) {
29322932
const isReferenced = resolver.isReferencedAliasDeclaration(node);
29332933
// If the alias is unreferenced but we want to keep the import, replace with 'import "mod"'.
2934-
if (!isReferenced && compilerOptions.importsNotUsedAsValue === ImportsNotUsedAsValue.Preserve) {
2934+
if (!isReferenced && compilerOptions.importsNotUsedAsValues === importsNotUsedAsValues.Preserve) {
29352935
return setOriginalNode(
29362936
setTextRange(
29372937
createImportDeclaration(

src/compiler/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5043,7 +5043,7 @@ namespace ts {
50435043
/*@internal*/generateCpuProfile?: string;
50445044
/*@internal*/help?: boolean;
50455045
importHelpers?: boolean;
5046-
importsNotUsedAsValue?: ImportsNotUsedAsValue;
5046+
importsNotUsedAsValues?: importsNotUsedAsValues;
50475047
/*@internal*/init?: boolean;
50485048
inlineSourceMap?: boolean;
50495049
inlineSources?: boolean;
@@ -5165,7 +5165,7 @@ namespace ts {
51655165
ReactNative = 3
51665166
}
51675167

5168-
export const enum ImportsNotUsedAsValue {
5168+
export const enum importsNotUsedAsValues {
51695169
Remove,
51705170
Preserve,
51715171
Error

src/lib/es5.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ declare var Function: FunctionConstructor;
298298
/**
299299
* Extracts the type of the 'this' parameter of a function type, or 'unknown' if the function type has no 'this' parameter.
300300
*/
301-
type ThisParameterType<T> = T extends (this: unknown, ...args: any[]) => any ? unknown : T extends (this: infer U, ...args: any[]) => any ? U : unknown;
301+
type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown;
302302

303303
/**
304304
* Removes the 'this' parameter from a function type.

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,7 +2651,7 @@ declare namespace ts {
26512651
experimentalDecorators?: boolean;
26522652
forceConsistentCasingInFileNames?: boolean;
26532653
importHelpers?: boolean;
2654-
importsNotUsedAsValue?: ImportsNotUsedAsValue;
2654+
importsNotUsedAsValues?: importsNotUsedAsValues;
26552655
inlineSourceMap?: boolean;
26562656
inlineSources?: boolean;
26572657
isolatedModules?: boolean;
@@ -2750,7 +2750,7 @@ declare namespace ts {
27502750
React = 2,
27512751
ReactNative = 3
27522752
}
2753-
export enum ImportsNotUsedAsValue {
2753+
export enum importsNotUsedAsValues {
27542754
Remove = 0,
27552755
Preserve = 1,
27562756
Error = 2

tests/baselines/reference/api/typescript.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,7 +2651,7 @@ declare namespace ts {
26512651
experimentalDecorators?: boolean;
26522652
forceConsistentCasingInFileNames?: boolean;
26532653
importHelpers?: boolean;
2654-
importsNotUsedAsValue?: ImportsNotUsedAsValue;
2654+
importsNotUsedAsValues?: importsNotUsedAsValues;
26552655
inlineSourceMap?: boolean;
26562656
inlineSources?: boolean;
26572657
isolatedModules?: boolean;
@@ -2750,7 +2750,7 @@ declare namespace ts {
27502750
React = 2,
27512751
ReactNative = 3
27522752
}
2753-
export enum ImportsNotUsedAsValue {
2753+
export enum importsNotUsedAsValues {
27542754
Remove = 0,
27552755
Preserve = 1,
27562756
Error = 2

tests/baselines/reference/crashInGetTextOfComputedPropertyName.errors.txt

Lines changed: 0 additions & 36 deletions
This file was deleted.

tests/baselines/reference/crashInGetTextOfComputedPropertyName.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,16 @@ const {
5656
items: { [itemId]: itemWithTSError } = {} /*happens when default value is provided*/
5757
>items : any
5858
>itemId : "some-id"
59-
>itemWithTSError : any
60-
>{} : { "some-id": any; }
59+
>itemWithTSError : AB
60+
>{} : {}
6161

6262
} = objWithItems
6363
>objWithItems : ObjWithItems
6464

6565
// in order to re-produce the error, uncomment next line:
6666
typeof itemWithTSError // :(
6767
>typeof itemWithTSError : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
68-
>itemWithTSError : any
68+
>itemWithTSError : AB
6969

7070
// will result in:
7171
// Error from compilation: TypeError: Cannot read property 'charCodeAt' of undefined TypeError: Cannot read property 'charCodeAt' of undefined

0 commit comments

Comments
 (0)