From 28e3e6ff2f49f1dbf06d31809ec73dbe42f1aa63 Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Tue, 25 May 2021 11:40:42 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Pick=20PR=20#44219=20(Properly?= =?UTF-8?q?=20remove=20generic=20types=20that=20...)=20into=20release-4.3?= =?UTF-8?q?=20(#44243)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Cherry-pick PR #44219 into release-4.3 Component commits: 4475012558 Improve getNonNullableType function 86f09ae87c Add tests d45806a984 More closely match previous behavior 634b01ab3a Add non-strict mode test * Update LKG Co-authored-by: Anders Hejlsberg Co-authored-by: typescript-bot --- lib/tsc.js | 29 +++++---- lib/tsserver.js | 34 +++++++---- lib/tsserverlibrary.js | 34 +++++++---- lib/typescript.js | 34 +++++++---- lib/typescriptServices.js | 34 +++++++---- lib/typingsInstaller.js | 34 +++++++---- src/compiler/checker.ts | 15 +++-- .../reference/nonNullableReduction.js | 33 ++++++++++ .../reference/nonNullableReduction.symbols | 61 +++++++++++++++++++ .../reference/nonNullableReduction.types | 50 +++++++++++++++ .../nonNullableReductionNonStrict.js | 32 ++++++++++ .../nonNullableReductionNonStrict.symbols | 61 +++++++++++++++++++ .../nonNullableReductionNonStrict.types | 50 +++++++++++++++ tests/cases/compiler/nonNullableReduction.ts | 19 ++++++ .../compiler/nonNullableReductionNonStrict.ts | 17 ++++++ 15 files changed, 460 insertions(+), 77 deletions(-) create mode 100644 tests/baselines/reference/nonNullableReduction.js create mode 100644 tests/baselines/reference/nonNullableReduction.symbols create mode 100644 tests/baselines/reference/nonNullableReduction.types create mode 100644 tests/baselines/reference/nonNullableReductionNonStrict.js create mode 100644 tests/baselines/reference/nonNullableReductionNonStrict.symbols create mode 100644 tests/baselines/reference/nonNullableReductionNonStrict.types create mode 100644 tests/cases/compiler/nonNullableReduction.ts create mode 100644 tests/cases/compiler/nonNullableReductionNonStrict.ts diff --git a/lib/tsc.js b/lib/tsc.js index 12bb4e68b5b08..83f54758acd6c 100644 --- a/lib/tsc.js +++ b/lib/tsc.js @@ -46281,6 +46281,10 @@ var ts; var indexSymbol = symbol && getIndexSymbol(symbol); return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); } + function getIndexDeclarationOfSymbolTable(symbolTable, kind) { + var indexSymbol = symbolTable && getIndexSymbolFromSymbolTable(symbolTable); + return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); + } function getIndexDeclarationOfIndexSymbol(indexSymbol, kind) { var syntaxKind = kind === 1 ? 144 : 147; if (indexSymbol === null || indexSymbol === void 0 ? void 0 : indexSymbol.declarations) { @@ -52614,13 +52618,13 @@ var ts; return type.flags & 32768 ? type : getUnionType([type, undefinedType]); } function getGlobalNonNullableTypeInstantiation(type) { + var reducedType = getTypeWithFacts(type, 2097152); if (!deferredGlobalNonNullableTypeAlias) { deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable", 524288, undefined) || unknownSymbol; } - if (deferredGlobalNonNullableTypeAlias !== unknownSymbol) { - return getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]); - } - return getTypeWithFacts(type, 2097152); + return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? + getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [reducedType]) : + reducedType; } function getNonNullableType(type) { return strictNullChecks ? getGlobalNonNullableTypeInstantiation(type) : type; @@ -55757,7 +55761,7 @@ var ts; !isGenericIndexType(getTypeOfExpression(parent.argumentExpression)); } function isGenericTypeWithUnionConstraint(type) { - return !!(type.flags & 465829888 && getBaseConstraintOrType(type).flags & 1048576); + return !!(type.flags & 465829888 && getBaseConstraintOrType(type).flags & (98304 | 1048576)); } function containsGenericType(type) { return !!(type.flags & 465829888 || type.flags & 3145728 && ts.some(type.types, containsGenericType)); @@ -65459,21 +65463,24 @@ var ts; checkBlock(node.finallyBlock); } } - function checkIndexConstraints(type) { - var declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, 1); - var declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, 0); + function checkIndexConstraints(type, isStatic) { + var _a, _b, _c, _d; + var declaredNumberIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_a = type.symbol) === null || _a === void 0 ? void 0 : _a.exports : (_b = type.symbol) === null || _b === void 0 ? void 0 : _b.members, 1); + var declaredStringIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_c = type.symbol) === null || _c === void 0 ? void 0 : _c.exports : (_d = type.symbol) === null || _d === void 0 ? void 0 : _d.members, 0); var stringIndexType = getIndexTypeOfType(type, 0); var numberIndexType = getIndexTypeOfType(type, 1); if (stringIndexType || numberIndexType) { ts.forEach(getPropertiesOfObjectType(type), function (prop) { + if (isStatic && prop.flags & 4194304) + return; var propType = getTypeOfSymbol(prop); checkIndexConstraintForProperty(prop, propType, type, declaredStringIndexer, stringIndexType, 0); checkIndexConstraintForProperty(prop, propType, type, declaredNumberIndexer, numberIndexType, 1); }); var classDeclaration = type.symbol.valueDeclaration; if (ts.getObjectFlags(type) & 1 && classDeclaration && ts.isClassLike(classDeclaration)) { - for (var _i = 0, _a = classDeclaration.members; _i < _a.length; _i++) { - var member = _a[_i]; + for (var _i = 0, _e = classDeclaration.members; _i < _e.length; _i++) { + var member = _e[_i]; if (!ts.hasSyntacticModifier(member, 32) && !hasBindableName(member)) { var symbol = getSymbolOfNode(member); var propType = getTypeOfSymbol(symbol); @@ -65767,7 +65774,7 @@ var ts; } if (produceDiagnostics) { checkIndexConstraints(type); - checkIndexConstraints(staticType); + checkIndexConstraints(staticType, true); checkTypeForDuplicateIndexSignatures(node); checkPropertyInitialization(node); } diff --git a/lib/tsserver.js b/lib/tsserver.js index 9d0fcc773e8c0..58028943d1d1f 100644 --- a/lib/tsserver.js +++ b/lib/tsserver.js @@ -56010,6 +56010,10 @@ var ts; var indexSymbol = symbol && getIndexSymbol(symbol); return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); } + function getIndexDeclarationOfSymbolTable(symbolTable, kind) { + var indexSymbol = symbolTable && getIndexSymbolFromSymbolTable(symbolTable); + return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); + } function getIndexDeclarationOfIndexSymbol(indexSymbol, kind) { var syntaxKind = kind === 1 /* Number */ ? 144 /* NumberKeyword */ : 147 /* StringKeyword */; if (indexSymbol === null || indexSymbol === void 0 ? void 0 : indexSymbol.declarations) { @@ -63218,14 +63222,17 @@ var ts; return type.flags & 32768 /* Undefined */ ? type : getUnionType([type, undefinedType]); } function getGlobalNonNullableTypeInstantiation(type) { + // First reduce away any constituents that are assignable to 'undefined' or 'null'. This not only eliminates + // 'undefined' and 'null', but also higher-order types such as a type parameter 'U extends undefined | null' + // that isn't eliminated by a NonNullable instantiation. + var reducedType = getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); if (!deferredGlobalNonNullableTypeAlias) { deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable", 524288 /* TypeAlias */, /*diagnostic*/ undefined) || unknownSymbol; } - // Use NonNullable global type alias if available to improve quick info/declaration emit - if (deferredGlobalNonNullableTypeAlias !== unknownSymbol) { - return getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]); - } - return getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); // Type alias unavailable, fall back to non-higher-order behavior + // If the NonNullable type is available, return an instantiation. Otherwise just return the reduced type. + return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? + getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [reducedType]) : + reducedType; } function getNonNullableType(type) { return strictNullChecks ? getGlobalNonNullableTypeInstantiation(type) : type; @@ -66813,7 +66820,7 @@ var ts; !isGenericIndexType(getTypeOfExpression(parent.argumentExpression)); } function isGenericTypeWithUnionConstraint(type) { - return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & 1048576 /* Union */); + return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & (98304 /* Nullable */ | 1048576 /* Union */)); } function containsGenericType(type) { return !!(type.flags & 465829888 /* Instantiable */ || type.flags & 3145728 /* UnionOrIntersection */ && ts.some(type.types, containsGenericType)); @@ -78287,21 +78294,24 @@ var ts; checkBlock(node.finallyBlock); } } - function checkIndexConstraints(type) { - var declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, 1 /* Number */); - var declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, 0 /* String */); + function checkIndexConstraints(type, isStatic) { + var _a, _b, _c, _d; + var declaredNumberIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_a = type.symbol) === null || _a === void 0 ? void 0 : _a.exports : (_b = type.symbol) === null || _b === void 0 ? void 0 : _b.members, 1 /* Number */); + var declaredStringIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_c = type.symbol) === null || _c === void 0 ? void 0 : _c.exports : (_d = type.symbol) === null || _d === void 0 ? void 0 : _d.members, 0 /* String */); var stringIndexType = getIndexTypeOfType(type, 0 /* String */); var numberIndexType = getIndexTypeOfType(type, 1 /* Number */); if (stringIndexType || numberIndexType) { ts.forEach(getPropertiesOfObjectType(type), function (prop) { + if (isStatic && prop.flags & 4194304 /* Prototype */) + return; var propType = getTypeOfSymbol(prop); checkIndexConstraintForProperty(prop, propType, type, declaredStringIndexer, stringIndexType, 0 /* String */); checkIndexConstraintForProperty(prop, propType, type, declaredNumberIndexer, numberIndexType, 1 /* Number */); }); var classDeclaration = type.symbol.valueDeclaration; if (ts.getObjectFlags(type) & 1 /* Class */ && classDeclaration && ts.isClassLike(classDeclaration)) { - for (var _i = 0, _a = classDeclaration.members; _i < _a.length; _i++) { - var member = _a[_i]; + for (var _i = 0, _e = classDeclaration.members; _i < _e.length; _i++) { + var member = _e[_i]; // Only process instance properties with computed names here. // Static properties cannot be in conflict with indexers, // and properties with literal names were already checked. @@ -78631,7 +78641,7 @@ var ts; } if (produceDiagnostics) { checkIndexConstraints(type); - checkIndexConstraints(staticType); + checkIndexConstraints(staticType, /*isStatic*/ true); checkTypeForDuplicateIndexSignatures(node); checkPropertyInitialization(node); } diff --git a/lib/tsserverlibrary.js b/lib/tsserverlibrary.js index 677cd7f8ff2f9..ee78ce982fd11 100644 --- a/lib/tsserverlibrary.js +++ b/lib/tsserverlibrary.js @@ -56204,6 +56204,10 @@ var ts; var indexSymbol = symbol && getIndexSymbol(symbol); return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); } + function getIndexDeclarationOfSymbolTable(symbolTable, kind) { + var indexSymbol = symbolTable && getIndexSymbolFromSymbolTable(symbolTable); + return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); + } function getIndexDeclarationOfIndexSymbol(indexSymbol, kind) { var syntaxKind = kind === 1 /* Number */ ? 144 /* NumberKeyword */ : 147 /* StringKeyword */; if (indexSymbol === null || indexSymbol === void 0 ? void 0 : indexSymbol.declarations) { @@ -63412,14 +63416,17 @@ var ts; return type.flags & 32768 /* Undefined */ ? type : getUnionType([type, undefinedType]); } function getGlobalNonNullableTypeInstantiation(type) { + // First reduce away any constituents that are assignable to 'undefined' or 'null'. This not only eliminates + // 'undefined' and 'null', but also higher-order types such as a type parameter 'U extends undefined | null' + // that isn't eliminated by a NonNullable instantiation. + var reducedType = getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); if (!deferredGlobalNonNullableTypeAlias) { deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable", 524288 /* TypeAlias */, /*diagnostic*/ undefined) || unknownSymbol; } - // Use NonNullable global type alias if available to improve quick info/declaration emit - if (deferredGlobalNonNullableTypeAlias !== unknownSymbol) { - return getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]); - } - return getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); // Type alias unavailable, fall back to non-higher-order behavior + // If the NonNullable type is available, return an instantiation. Otherwise just return the reduced type. + return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? + getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [reducedType]) : + reducedType; } function getNonNullableType(type) { return strictNullChecks ? getGlobalNonNullableTypeInstantiation(type) : type; @@ -67007,7 +67014,7 @@ var ts; !isGenericIndexType(getTypeOfExpression(parent.argumentExpression)); } function isGenericTypeWithUnionConstraint(type) { - return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & 1048576 /* Union */); + return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & (98304 /* Nullable */ | 1048576 /* Union */)); } function containsGenericType(type) { return !!(type.flags & 465829888 /* Instantiable */ || type.flags & 3145728 /* UnionOrIntersection */ && ts.some(type.types, containsGenericType)); @@ -78481,21 +78488,24 @@ var ts; checkBlock(node.finallyBlock); } } - function checkIndexConstraints(type) { - var declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, 1 /* Number */); - var declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, 0 /* String */); + function checkIndexConstraints(type, isStatic) { + var _a, _b, _c, _d; + var declaredNumberIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_a = type.symbol) === null || _a === void 0 ? void 0 : _a.exports : (_b = type.symbol) === null || _b === void 0 ? void 0 : _b.members, 1 /* Number */); + var declaredStringIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_c = type.symbol) === null || _c === void 0 ? void 0 : _c.exports : (_d = type.symbol) === null || _d === void 0 ? void 0 : _d.members, 0 /* String */); var stringIndexType = getIndexTypeOfType(type, 0 /* String */); var numberIndexType = getIndexTypeOfType(type, 1 /* Number */); if (stringIndexType || numberIndexType) { ts.forEach(getPropertiesOfObjectType(type), function (prop) { + if (isStatic && prop.flags & 4194304 /* Prototype */) + return; var propType = getTypeOfSymbol(prop); checkIndexConstraintForProperty(prop, propType, type, declaredStringIndexer, stringIndexType, 0 /* String */); checkIndexConstraintForProperty(prop, propType, type, declaredNumberIndexer, numberIndexType, 1 /* Number */); }); var classDeclaration = type.symbol.valueDeclaration; if (ts.getObjectFlags(type) & 1 /* Class */ && classDeclaration && ts.isClassLike(classDeclaration)) { - for (var _i = 0, _a = classDeclaration.members; _i < _a.length; _i++) { - var member = _a[_i]; + for (var _i = 0, _e = classDeclaration.members; _i < _e.length; _i++) { + var member = _e[_i]; // Only process instance properties with computed names here. // Static properties cannot be in conflict with indexers, // and properties with literal names were already checked. @@ -78825,7 +78835,7 @@ var ts; } if (produceDiagnostics) { checkIndexConstraints(type); - checkIndexConstraints(staticType); + checkIndexConstraints(staticType, /*isStatic*/ true); checkTypeForDuplicateIndexSignatures(node); checkPropertyInitialization(node); } diff --git a/lib/typescript.js b/lib/typescript.js index d1ed99912c034..615ad27f3f7d9 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -56204,6 +56204,10 @@ var ts; var indexSymbol = symbol && getIndexSymbol(symbol); return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); } + function getIndexDeclarationOfSymbolTable(symbolTable, kind) { + var indexSymbol = symbolTable && getIndexSymbolFromSymbolTable(symbolTable); + return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); + } function getIndexDeclarationOfIndexSymbol(indexSymbol, kind) { var syntaxKind = kind === 1 /* Number */ ? 144 /* NumberKeyword */ : 147 /* StringKeyword */; if (indexSymbol === null || indexSymbol === void 0 ? void 0 : indexSymbol.declarations) { @@ -63412,14 +63416,17 @@ var ts; return type.flags & 32768 /* Undefined */ ? type : getUnionType([type, undefinedType]); } function getGlobalNonNullableTypeInstantiation(type) { + // First reduce away any constituents that are assignable to 'undefined' or 'null'. This not only eliminates + // 'undefined' and 'null', but also higher-order types such as a type parameter 'U extends undefined | null' + // that isn't eliminated by a NonNullable instantiation. + var reducedType = getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); if (!deferredGlobalNonNullableTypeAlias) { deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable", 524288 /* TypeAlias */, /*diagnostic*/ undefined) || unknownSymbol; } - // Use NonNullable global type alias if available to improve quick info/declaration emit - if (deferredGlobalNonNullableTypeAlias !== unknownSymbol) { - return getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]); - } - return getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); // Type alias unavailable, fall back to non-higher-order behavior + // If the NonNullable type is available, return an instantiation. Otherwise just return the reduced type. + return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? + getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [reducedType]) : + reducedType; } function getNonNullableType(type) { return strictNullChecks ? getGlobalNonNullableTypeInstantiation(type) : type; @@ -67007,7 +67014,7 @@ var ts; !isGenericIndexType(getTypeOfExpression(parent.argumentExpression)); } function isGenericTypeWithUnionConstraint(type) { - return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & 1048576 /* Union */); + return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & (98304 /* Nullable */ | 1048576 /* Union */)); } function containsGenericType(type) { return !!(type.flags & 465829888 /* Instantiable */ || type.flags & 3145728 /* UnionOrIntersection */ && ts.some(type.types, containsGenericType)); @@ -78481,21 +78488,24 @@ var ts; checkBlock(node.finallyBlock); } } - function checkIndexConstraints(type) { - var declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, 1 /* Number */); - var declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, 0 /* String */); + function checkIndexConstraints(type, isStatic) { + var _a, _b, _c, _d; + var declaredNumberIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_a = type.symbol) === null || _a === void 0 ? void 0 : _a.exports : (_b = type.symbol) === null || _b === void 0 ? void 0 : _b.members, 1 /* Number */); + var declaredStringIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_c = type.symbol) === null || _c === void 0 ? void 0 : _c.exports : (_d = type.symbol) === null || _d === void 0 ? void 0 : _d.members, 0 /* String */); var stringIndexType = getIndexTypeOfType(type, 0 /* String */); var numberIndexType = getIndexTypeOfType(type, 1 /* Number */); if (stringIndexType || numberIndexType) { ts.forEach(getPropertiesOfObjectType(type), function (prop) { + if (isStatic && prop.flags & 4194304 /* Prototype */) + return; var propType = getTypeOfSymbol(prop); checkIndexConstraintForProperty(prop, propType, type, declaredStringIndexer, stringIndexType, 0 /* String */); checkIndexConstraintForProperty(prop, propType, type, declaredNumberIndexer, numberIndexType, 1 /* Number */); }); var classDeclaration = type.symbol.valueDeclaration; if (ts.getObjectFlags(type) & 1 /* Class */ && classDeclaration && ts.isClassLike(classDeclaration)) { - for (var _i = 0, _a = classDeclaration.members; _i < _a.length; _i++) { - var member = _a[_i]; + for (var _i = 0, _e = classDeclaration.members; _i < _e.length; _i++) { + var member = _e[_i]; // Only process instance properties with computed names here. // Static properties cannot be in conflict with indexers, // and properties with literal names were already checked. @@ -78825,7 +78835,7 @@ var ts; } if (produceDiagnostics) { checkIndexConstraints(type); - checkIndexConstraints(staticType); + checkIndexConstraints(staticType, /*isStatic*/ true); checkTypeForDuplicateIndexSignatures(node); checkPropertyInitialization(node); } diff --git a/lib/typescriptServices.js b/lib/typescriptServices.js index 4655fac07d1c5..59f7d01b56ae8 100644 --- a/lib/typescriptServices.js +++ b/lib/typescriptServices.js @@ -56204,6 +56204,10 @@ var ts; var indexSymbol = symbol && getIndexSymbol(symbol); return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); } + function getIndexDeclarationOfSymbolTable(symbolTable, kind) { + var indexSymbol = symbolTable && getIndexSymbolFromSymbolTable(symbolTable); + return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); + } function getIndexDeclarationOfIndexSymbol(indexSymbol, kind) { var syntaxKind = kind === 1 /* Number */ ? 144 /* NumberKeyword */ : 147 /* StringKeyword */; if (indexSymbol === null || indexSymbol === void 0 ? void 0 : indexSymbol.declarations) { @@ -63412,14 +63416,17 @@ var ts; return type.flags & 32768 /* Undefined */ ? type : getUnionType([type, undefinedType]); } function getGlobalNonNullableTypeInstantiation(type) { + // First reduce away any constituents that are assignable to 'undefined' or 'null'. This not only eliminates + // 'undefined' and 'null', but also higher-order types such as a type parameter 'U extends undefined | null' + // that isn't eliminated by a NonNullable instantiation. + var reducedType = getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); if (!deferredGlobalNonNullableTypeAlias) { deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable", 524288 /* TypeAlias */, /*diagnostic*/ undefined) || unknownSymbol; } - // Use NonNullable global type alias if available to improve quick info/declaration emit - if (deferredGlobalNonNullableTypeAlias !== unknownSymbol) { - return getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]); - } - return getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); // Type alias unavailable, fall back to non-higher-order behavior + // If the NonNullable type is available, return an instantiation. Otherwise just return the reduced type. + return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? + getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [reducedType]) : + reducedType; } function getNonNullableType(type) { return strictNullChecks ? getGlobalNonNullableTypeInstantiation(type) : type; @@ -67007,7 +67014,7 @@ var ts; !isGenericIndexType(getTypeOfExpression(parent.argumentExpression)); } function isGenericTypeWithUnionConstraint(type) { - return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & 1048576 /* Union */); + return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & (98304 /* Nullable */ | 1048576 /* Union */)); } function containsGenericType(type) { return !!(type.flags & 465829888 /* Instantiable */ || type.flags & 3145728 /* UnionOrIntersection */ && ts.some(type.types, containsGenericType)); @@ -78481,21 +78488,24 @@ var ts; checkBlock(node.finallyBlock); } } - function checkIndexConstraints(type) { - var declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, 1 /* Number */); - var declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, 0 /* String */); + function checkIndexConstraints(type, isStatic) { + var _a, _b, _c, _d; + var declaredNumberIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_a = type.symbol) === null || _a === void 0 ? void 0 : _a.exports : (_b = type.symbol) === null || _b === void 0 ? void 0 : _b.members, 1 /* Number */); + var declaredStringIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_c = type.symbol) === null || _c === void 0 ? void 0 : _c.exports : (_d = type.symbol) === null || _d === void 0 ? void 0 : _d.members, 0 /* String */); var stringIndexType = getIndexTypeOfType(type, 0 /* String */); var numberIndexType = getIndexTypeOfType(type, 1 /* Number */); if (stringIndexType || numberIndexType) { ts.forEach(getPropertiesOfObjectType(type), function (prop) { + if (isStatic && prop.flags & 4194304 /* Prototype */) + return; var propType = getTypeOfSymbol(prop); checkIndexConstraintForProperty(prop, propType, type, declaredStringIndexer, stringIndexType, 0 /* String */); checkIndexConstraintForProperty(prop, propType, type, declaredNumberIndexer, numberIndexType, 1 /* Number */); }); var classDeclaration = type.symbol.valueDeclaration; if (ts.getObjectFlags(type) & 1 /* Class */ && classDeclaration && ts.isClassLike(classDeclaration)) { - for (var _i = 0, _a = classDeclaration.members; _i < _a.length; _i++) { - var member = _a[_i]; + for (var _i = 0, _e = classDeclaration.members; _i < _e.length; _i++) { + var member = _e[_i]; // Only process instance properties with computed names here. // Static properties cannot be in conflict with indexers, // and properties with literal names were already checked. @@ -78825,7 +78835,7 @@ var ts; } if (produceDiagnostics) { checkIndexConstraints(type); - checkIndexConstraints(staticType); + checkIndexConstraints(staticType, /*isStatic*/ true); checkTypeForDuplicateIndexSignatures(node); checkPropertyInitialization(node); } diff --git a/lib/typingsInstaller.js b/lib/typingsInstaller.js index eb839a30eab36..6810860b9c4b6 100644 --- a/lib/typingsInstaller.js +++ b/lib/typingsInstaller.js @@ -55999,6 +55999,10 @@ var ts; var indexSymbol = symbol && getIndexSymbol(symbol); return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); } + function getIndexDeclarationOfSymbolTable(symbolTable, kind) { + var indexSymbol = symbolTable && getIndexSymbolFromSymbolTable(symbolTable); + return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind); + } function getIndexDeclarationOfIndexSymbol(indexSymbol, kind) { var syntaxKind = kind === 1 /* Number */ ? 144 /* NumberKeyword */ : 147 /* StringKeyword */; if (indexSymbol === null || indexSymbol === void 0 ? void 0 : indexSymbol.declarations) { @@ -63207,14 +63211,17 @@ var ts; return type.flags & 32768 /* Undefined */ ? type : getUnionType([type, undefinedType]); } function getGlobalNonNullableTypeInstantiation(type) { + // First reduce away any constituents that are assignable to 'undefined' or 'null'. This not only eliminates + // 'undefined' and 'null', but also higher-order types such as a type parameter 'U extends undefined | null' + // that isn't eliminated by a NonNullable instantiation. + var reducedType = getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); if (!deferredGlobalNonNullableTypeAlias) { deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable", 524288 /* TypeAlias */, /*diagnostic*/ undefined) || unknownSymbol; } - // Use NonNullable global type alias if available to improve quick info/declaration emit - if (deferredGlobalNonNullableTypeAlias !== unknownSymbol) { - return getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]); - } - return getTypeWithFacts(type, 2097152 /* NEUndefinedOrNull */); // Type alias unavailable, fall back to non-higher-order behavior + // If the NonNullable type is available, return an instantiation. Otherwise just return the reduced type. + return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? + getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [reducedType]) : + reducedType; } function getNonNullableType(type) { return strictNullChecks ? getGlobalNonNullableTypeInstantiation(type) : type; @@ -66802,7 +66809,7 @@ var ts; !isGenericIndexType(getTypeOfExpression(parent.argumentExpression)); } function isGenericTypeWithUnionConstraint(type) { - return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & 1048576 /* Union */); + return !!(type.flags & 465829888 /* Instantiable */ && getBaseConstraintOrType(type).flags & (98304 /* Nullable */ | 1048576 /* Union */)); } function containsGenericType(type) { return !!(type.flags & 465829888 /* Instantiable */ || type.flags & 3145728 /* UnionOrIntersection */ && ts.some(type.types, containsGenericType)); @@ -78276,21 +78283,24 @@ var ts; checkBlock(node.finallyBlock); } } - function checkIndexConstraints(type) { - var declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, 1 /* Number */); - var declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, 0 /* String */); + function checkIndexConstraints(type, isStatic) { + var _a, _b, _c, _d; + var declaredNumberIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_a = type.symbol) === null || _a === void 0 ? void 0 : _a.exports : (_b = type.symbol) === null || _b === void 0 ? void 0 : _b.members, 1 /* Number */); + var declaredStringIndexer = getIndexDeclarationOfSymbolTable(isStatic ? (_c = type.symbol) === null || _c === void 0 ? void 0 : _c.exports : (_d = type.symbol) === null || _d === void 0 ? void 0 : _d.members, 0 /* String */); var stringIndexType = getIndexTypeOfType(type, 0 /* String */); var numberIndexType = getIndexTypeOfType(type, 1 /* Number */); if (stringIndexType || numberIndexType) { ts.forEach(getPropertiesOfObjectType(type), function (prop) { + if (isStatic && prop.flags & 4194304 /* Prototype */) + return; var propType = getTypeOfSymbol(prop); checkIndexConstraintForProperty(prop, propType, type, declaredStringIndexer, stringIndexType, 0 /* String */); checkIndexConstraintForProperty(prop, propType, type, declaredNumberIndexer, numberIndexType, 1 /* Number */); }); var classDeclaration = type.symbol.valueDeclaration; if (ts.getObjectFlags(type) & 1 /* Class */ && classDeclaration && ts.isClassLike(classDeclaration)) { - for (var _i = 0, _a = classDeclaration.members; _i < _a.length; _i++) { - var member = _a[_i]; + for (var _i = 0, _e = classDeclaration.members; _i < _e.length; _i++) { + var member = _e[_i]; // Only process instance properties with computed names here. // Static properties cannot be in conflict with indexers, // and properties with literal names were already checked. @@ -78620,7 +78630,7 @@ var ts; } if (produceDiagnostics) { checkIndexConstraints(type); - checkIndexConstraints(staticType); + checkIndexConstraints(staticType, /*isStatic*/ true); checkTypeForDuplicateIndexSignatures(node); checkPropertyInitialization(node); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f9cd044a79331..eb8397a18b019 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20239,14 +20239,17 @@ namespace ts { } function getGlobalNonNullableTypeInstantiation(type: Type) { + // First reduce away any constituents that are assignable to 'undefined' or 'null'. This not only eliminates + // 'undefined' and 'null', but also higher-order types such as a type parameter 'U extends undefined | null' + // that isn't eliminated by a NonNullable instantiation. + const reducedType = getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); if (!deferredGlobalNonNullableTypeAlias) { deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable" as __String, SymbolFlags.TypeAlias, /*diagnostic*/ undefined) || unknownSymbol; } - // Use NonNullable global type alias if available to improve quick info/declaration emit - if (deferredGlobalNonNullableTypeAlias !== unknownSymbol) { - return getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]); - } - return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); // Type alias unavailable, fall back to non-higher-order behavior + // If the NonNullable type is available, return an instantiation. Otherwise just return the reduced type. + return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? + getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [reducedType]) : + reducedType; } function getNonNullableType(type: Type): Type { @@ -24035,7 +24038,7 @@ namespace ts { } function isGenericTypeWithUnionConstraint(type: Type) { - return !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & TypeFlags.Union); + return !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); } function containsGenericType(type: Type): boolean { diff --git a/tests/baselines/reference/nonNullableReduction.js b/tests/baselines/reference/nonNullableReduction.js new file mode 100644 index 0000000000000..57de1f96a7b71 --- /dev/null +++ b/tests/baselines/reference/nonNullableReduction.js @@ -0,0 +1,33 @@ +//// [nonNullableReduction.ts] +// Repros from #43425 + +type Transform1 = ((value: string) => T) | (string extends T ? undefined : never); +type Transform2 = string extends T ? ((value: string) => T) | undefined : (value: string) => T; + +function test(f1: Transform1, f2: Transform2) { + f1?.("hello"); + f2?.("hello"); +} + +function f1(x: T | (string extends T ? null | undefined : never)) { + let z = x!; // NonNullable +} + +function f2(x: T | U) { + let z = x!; // NonNullable +} + + +//// [nonNullableReduction.js] +"use strict"; +// Repros from #43425 +function test(f1, f2) { + f1 === null || f1 === void 0 ? void 0 : f1("hello"); + f2 === null || f2 === void 0 ? void 0 : f2("hello"); +} +function f1(x) { + var z = x; // NonNullable +} +function f2(x) { + var z = x; // NonNullable +} diff --git a/tests/baselines/reference/nonNullableReduction.symbols b/tests/baselines/reference/nonNullableReduction.symbols new file mode 100644 index 0000000000000..6007449ca6d4c --- /dev/null +++ b/tests/baselines/reference/nonNullableReduction.symbols @@ -0,0 +1,61 @@ +=== tests/cases/compiler/nonNullableReduction.ts === +// Repros from #43425 + +type Transform1 = ((value: string) => T) | (string extends T ? undefined : never); +>Transform1 : Symbol(Transform1, Decl(nonNullableReduction.ts, 0, 0)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 2, 16)) +>value : Symbol(value, Decl(nonNullableReduction.ts, 2, 23)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 2, 16)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 2, 16)) + +type Transform2 = string extends T ? ((value: string) => T) | undefined : (value: string) => T; +>Transform2 : Symbol(Transform2, Decl(nonNullableReduction.ts, 2, 85)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 3, 16)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 3, 16)) +>value : Symbol(value, Decl(nonNullableReduction.ts, 3, 42)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 3, 16)) +>value : Symbol(value, Decl(nonNullableReduction.ts, 3, 78)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 3, 16)) + +function test(f1: Transform1, f2: Transform2) { +>test : Symbol(test, Decl(nonNullableReduction.ts, 3, 98)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 5, 14)) +>f1 : Symbol(f1, Decl(nonNullableReduction.ts, 5, 17)) +>Transform1 : Symbol(Transform1, Decl(nonNullableReduction.ts, 0, 0)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 5, 14)) +>f2 : Symbol(f2, Decl(nonNullableReduction.ts, 5, 35)) +>Transform2 : Symbol(Transform2, Decl(nonNullableReduction.ts, 2, 85)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 5, 14)) + + f1?.("hello"); +>f1 : Symbol(f1, Decl(nonNullableReduction.ts, 5, 17)) + + f2?.("hello"); +>f2 : Symbol(f2, Decl(nonNullableReduction.ts, 5, 35)) +} + +function f1(x: T | (string extends T ? null | undefined : never)) { +>f1 : Symbol(f1, Decl(nonNullableReduction.ts, 8, 1)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 10, 12)) +>x : Symbol(x, Decl(nonNullableReduction.ts, 10, 15)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 10, 12)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 10, 12)) + + let z = x!; // NonNullable +>z : Symbol(z, Decl(nonNullableReduction.ts, 11, 7)) +>x : Symbol(x, Decl(nonNullableReduction.ts, 10, 15)) +} + +function f2(x: T | U) { +>f2 : Symbol(f2, Decl(nonNullableReduction.ts, 12, 1)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 14, 12)) +>U : Symbol(U, Decl(nonNullableReduction.ts, 14, 14)) +>x : Symbol(x, Decl(nonNullableReduction.ts, 14, 43)) +>T : Symbol(T, Decl(nonNullableReduction.ts, 14, 12)) +>U : Symbol(U, Decl(nonNullableReduction.ts, 14, 14)) + + let z = x!; // NonNullable +>z : Symbol(z, Decl(nonNullableReduction.ts, 15, 7)) +>x : Symbol(x, Decl(nonNullableReduction.ts, 14, 43)) +} + diff --git a/tests/baselines/reference/nonNullableReduction.types b/tests/baselines/reference/nonNullableReduction.types new file mode 100644 index 0000000000000..20a4a82179f7f --- /dev/null +++ b/tests/baselines/reference/nonNullableReduction.types @@ -0,0 +1,50 @@ +=== tests/cases/compiler/nonNullableReduction.ts === +// Repros from #43425 + +type Transform1 = ((value: string) => T) | (string extends T ? undefined : never); +>Transform1 : Transform1 +>value : string + +type Transform2 = string extends T ? ((value: string) => T) | undefined : (value: string) => T; +>Transform2 : Transform2 +>value : string +>value : string + +function test(f1: Transform1, f2: Transform2) { +>test : (f1: Transform1, f2: Transform2) => void +>f1 : Transform1 +>f2 : Transform2 + + f1?.("hello"); +>f1?.("hello") : T | undefined +>f1 : ((value: string) => T) | undefined +>"hello" : "hello" + + f2?.("hello"); +>f2?.("hello") : T | undefined +>f2 : ((value: string) => T) | ((value: string) => T) | undefined +>"hello" : "hello" +} + +function f1(x: T | (string extends T ? null | undefined : never)) { +>f1 : (x: T | (string extends T ? null | undefined : never)) => void +>x : T | (string extends T ? null | undefined : never) +>null : null + + let z = x!; // NonNullable +>z : NonNullable +>x! : NonNullable +>x : T | (string extends T ? null | undefined : never) +} + +function f2(x: T | U) { +>f2 : (x: T | U) => void +>null : null +>x : T | U + + let z = x!; // NonNullable +>z : NonNullable +>x! : NonNullable +>x : T | U +} + diff --git a/tests/baselines/reference/nonNullableReductionNonStrict.js b/tests/baselines/reference/nonNullableReductionNonStrict.js new file mode 100644 index 0000000000000..29c88cdec7fc1 --- /dev/null +++ b/tests/baselines/reference/nonNullableReductionNonStrict.js @@ -0,0 +1,32 @@ +//// [nonNullableReductionNonStrict.ts] +// Repros from #43425 + +type Transform1 = ((value: string) => T) | (string extends T ? undefined : never); +type Transform2 = string extends T ? ((value: string) => T) | undefined : (value: string) => T; + +function test(f1: Transform1, f2: Transform2) { + f1?.("hello"); + f2?.("hello"); +} + +function f1(x: T | (string extends T ? null | undefined : never)) { + let z = x!; // NonNullable +} + +function f2(x: T | U) { + let z = x!; // NonNullable +} + + +//// [nonNullableReductionNonStrict.js] +// Repros from #43425 +function test(f1, f2) { + f1 === null || f1 === void 0 ? void 0 : f1("hello"); + f2 === null || f2 === void 0 ? void 0 : f2("hello"); +} +function f1(x) { + var z = x; // NonNullable +} +function f2(x) { + var z = x; // NonNullable +} diff --git a/tests/baselines/reference/nonNullableReductionNonStrict.symbols b/tests/baselines/reference/nonNullableReductionNonStrict.symbols new file mode 100644 index 0000000000000..20e0c8ee0ff80 --- /dev/null +++ b/tests/baselines/reference/nonNullableReductionNonStrict.symbols @@ -0,0 +1,61 @@ +=== tests/cases/compiler/nonNullableReductionNonStrict.ts === +// Repros from #43425 + +type Transform1 = ((value: string) => T) | (string extends T ? undefined : never); +>Transform1 : Symbol(Transform1, Decl(nonNullableReductionNonStrict.ts, 0, 0)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 2, 16)) +>value : Symbol(value, Decl(nonNullableReductionNonStrict.ts, 2, 23)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 2, 16)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 2, 16)) + +type Transform2 = string extends T ? ((value: string) => T) | undefined : (value: string) => T; +>Transform2 : Symbol(Transform2, Decl(nonNullableReductionNonStrict.ts, 2, 85)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 3, 16)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 3, 16)) +>value : Symbol(value, Decl(nonNullableReductionNonStrict.ts, 3, 42)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 3, 16)) +>value : Symbol(value, Decl(nonNullableReductionNonStrict.ts, 3, 78)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 3, 16)) + +function test(f1: Transform1, f2: Transform2) { +>test : Symbol(test, Decl(nonNullableReductionNonStrict.ts, 3, 98)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 5, 14)) +>f1 : Symbol(f1, Decl(nonNullableReductionNonStrict.ts, 5, 17)) +>Transform1 : Symbol(Transform1, Decl(nonNullableReductionNonStrict.ts, 0, 0)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 5, 14)) +>f2 : Symbol(f2, Decl(nonNullableReductionNonStrict.ts, 5, 35)) +>Transform2 : Symbol(Transform2, Decl(nonNullableReductionNonStrict.ts, 2, 85)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 5, 14)) + + f1?.("hello"); +>f1 : Symbol(f1, Decl(nonNullableReductionNonStrict.ts, 5, 17)) + + f2?.("hello"); +>f2 : Symbol(f2, Decl(nonNullableReductionNonStrict.ts, 5, 35)) +} + +function f1(x: T | (string extends T ? null | undefined : never)) { +>f1 : Symbol(f1, Decl(nonNullableReductionNonStrict.ts, 8, 1)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 10, 12)) +>x : Symbol(x, Decl(nonNullableReductionNonStrict.ts, 10, 15)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 10, 12)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 10, 12)) + + let z = x!; // NonNullable +>z : Symbol(z, Decl(nonNullableReductionNonStrict.ts, 11, 7)) +>x : Symbol(x, Decl(nonNullableReductionNonStrict.ts, 10, 15)) +} + +function f2(x: T | U) { +>f2 : Symbol(f2, Decl(nonNullableReductionNonStrict.ts, 12, 1)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 14, 12)) +>U : Symbol(U, Decl(nonNullableReductionNonStrict.ts, 14, 14)) +>x : Symbol(x, Decl(nonNullableReductionNonStrict.ts, 14, 43)) +>T : Symbol(T, Decl(nonNullableReductionNonStrict.ts, 14, 12)) +>U : Symbol(U, Decl(nonNullableReductionNonStrict.ts, 14, 14)) + + let z = x!; // NonNullable +>z : Symbol(z, Decl(nonNullableReductionNonStrict.ts, 15, 7)) +>x : Symbol(x, Decl(nonNullableReductionNonStrict.ts, 14, 43)) +} + diff --git a/tests/baselines/reference/nonNullableReductionNonStrict.types b/tests/baselines/reference/nonNullableReductionNonStrict.types new file mode 100644 index 0000000000000..075ee5a41fd1b --- /dev/null +++ b/tests/baselines/reference/nonNullableReductionNonStrict.types @@ -0,0 +1,50 @@ +=== tests/cases/compiler/nonNullableReductionNonStrict.ts === +// Repros from #43425 + +type Transform1 = ((value: string) => T) | (string extends T ? undefined : never); +>Transform1 : Transform1 +>value : string + +type Transform2 = string extends T ? ((value: string) => T) | undefined : (value: string) => T; +>Transform2 : Transform2 +>value : string +>value : string + +function test(f1: Transform1, f2: Transform2) { +>test : (f1: Transform1, f2: Transform2) => void +>f1 : Transform1 +>f2 : Transform2 + + f1?.("hello"); +>f1?.("hello") : T +>f1 : (value: string) => T +>"hello" : "hello" + + f2?.("hello"); +>f2?.("hello") : T +>f2 : ((value: string) => T) | ((value: string) => T) +>"hello" : "hello" +} + +function f1(x: T | (string extends T ? null | undefined : never)) { +>f1 : (x: T | (string extends T ? null | undefined : never)) => void +>x : T | (string extends T ? null : never) +>null : null + + let z = x!; // NonNullable +>z : T | (string extends T ? null : never) +>x! : T | (string extends T ? null : never) +>x : T | (string extends T ? null : never) +} + +function f2(x: T | U) { +>f2 : (x: T | U) => void +>null : null +>x : T | U + + let z = x!; // NonNullable +>z : T | U +>x! : T | U +>x : T | U +} + diff --git a/tests/cases/compiler/nonNullableReduction.ts b/tests/cases/compiler/nonNullableReduction.ts new file mode 100644 index 0000000000000..1465d0e650ae6 --- /dev/null +++ b/tests/cases/compiler/nonNullableReduction.ts @@ -0,0 +1,19 @@ +// @strict: true + +// Repros from #43425 + +type Transform1 = ((value: string) => T) | (string extends T ? undefined : never); +type Transform2 = string extends T ? ((value: string) => T) | undefined : (value: string) => T; + +function test(f1: Transform1, f2: Transform2) { + f1?.("hello"); + f2?.("hello"); +} + +function f1(x: T | (string extends T ? null | undefined : never)) { + let z = x!; // NonNullable +} + +function f2(x: T | U) { + let z = x!; // NonNullable +} diff --git a/tests/cases/compiler/nonNullableReductionNonStrict.ts b/tests/cases/compiler/nonNullableReductionNonStrict.ts new file mode 100644 index 0000000000000..6212431709dad --- /dev/null +++ b/tests/cases/compiler/nonNullableReductionNonStrict.ts @@ -0,0 +1,17 @@ +// Repros from #43425 + +type Transform1 = ((value: string) => T) | (string extends T ? undefined : never); +type Transform2 = string extends T ? ((value: string) => T) | undefined : (value: string) => T; + +function test(f1: Transform1, f2: Transform2) { + f1?.("hello"); + f2?.("hello"); +} + +function f1(x: T | (string extends T ? null | undefined : never)) { + let z = x!; // NonNullable +} + +function f2(x: T | U) { + let z = x!; // NonNullable +}