Detect and construct narrowable references for embedded type parameters

This commit is contained in:
Gabriela Araujo Britto
2025-02-28 14:01:28 -08:00
parent a22b7bfd04
commit d49a4956a0
5 changed files with 2033 additions and 23 deletions
+88 -23
View File
@@ -45918,14 +45918,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const narrowedTypeParameters: TypeParameter[] = [];
const narrowedTypes: Type[] = [];
for (const [typeParam, symbol, reference] of narrowableTypeParameters) {
const narrowReference = factory.cloneNode(reference); // Construct a reference that can be narrowed.
// Don't reuse the original reference's node id,
// because that could cause us to get a type that was cached for the original reference.
narrowReference.id = undefined;
for (const [typeParam, symbol, narrowReference] of narrowableTypeParameters) {
// Do not reuse node ids, as that could lead us to wrongly reuse cached information.
resetNodeId(narrowReference);
// Set the symbol of the synthetic reference.
// This allows us to get the type of the reference at a location where the reference is possibly shadowed.
getNodeLinks(narrowReference).resolvedSymbol = symbol;
let baseReference: Node = narrowReference;
while (isAccessExpression(baseReference)) {
baseReference = baseReference.expression;
}
getNodeLinks(baseReference).resolvedSymbol = symbol;
setParent(narrowReference, narrowPosition.parent);
narrowReference.flowNode = narrowFlowNode;
const initialType = getNarrowableTypeForReference(typeParam, narrowReference, /*checkMode*/ undefined, /*forReturnTypeNarrowing*/ true);
@@ -45974,13 +45976,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
checkTypeAssignableToAndOptionallyElaborate(narrowedUnwrappedExprType, narrowedReturnType, errorNode, effectiveExpr);
}
// Reset node ids of cloned nodes.
function resetNodeId(node: Node): void {
node.id = undefined;
forEachChildRecursively(node, resetNodeId);
}
type NarrowableReference = Identifier | ElementAccessExpression | PropertyAccessExpression;
/**
* Narrowable type parameters are type parameters that:
* (1) have a narrowable constraint;
* (2) are syntactically used as the type of a single parameter in the function, and nothing else
*/
function getNarrowableTypeParameters(candidates: TypeParameter[]): [TypeParameter, Symbol, Identifier][] {
const narrowableParams: [TypeParameter, Symbol, Identifier][] = [];
function getNarrowableTypeParameters(candidates: TypeParameter[]): [TypeParameter, Symbol, NarrowableReference][] {
const narrowableParams: [TypeParameter, Symbol, NarrowableReference][] = [];
for (const typeParam of candidates) {
const constraint = getConstraintOfTypeParameter(typeParam);
if (!constraint || !isNarrowableTypeParameterConstraint(constraint)) continue;
@@ -46008,9 +46017,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
paramReference = paramDecl;
}
}
if (!hasInvalidReference && referencePath) { // Valid type parameter reference: type parameter is narrowable
const symbol = getResolvedSymbol(reference); // >> TODO: construct reference; get its symbol
if (symbol !== unknownSymbol) narrowableParams.push([typeParam, symbol, reference]);
if (!hasInvalidReference && referencePath) {
const symbolAndReference = constructNarrowableReference(paramReference!, referencePath);
if (symbolAndReference) {
if (symbolAndReference[0] && symbolAndReference[0] !== unknownSymbol) {
narrowableParams.push([typeParam, symbolAndReference[0], symbolAndReference[1]]);
}
}
}
}
}
@@ -46062,10 +46075,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
const typeArgs = (typeNode as TypeReferenceNode).typeArguments;
// Type arguments that reference `T`
const typeArgsReferenced = typeArgs?.filter(node => isTypeParameterReferenced(typeParam, node))
if (!typeArgsReferenced || typeArgsReferenced.length == 0) return true; // Type reference unrelated to `T`
if (typeArgsReferenced && typeArgsReferenced.length > 1) return false; // e.g. `Foo<T, T, ...>`
const typeArg = typeArgsReferenced[0];
const typeArgsReferencingT = typeArgs?.filter(node => isTypeParameterReferenced(typeParam, node))
if (!typeArgsReferencingT || typeArgsReferencingT.length == 0) return true; // Type reference unrelated to `T`
if (typeArgsReferencingT && typeArgsReferencingT.length > 1) return false; // e.g. `Foo<T, T, ...>`
const typeArg = typeArgsReferencingT[0];
if (!(typeArg.kind & SyntaxKind.TypeReference)) return false; // e.g. `Foo<Wrapper<T>, ...>`
if (!type.symbol || !type.symbol.declarations || type.symbol.declarations.length != 1) return false;
const typeDeclaration = type.symbol.declarations[0];
@@ -46081,7 +46094,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const typeArgIndex = typeArgs!.findIndex(arg => arg === typeArg);
const matchingTypeParamDecl = aliasDeclaration.typeParameters?.[typeArgIndex];
if (!matchingTypeParamDecl) return false; // Shouldn't happen, unless there is an error in the input program.
const matchingTypeParam = getTypeOfSymbol(getSymbolOfDeclaration(matchingTypeParamDecl)) as TypeParameter; // >> TODO: better way?
const matchingTypeParam = getDeclaredTypeOfTypeParameter(matchingTypeParamDecl.symbol);
return getValidTypeParameterReference(typeDeclaration, matchingTypeParam, path);
case SyntaxKind.InterfaceDeclaration:
const extendsTypes = flatMap((typeNode as InterfaceDeclaration).heritageClauses, clause => clause.types);
@@ -46129,13 +46142,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!isPropertySignature(member)) {
return false; // Unsupported reference to `T`, e.g. `[s: string]: T`.
}
if (!isIdentifier(member.name) && !isStringLiteral(member.name)) { // >> TODO: support number literal? others?
if (!isIdentifier(member.name) && !isStringLiteral(member.name)) { // >> TODO: support others e.g. computed property?
return false; // Unsupported property name, e.g. `[c]: T`
}
if (member.questionToken) {
// >> TODO: account for property optionality
}
const result = getValidTypeParameterReference(member.type!, typeParam, [member.name, ...path])
const result = getValidTypeParameterReference(member.type!, typeParam, [...path, member.name])
if (!result) {
return false;
}
@@ -46157,14 +46170,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// `constructNarrowableReference(`param: { "a b": T }`, ["a b"])` ==> `param["a b"]`
// `constructNarrowableReference(`{ b }: { b: T }`, [`b`])` ==> `b`
// `constructNarrowableReference(`{ a }: { a: { b: T } }`, [`a`, `b`])` ==> `a.b`
function constructNarrowableReference(paramDecl: ParameterDeclaration, path: Name[]): PropertyAccessExpression {
// >> TODO: impl
// >> TODO: consider if we'll be able to get the symbol at this constructed location...
// `constructNarrowableReference(`{ a: { b }} : { a: { b: T }} }`, [`a`, `b`])` ==> `b`
function constructNarrowableReference(paramDecl: ParameterDeclaration, path: Name[]): [Symbol, NarrowableReference] | undefined {
let currentName = paramDecl.name;
let i = 0;
for (; i < path.length; i++) {
if (isIdentifier(currentName)) {
break;
}
else if (isObjectBindingPattern(currentName)) {
const name = path[i];
let nameText: __String | undefined;
if (isIdentifier(name)) nameText = name.escapedText
else {
const rawText = getLiteralPropertyNameText(name);
if (rawText) nameText = escapeLeadingUnderscores(rawText);
}
// Find binding element corresponding to `name`.
const element = currentName.elements.find(element => {
const propertyName = getDestructuringPropertyName(element);
const propertyNameText = propertyName && escapeLeadingUnderscores(propertyName);
return nameText && propertyNameText && nameText === propertyNameText;
});
if (!element) {
return undefined; // Shouldn't happen unless the program has errors.
}
currentName = element.name;
}
else {
// Unsupported cases. Shouldn't happen unless the program has errors.
return undefined;
}
}
if (!isIdentifier(currentName)) {
return undefined; // Shouldn't happen unless the program has errors.
}
let result: NarrowableReference = factory.cloneNode(currentName);
const initialSymbol = getSymbolOfDeclaration(currentName.parent as ParameterDeclaration | BindingElement);
for (let j = i; j < path.length; j++) {
result = addName(result, path[j]);
}
return [initialSymbol, result];
}
function addName(exp: NarrowableReference, name: Name): NarrowableReference {
name = factory.cloneNode(name);
if (isIdentifier(name)) {
const accessExp = factory.createPropertyAccessExpression(exp, name);
setParent(name, accessExp);
setParent(exp, accessExp);
return accessExp;
}
else {
const accessExp = factory.createElementAccessExpression(exp, name);
setParent(name, accessExp);
setParent(exp, accessExp);
return accessExp;
}
}
}
/**
* Determines if the type parameter constraint allows for narrowing of that type parameter.
* This is true if:
@@ -0,0 +1,275 @@
dependentReturnType11.ts(36,34): error TS2339: Property 'prop1' does not exist on type 'Boolean'.
dependentReturnType11.ts(37,20): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(37,24): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(72,25): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(72,29): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(93,25): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(93,29): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(110,19): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(110,23): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(114,23): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(114,27): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(118,23): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(118,27): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(136,25): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(136,29): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(144,25): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(144,29): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(152,25): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(152,29): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(205,13): error TS2322: Type '1' is not assignable to type 'Ret<T>'.
dependentReturnType11.ts(207,9): error TS2322: Type '2' is not assignable to type 'Ret<T>'.
==== dependentReturnType11.ts (21 errors) ====
type Ret<T extends boolean> =
T extends true ? 1 :
T extends false ? 2 :
never;
// Tests for constructing narrowable reference.
function f1<T extends boolean>(param: T): Ret<T> {
return param ? 1 : 2;
}
function f2<T extends boolean>(param: { prop: T }): Ret<T> {
return param.prop ? 1 : 2;
}
function f3<T extends boolean>({ prop }: { prop: T }): Ret<T> {
return prop ? 1 : 2;
}
function f4<T extends boolean>({ prop1 }: { prop1: { prop2: T } }): Ret<T> {
return prop1.prop2 ? 1 : 2;
}
function f5<T extends boolean>(param: { prop1: { prop2: T } }): Ret<T> {
return param.prop1.prop2 ? 1 : 2;
}
function f6<T extends boolean>({ prop1: { prop2: a } }: { prop1: { prop2: T } }): Ret<T> {
return a ? 1 : 2;
}
function f7<T extends boolean>({ prop1: { prop2 } }: { prop1: { prop2: T } }): Ret<T> {
return prop2 ? 1 : 2;
}
function f8<T extends boolean>({ prop1 }: T): Ret<T> { // Bad.
~~~~~
!!! error TS2339: Property 'prop1' does not exist on type 'Boolean'.
return prop1 ? 1 : 2;
~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
function f9<T extends boolean>(param: { "some prop": T }): Ret<T> {
return param["some prop"] ? 1 : 2;
}
// Tests for detection of valid narrowable type parameter references.
function g1<T extends boolean>(param: T): Ret<T> {
return param ? 1 : 2;
}
function g2<T extends boolean>(param: { prop: T }): Ret<T> {
return param.prop ? 1 : 2;
}
class Dog {
bark(): void {}
}
class Cat {
meow(): void {}
}
type Type1<T> = { prop: T, prop2: Cat | Dog }
function g3<T extends boolean>(param: Type1<T>): Ret<T> {
return param.prop ? 1 : 2;
}
type TypeUnused<T> = string;
function g4<T extends boolean>(param: Type1<T>, other: TypeUnused<T>): Ret<T> { // Bad.
return param.prop ? 1 : 2;
~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
interface Type2<T extends boolean> {
prop: T,
[s: string]: boolean | undefined,
}
function g5<T extends boolean>(param: Type2<T>): Ret<T> {
return param.prop ? 1 : 2;
}
interface Type3<T extends boolean> {
prop: T,
}
interface Type3<T extends boolean> {
prop2: Cat | Dog,
}
function g6<T extends boolean>(param: Type3<T>): Ret<T> { // Unsupported for now: interface merging.
return param.prop ? 1 : 2;
~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
type Type4<T, S> = {
prop: T,
prop2: S[],
}
function g7<T extends boolean, S>(param: Type4<T, S>): Ret<T> {
return param.prop ? 1 : 2;
}
function g8<T extends boolean>(param: Type1<T> & { prop2: Cat | Dog }): Ret<T> {
return param.prop ? 1 : 2;
}
function g9<T extends boolean>([ prop ]: [T]): Ret<T> { // Unsupported.
return prop ? 1 : 2;
~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
function g10<T extends boolean>(param: [T]): Ret<T> { // Unsupported.
return param[0] ? 1 : 2;
~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
function g11<T extends boolean>(param: T[]): Ret<T> { // Bad.
return param[0] ? 1 : 2;
~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
type Type5<S> = {
prop: S,
prop2: string[],
}
function g12<T extends boolean>(param: Type5<T>): Ret<T> {
return param.prop ? 1 : 2;
}
type Type6<S> = {
prop: S,
prop2: S[],
}
function g13<T extends boolean>(param: Type6<T>): Ret<T> { // Bad.
return param.prop ? 1 : 2;
~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
type Type7<T> = {
[Key in "prop"]: T
}
function g14<T extends boolean>(param: Type7<T>): Ret<T> { // Unsupported.
return param.prop ? 1 : 2;
~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
class Class1<T> {
prop!: T;
}
function g15<T extends boolean>(param: Class1<T>): Ret<T> { // Unsupported.
return param.prop ? 1 : 2;
~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
type Type8<T> = {
prop: T,
}
type Type9<T> = {
prop2: T,
}
function g16<T extends boolean>(param: Type8<Type9<T>["prop2"]>): Ret<T> { // Unsupported.
return param.prop ? 1 : 2;
}
// Tests for shadowing and resolving the constructed narrowable reference.
function h1<T extends boolean>(param: T): Ret<T> {
if (param) {
const param = false;
return 1;
}
return 2;
}
function h2<T extends boolean>({ prop }: { prop: T}): Ret<T> {
if (prop) {
const prop = false;
return 1;
}
return 2;
}
function h3<T extends boolean>(param: { prop: T}): Ret<T> {
if (param.prop) {
const param = { prop: false };
return 1;
}
return 2;
}
function h4<T extends boolean>(param: { "some prop": T }): Ret<T> {
if (param["some prop"]) {
const param = { "some prop": false };
return 1;
}
return 2;
}
function h5<T extends boolean>(param: T): Ret<T> {
{
const param = true;
if (param) {
return 1; // Bad.
~~~~~~
!!! error TS2322: Type '1' is not assignable to type 'Ret<T>'.
}
return 2;
~~~~~~
!!! error TS2322: Type '2' is not assignable to type 'Ret<T>'.
}
}
@@ -0,0 +1,627 @@
//// [tests/cases/compiler/dependentReturnType11.ts] ////
=== dependentReturnType11.ts ===
type Ret<T extends boolean> =
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 0, 9))
T extends true ? 1 :
>T : Symbol(T, Decl(dependentReturnType11.ts, 0, 9))
T extends false ? 2 :
>T : Symbol(T, Decl(dependentReturnType11.ts, 0, 9))
never;
// Tests for constructing narrowable reference.
function f1<T extends boolean>(param: T): Ret<T> {
>f1 : Symbol(f1, Decl(dependentReturnType11.ts, 3, 10))
>T : Symbol(T, Decl(dependentReturnType11.ts, 7, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 7, 31))
>T : Symbol(T, Decl(dependentReturnType11.ts, 7, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 7, 12))
return param ? 1 : 2;
>param : Symbol(param, Decl(dependentReturnType11.ts, 7, 31))
}
function f2<T extends boolean>(param: { prop: T }): Ret<T> {
>f2 : Symbol(f2, Decl(dependentReturnType11.ts, 9, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 11, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 11, 31))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 11, 39))
>T : Symbol(T, Decl(dependentReturnType11.ts, 11, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 11, 12))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 11, 39))
>param : Symbol(param, Decl(dependentReturnType11.ts, 11, 31))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 11, 39))
}
function f3<T extends boolean>({ prop }: { prop: T }): Ret<T> {
>f3 : Symbol(f3, Decl(dependentReturnType11.ts, 13, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 15, 12))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 15, 32))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 15, 42))
>T : Symbol(T, Decl(dependentReturnType11.ts, 15, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 15, 12))
return prop ? 1 : 2;
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 15, 32))
}
function f4<T extends boolean>({ prop1 }: { prop1: { prop2: T } }): Ret<T> {
>f4 : Symbol(f4, Decl(dependentReturnType11.ts, 17, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 19, 12))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 19, 32))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 19, 43))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 19, 52))
>T : Symbol(T, Decl(dependentReturnType11.ts, 19, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 19, 12))
return prop1.prop2 ? 1 : 2;
>prop1.prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 19, 52))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 19, 32))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 19, 52))
}
function f5<T extends boolean>(param: { prop1: { prop2: T } }): Ret<T> {
>f5 : Symbol(f5, Decl(dependentReturnType11.ts, 21, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 23, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 23, 31))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 23, 39))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 23, 48))
>T : Symbol(T, Decl(dependentReturnType11.ts, 23, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 23, 12))
return param.prop1.prop2 ? 1 : 2;
>param.prop1.prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 23, 48))
>param.prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 23, 39))
>param : Symbol(param, Decl(dependentReturnType11.ts, 23, 31))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 23, 39))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 23, 48))
}
function f6<T extends boolean>({ prop1: { prop2: a } }: { prop1: { prop2: T } }): Ret<T> {
>f6 : Symbol(f6, Decl(dependentReturnType11.ts, 25, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 27, 12))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 27, 57))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 27, 66))
>a : Symbol(a, Decl(dependentReturnType11.ts, 27, 41))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 27, 57))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 27, 66))
>T : Symbol(T, Decl(dependentReturnType11.ts, 27, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 27, 12))
return a ? 1 : 2;
>a : Symbol(a, Decl(dependentReturnType11.ts, 27, 41))
}
function f7<T extends boolean>({ prop1: { prop2 } }: { prop1: { prop2: T } }): Ret<T> {
>f7 : Symbol(f7, Decl(dependentReturnType11.ts, 29, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 31, 12))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 31, 54))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 31, 41))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 31, 54))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 31, 63))
>T : Symbol(T, Decl(dependentReturnType11.ts, 31, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 31, 12))
return prop2 ? 1 : 2;
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 31, 41))
}
function f8<T extends boolean>({ prop1 }: T): Ret<T> { // Bad.
>f8 : Symbol(f8, Decl(dependentReturnType11.ts, 33, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 35, 12))
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 35, 32))
>T : Symbol(T, Decl(dependentReturnType11.ts, 35, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 35, 12))
return prop1 ? 1 : 2;
>prop1 : Symbol(prop1, Decl(dependentReturnType11.ts, 35, 32))
}
function f9<T extends boolean>(param: { "some prop": T }): Ret<T> {
>f9 : Symbol(f9, Decl(dependentReturnType11.ts, 37, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 39, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 39, 31))
>"some prop" : Symbol("some prop", Decl(dependentReturnType11.ts, 39, 39))
>T : Symbol(T, Decl(dependentReturnType11.ts, 39, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 39, 12))
return param["some prop"] ? 1 : 2;
>param : Symbol(param, Decl(dependentReturnType11.ts, 39, 31))
>"some prop" : Symbol("some prop", Decl(dependentReturnType11.ts, 39, 39))
}
// Tests for detection of valid narrowable type parameter references.
function g1<T extends boolean>(param: T): Ret<T> {
>g1 : Symbol(g1, Decl(dependentReturnType11.ts, 41, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 45, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 45, 31))
>T : Symbol(T, Decl(dependentReturnType11.ts, 45, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 45, 12))
return param ? 1 : 2;
>param : Symbol(param, Decl(dependentReturnType11.ts, 45, 31))
}
function g2<T extends boolean>(param: { prop: T }): Ret<T> {
>g2 : Symbol(g2, Decl(dependentReturnType11.ts, 47, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 49, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 49, 31))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 49, 39))
>T : Symbol(T, Decl(dependentReturnType11.ts, 49, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 49, 12))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 49, 39))
>param : Symbol(param, Decl(dependentReturnType11.ts, 49, 31))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 49, 39))
}
class Dog {
>Dog : Symbol(Dog, Decl(dependentReturnType11.ts, 51, 1))
bark(): void {}
>bark : Symbol(Dog.bark, Decl(dependentReturnType11.ts, 53, 11))
}
class Cat {
>Cat : Symbol(Cat, Decl(dependentReturnType11.ts, 55, 1))
meow(): void {}
>meow : Symbol(Cat.meow, Decl(dependentReturnType11.ts, 57, 11))
}
type Type1<T> = { prop: T, prop2: Cat | Dog }
>Type1 : Symbol(Type1, Decl(dependentReturnType11.ts, 60, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 62, 11))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 62, 17))
>T : Symbol(T, Decl(dependentReturnType11.ts, 62, 11))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 62, 26))
>Cat : Symbol(Cat, Decl(dependentReturnType11.ts, 55, 1))
>Dog : Symbol(Dog, Decl(dependentReturnType11.ts, 51, 1))
function g3<T extends boolean>(param: Type1<T>): Ret<T> {
>g3 : Symbol(g3, Decl(dependentReturnType11.ts, 62, 45))
>T : Symbol(T, Decl(dependentReturnType11.ts, 64, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 64, 31))
>Type1 : Symbol(Type1, Decl(dependentReturnType11.ts, 60, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 64, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 64, 12))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 62, 17))
>param : Symbol(param, Decl(dependentReturnType11.ts, 64, 31))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 62, 17))
}
type TypeUnused<T> = string;
>TypeUnused : Symbol(TypeUnused, Decl(dependentReturnType11.ts, 66, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 68, 16))
function g4<T extends boolean>(param: Type1<T>, other: TypeUnused<T>): Ret<T> { // Bad.
>g4 : Symbol(g4, Decl(dependentReturnType11.ts, 68, 28))
>T : Symbol(T, Decl(dependentReturnType11.ts, 70, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 70, 31))
>Type1 : Symbol(Type1, Decl(dependentReturnType11.ts, 60, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 70, 12))
>other : Symbol(other, Decl(dependentReturnType11.ts, 70, 47))
>TypeUnused : Symbol(TypeUnused, Decl(dependentReturnType11.ts, 66, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 70, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 70, 12))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 62, 17))
>param : Symbol(param, Decl(dependentReturnType11.ts, 70, 31))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 62, 17))
}
interface Type2<T extends boolean> {
>Type2 : Symbol(Type2, Decl(dependentReturnType11.ts, 72, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 74, 16))
prop: T,
>prop : Symbol(Type2.prop, Decl(dependentReturnType11.ts, 74, 36))
>T : Symbol(T, Decl(dependentReturnType11.ts, 74, 16))
[s: string]: boolean | undefined,
>s : Symbol(s, Decl(dependentReturnType11.ts, 76, 5))
}
function g5<T extends boolean>(param: Type2<T>): Ret<T> {
>g5 : Symbol(g5, Decl(dependentReturnType11.ts, 77, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 79, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 79, 31))
>Type2 : Symbol(Type2, Decl(dependentReturnType11.ts, 72, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 79, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 79, 12))
return param.prop ? 1 : 2;
>param.prop : Symbol(Type2.prop, Decl(dependentReturnType11.ts, 74, 36))
>param : Symbol(param, Decl(dependentReturnType11.ts, 79, 31))
>prop : Symbol(Type2.prop, Decl(dependentReturnType11.ts, 74, 36))
}
interface Type3<T extends boolean> {
>Type3 : Symbol(Type3, Decl(dependentReturnType11.ts, 81, 1), Decl(dependentReturnType11.ts, 85, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 83, 16), Decl(dependentReturnType11.ts, 87, 16))
prop: T,
>prop : Symbol(Type3.prop, Decl(dependentReturnType11.ts, 83, 36))
>T : Symbol(T, Decl(dependentReturnType11.ts, 83, 16), Decl(dependentReturnType11.ts, 87, 16))
}
interface Type3<T extends boolean> {
>Type3 : Symbol(Type3, Decl(dependentReturnType11.ts, 81, 1), Decl(dependentReturnType11.ts, 85, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 83, 16), Decl(dependentReturnType11.ts, 87, 16))
prop2: Cat | Dog,
>prop2 : Symbol(Type3.prop2, Decl(dependentReturnType11.ts, 87, 36))
>Cat : Symbol(Cat, Decl(dependentReturnType11.ts, 55, 1))
>Dog : Symbol(Dog, Decl(dependentReturnType11.ts, 51, 1))
}
function g6<T extends boolean>(param: Type3<T>): Ret<T> { // Unsupported for now: interface merging.
>g6 : Symbol(g6, Decl(dependentReturnType11.ts, 89, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 91, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 91, 31))
>Type3 : Symbol(Type3, Decl(dependentReturnType11.ts, 81, 1), Decl(dependentReturnType11.ts, 85, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 91, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 91, 12))
return param.prop ? 1 : 2;
>param.prop : Symbol(Type3.prop, Decl(dependentReturnType11.ts, 83, 36))
>param : Symbol(param, Decl(dependentReturnType11.ts, 91, 31))
>prop : Symbol(Type3.prop, Decl(dependentReturnType11.ts, 83, 36))
}
type Type4<T, S> = {
>Type4 : Symbol(Type4, Decl(dependentReturnType11.ts, 93, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 95, 11))
>S : Symbol(S, Decl(dependentReturnType11.ts, 95, 13))
prop: T,
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 95, 20))
>T : Symbol(T, Decl(dependentReturnType11.ts, 95, 11))
prop2: S[],
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 96, 12))
>S : Symbol(S, Decl(dependentReturnType11.ts, 95, 13))
}
function g7<T extends boolean, S>(param: Type4<T, S>): Ret<T> {
>g7 : Symbol(g7, Decl(dependentReturnType11.ts, 98, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 100, 12))
>S : Symbol(S, Decl(dependentReturnType11.ts, 100, 30))
>param : Symbol(param, Decl(dependentReturnType11.ts, 100, 34))
>Type4 : Symbol(Type4, Decl(dependentReturnType11.ts, 93, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 100, 12))
>S : Symbol(S, Decl(dependentReturnType11.ts, 100, 30))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 100, 12))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 95, 20))
>param : Symbol(param, Decl(dependentReturnType11.ts, 100, 34))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 95, 20))
}
function g8<T extends boolean>(param: Type1<T> & { prop2: Cat | Dog }): Ret<T> {
>g8 : Symbol(g8, Decl(dependentReturnType11.ts, 102, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 104, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 104, 31))
>Type1 : Symbol(Type1, Decl(dependentReturnType11.ts, 60, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 104, 12))
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 104, 50))
>Cat : Symbol(Cat, Decl(dependentReturnType11.ts, 55, 1))
>Dog : Symbol(Dog, Decl(dependentReturnType11.ts, 51, 1))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 104, 12))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 62, 17))
>param : Symbol(param, Decl(dependentReturnType11.ts, 104, 31))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 62, 17))
}
function g9<T extends boolean>([ prop ]: [T]): Ret<T> { // Unsupported.
>g9 : Symbol(g9, Decl(dependentReturnType11.ts, 106, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 108, 12))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 108, 32))
>T : Symbol(T, Decl(dependentReturnType11.ts, 108, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 108, 12))
return prop ? 1 : 2;
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 108, 32))
}
function g10<T extends boolean>(param: [T]): Ret<T> { // Unsupported.
>g10 : Symbol(g10, Decl(dependentReturnType11.ts, 110, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 112, 13))
>param : Symbol(param, Decl(dependentReturnType11.ts, 112, 32))
>T : Symbol(T, Decl(dependentReturnType11.ts, 112, 13))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 112, 13))
return param[0] ? 1 : 2;
>param : Symbol(param, Decl(dependentReturnType11.ts, 112, 32))
>0 : Symbol(0)
}
function g11<T extends boolean>(param: T[]): Ret<T> { // Bad.
>g11 : Symbol(g11, Decl(dependentReturnType11.ts, 114, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 116, 13))
>param : Symbol(param, Decl(dependentReturnType11.ts, 116, 32))
>T : Symbol(T, Decl(dependentReturnType11.ts, 116, 13))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 116, 13))
return param[0] ? 1 : 2;
>param : Symbol(param, Decl(dependentReturnType11.ts, 116, 32))
}
type Type5<S> = {
>Type5 : Symbol(Type5, Decl(dependentReturnType11.ts, 118, 1))
>S : Symbol(S, Decl(dependentReturnType11.ts, 120, 11))
prop: S,
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 120, 17))
>S : Symbol(S, Decl(dependentReturnType11.ts, 120, 11))
prop2: string[],
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 121, 12))
}
function g12<T extends boolean>(param: Type5<T>): Ret<T> {
>g12 : Symbol(g12, Decl(dependentReturnType11.ts, 123, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 125, 13))
>param : Symbol(param, Decl(dependentReturnType11.ts, 125, 32))
>Type5 : Symbol(Type5, Decl(dependentReturnType11.ts, 118, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 125, 13))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 125, 13))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 120, 17))
>param : Symbol(param, Decl(dependentReturnType11.ts, 125, 32))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 120, 17))
}
type Type6<S> = {
>Type6 : Symbol(Type6, Decl(dependentReturnType11.ts, 127, 1))
>S : Symbol(S, Decl(dependentReturnType11.ts, 129, 11))
prop: S,
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 129, 17))
>S : Symbol(S, Decl(dependentReturnType11.ts, 129, 11))
prop2: S[],
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 130, 12))
>S : Symbol(S, Decl(dependentReturnType11.ts, 129, 11))
}
function g13<T extends boolean>(param: Type6<T>): Ret<T> { // Bad.
>g13 : Symbol(g13, Decl(dependentReturnType11.ts, 132, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 134, 13))
>param : Symbol(param, Decl(dependentReturnType11.ts, 134, 32))
>Type6 : Symbol(Type6, Decl(dependentReturnType11.ts, 127, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 134, 13))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 134, 13))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 129, 17))
>param : Symbol(param, Decl(dependentReturnType11.ts, 134, 32))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 129, 17))
}
type Type7<T> = {
>Type7 : Symbol(Type7, Decl(dependentReturnType11.ts, 136, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 138, 11))
[Key in "prop"]: T
>Key : Symbol(Key, Decl(dependentReturnType11.ts, 139, 5))
>T : Symbol(T, Decl(dependentReturnType11.ts, 138, 11))
}
function g14<T extends boolean>(param: Type7<T>): Ret<T> { // Unsupported.
>g14 : Symbol(g14, Decl(dependentReturnType11.ts, 140, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 142, 13))
>param : Symbol(param, Decl(dependentReturnType11.ts, 142, 32))
>Type7 : Symbol(Type7, Decl(dependentReturnType11.ts, 136, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 142, 13))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 142, 13))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop)
>param : Symbol(param, Decl(dependentReturnType11.ts, 142, 32))
>prop : Symbol(prop)
}
class Class1<T> {
>Class1 : Symbol(Class1, Decl(dependentReturnType11.ts, 144, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 146, 13))
prop!: T;
>prop : Symbol(Class1.prop, Decl(dependentReturnType11.ts, 146, 17))
>T : Symbol(T, Decl(dependentReturnType11.ts, 146, 13))
}
function g15<T extends boolean>(param: Class1<T>): Ret<T> { // Unsupported.
>g15 : Symbol(g15, Decl(dependentReturnType11.ts, 148, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 150, 13))
>param : Symbol(param, Decl(dependentReturnType11.ts, 150, 32))
>Class1 : Symbol(Class1, Decl(dependentReturnType11.ts, 144, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 150, 13))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 150, 13))
return param.prop ? 1 : 2;
>param.prop : Symbol(Class1.prop, Decl(dependentReturnType11.ts, 146, 17))
>param : Symbol(param, Decl(dependentReturnType11.ts, 150, 32))
>prop : Symbol(Class1.prop, Decl(dependentReturnType11.ts, 146, 17))
}
type Type8<T> = {
>Type8 : Symbol(Type8, Decl(dependentReturnType11.ts, 152, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 154, 11))
prop: T,
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 154, 17))
>T : Symbol(T, Decl(dependentReturnType11.ts, 154, 11))
}
type Type9<T> = {
>Type9 : Symbol(Type9, Decl(dependentReturnType11.ts, 156, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 158, 11))
prop2: T,
>prop2 : Symbol(prop2, Decl(dependentReturnType11.ts, 158, 17))
>T : Symbol(T, Decl(dependentReturnType11.ts, 158, 11))
}
function g16<T extends boolean>(param: Type8<Type9<T>["prop2"]>): Ret<T> { // Unsupported.
>g16 : Symbol(g16, Decl(dependentReturnType11.ts, 160, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 162, 13))
>param : Symbol(param, Decl(dependentReturnType11.ts, 162, 32))
>Type8 : Symbol(Type8, Decl(dependentReturnType11.ts, 152, 1))
>Type9 : Symbol(Type9, Decl(dependentReturnType11.ts, 156, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 162, 13))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 162, 13))
return param.prop ? 1 : 2;
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 154, 17))
>param : Symbol(param, Decl(dependentReturnType11.ts, 162, 32))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 154, 17))
}
// Tests for shadowing and resolving the constructed narrowable reference.
function h1<T extends boolean>(param: T): Ret<T> {
>h1 : Symbol(h1, Decl(dependentReturnType11.ts, 164, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 168, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 168, 31))
>T : Symbol(T, Decl(dependentReturnType11.ts, 168, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 168, 12))
if (param) {
>param : Symbol(param, Decl(dependentReturnType11.ts, 168, 31))
const param = false;
>param : Symbol(param, Decl(dependentReturnType11.ts, 170, 13))
return 1;
}
return 2;
}
function h2<T extends boolean>({ prop }: { prop: T}): Ret<T> {
>h2 : Symbol(h2, Decl(dependentReturnType11.ts, 174, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 176, 12))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 176, 32))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 176, 42))
>T : Symbol(T, Decl(dependentReturnType11.ts, 176, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 176, 12))
if (prop) {
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 176, 32))
const prop = false;
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 178, 13))
return 1;
}
return 2;
}
function h3<T extends boolean>(param: { prop: T}): Ret<T> {
>h3 : Symbol(h3, Decl(dependentReturnType11.ts, 182, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 184, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 184, 31))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 184, 39))
>T : Symbol(T, Decl(dependentReturnType11.ts, 184, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 184, 12))
if (param.prop) {
>param.prop : Symbol(prop, Decl(dependentReturnType11.ts, 184, 39))
>param : Symbol(param, Decl(dependentReturnType11.ts, 184, 31))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 184, 39))
const param = { prop: false };
>param : Symbol(param, Decl(dependentReturnType11.ts, 186, 13))
>prop : Symbol(prop, Decl(dependentReturnType11.ts, 186, 23))
return 1;
}
return 2;
}
function h4<T extends boolean>(param: { "some prop": T }): Ret<T> {
>h4 : Symbol(h4, Decl(dependentReturnType11.ts, 190, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 192, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 192, 31))
>"some prop" : Symbol("some prop", Decl(dependentReturnType11.ts, 192, 39))
>T : Symbol(T, Decl(dependentReturnType11.ts, 192, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 192, 12))
if (param["some prop"]) {
>param : Symbol(param, Decl(dependentReturnType11.ts, 192, 31))
>"some prop" : Symbol("some prop", Decl(dependentReturnType11.ts, 192, 39))
const param = { "some prop": false };
>param : Symbol(param, Decl(dependentReturnType11.ts, 194, 13))
>"some prop" : Symbol("some prop", Decl(dependentReturnType11.ts, 194, 23))
return 1;
}
return 2;
}
function h5<T extends boolean>(param: T): Ret<T> {
>h5 : Symbol(h5, Decl(dependentReturnType11.ts, 198, 1))
>T : Symbol(T, Decl(dependentReturnType11.ts, 200, 12))
>param : Symbol(param, Decl(dependentReturnType11.ts, 200, 31))
>T : Symbol(T, Decl(dependentReturnType11.ts, 200, 12))
>Ret : Symbol(Ret, Decl(dependentReturnType11.ts, 0, 0))
>T : Symbol(T, Decl(dependentReturnType11.ts, 200, 12))
{
const param = true;
>param : Symbol(param, Decl(dependentReturnType11.ts, 202, 13))
if (param) {
>param : Symbol(param, Decl(dependentReturnType11.ts, 202, 13))
return 1; // Bad.
}
return 2;
}
}
@@ -0,0 +1,831 @@
//// [tests/cases/compiler/dependentReturnType11.ts] ////
=== dependentReturnType11.ts ===
type Ret<T extends boolean> =
>Ret : Ret<T>
> : ^^^^^^
T extends true ? 1 :
>true : true
> : ^^^^
T extends false ? 2 :
>false : false
> : ^^^^^
never;
// Tests for constructing narrowable reference.
function f1<T extends boolean>(param: T): Ret<T> {
>f1 : <T extends boolean>(param: T) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : T
> : ^
return param ? 1 : 2;
>param ? 1 : 2 : 1 | 2
> : ^^^^^
>param : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function f2<T extends boolean>(param: { prop: T }): Ret<T> {
>f2 : <T extends boolean>(param: { prop: T; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : { prop: T; }
> : ^^^^^^^^ ^^^
>prop : T
> : ^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : { prop: T; }
> : ^^^^^^^^ ^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function f3<T extends boolean>({ prop }: { prop: T }): Ret<T> {
>f3 : <T extends boolean>({ prop }: { prop: T; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>prop : T
> : ^
>prop : T
> : ^
return prop ? 1 : 2;
>prop ? 1 : 2 : 1 | 2
> : ^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function f4<T extends boolean>({ prop1 }: { prop1: { prop2: T } }): Ret<T> {
>f4 : <T extends boolean>({ prop1 }: { prop1: { prop2: T; }; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>prop1 : { prop2: T; }
> : ^^^^^^^^^ ^^^
>prop1 : { prop2: T; }
> : ^^^^^^^^^ ^^^
>prop2 : T
> : ^
return prop1.prop2 ? 1 : 2;
>prop1.prop2 ? 1 : 2 : 1 | 2
> : ^^^^^
>prop1.prop2 : T
> : ^
>prop1 : { prop2: T; }
> : ^^^^^^^^^ ^^^
>prop2 : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function f5<T extends boolean>(param: { prop1: { prop2: T } }): Ret<T> {
>f5 : <T extends boolean>(param: { prop1: { prop2: T; }; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : { prop1: { prop2: T; }; }
> : ^^^^^^^^^ ^^^
>prop1 : { prop2: T; }
> : ^^^^^^^^^ ^^^
>prop2 : T
> : ^
return param.prop1.prop2 ? 1 : 2;
>param.prop1.prop2 ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop1.prop2 : T
> : ^
>param.prop1 : { prop2: T; }
> : ^^^^^^^^^ ^^^
>param : { prop1: { prop2: T; }; }
> : ^^^^^^^^^ ^^^
>prop1 : { prop2: T; }
> : ^^^^^^^^^ ^^^
>prop2 : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function f6<T extends boolean>({ prop1: { prop2: a } }: { prop1: { prop2: T } }): Ret<T> {
>f6 : <T extends boolean>({ prop1: { prop2: a } }: { prop1: { prop2: T; }; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>prop1 : any
> : ^^^
>prop2 : any
> : ^^^
>a : T
> : ^
>prop1 : { prop2: T; }
> : ^^^^^^^^^ ^^^
>prop2 : T
> : ^
return a ? 1 : 2;
>a ? 1 : 2 : 1 | 2
> : ^^^^^
>a : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function f7<T extends boolean>({ prop1: { prop2 } }: { prop1: { prop2: T } }): Ret<T> {
>f7 : <T extends boolean>({ prop1: { prop2 } }: { prop1: { prop2: T; }; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>prop1 : any
> : ^^^
>prop2 : T
> : ^
>prop1 : { prop2: T; }
> : ^^^^^^^^^ ^^^
>prop2 : T
> : ^
return prop2 ? 1 : 2;
>prop2 ? 1 : 2 : 1 | 2
> : ^^^^^
>prop2 : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function f8<T extends boolean>({ prop1 }: T): Ret<T> { // Bad.
>f8 : <T extends boolean>({ prop1 }: T) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>prop1 : any
> : ^^^
return prop1 ? 1 : 2;
>prop1 ? 1 : 2 : 1 | 2
> : ^^^^^
>prop1 : any
> : ^^^
>1 : 1
> : ^
>2 : 2
> : ^
}
function f9<T extends boolean>(param: { "some prop": T }): Ret<T> {
>f9 : <T extends boolean>(param: { "some prop": T; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : { "some prop": T; }
> : ^^^^^^^^^^^^^^^ ^^^
>"some prop" : T
> : ^
return param["some prop"] ? 1 : 2;
>param["some prop"] ? 1 : 2 : 1 | 2
> : ^^^^^
>param["some prop"] : T
> : ^
>param : { "some prop": T; }
> : ^^^^^^^^^^^^^^^ ^^^
>"some prop" : "some prop"
> : ^^^^^^^^^^^
>1 : 1
> : ^
>2 : 2
> : ^
}
// Tests for detection of valid narrowable type parameter references.
function g1<T extends boolean>(param: T): Ret<T> {
>g1 : <T extends boolean>(param: T) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : T
> : ^
return param ? 1 : 2;
>param ? 1 : 2 : 1 | 2
> : ^^^^^
>param : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function g2<T extends boolean>(param: { prop: T }): Ret<T> {
>g2 : <T extends boolean>(param: { prop: T; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : { prop: T; }
> : ^^^^^^^^ ^^^
>prop : T
> : ^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : { prop: T; }
> : ^^^^^^^^ ^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
class Dog {
>Dog : Dog
> : ^^^
bark(): void {}
>bark : () => void
> : ^^^^^^
}
class Cat {
>Cat : Cat
> : ^^^
meow(): void {}
>meow : () => void
> : ^^^^^^
}
type Type1<T> = { prop: T, prop2: Cat | Dog }
>Type1 : Type1<T>
> : ^^^^^^^^
>prop : T
> : ^
>prop2 : Dog | Cat
> : ^^^^^^^^^
function g3<T extends boolean>(param: Type1<T>): Ret<T> {
>g3 : <T extends boolean>(param: Type1<T>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : Type1<T>
> : ^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type1<T>
> : ^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
type TypeUnused<T> = string;
>TypeUnused : string
> : ^^^^^^
function g4<T extends boolean>(param: Type1<T>, other: TypeUnused<T>): Ret<T> { // Bad.
>g4 : <T extends boolean>(param: Type1<T>, other: TypeUnused<T>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^
>param : Type1<T>
> : ^^^^^^^^
>other : string
> : ^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type1<T>
> : ^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
interface Type2<T extends boolean> {
prop: T,
>prop : T
> : ^
[s: string]: boolean | undefined,
>s : string
> : ^^^^^^
}
function g5<T extends boolean>(param: Type2<T>): Ret<T> {
>g5 : <T extends boolean>(param: Type2<T>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : Type2<T>
> : ^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type2<T>
> : ^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
interface Type3<T extends boolean> {
prop: T,
>prop : T
> : ^
}
interface Type3<T extends boolean> {
prop2: Cat | Dog,
>prop2 : Dog | Cat
> : ^^^^^^^^^
}
function g6<T extends boolean>(param: Type3<T>): Ret<T> { // Unsupported for now: interface merging.
>g6 : <T extends boolean>(param: Type3<T>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : Type3<T>
> : ^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type3<T>
> : ^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
type Type4<T, S> = {
>Type4 : Type4<T, S>
> : ^^^^^^^^^^^
prop: T,
>prop : T
> : ^
prop2: S[],
>prop2 : S[]
> : ^^^
}
function g7<T extends boolean, S>(param: Type4<T, S>): Ret<T> {
>g7 : <T extends boolean, S>(param: Type4<T, S>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^
>param : Type4<T, S>
> : ^^^^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type4<T, S>
> : ^^^^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function g8<T extends boolean>(param: Type1<T> & { prop2: Cat | Dog }): Ret<T> {
>g8 : <T extends boolean>(param: Type1<T> & { prop2: Cat | Dog; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : Type1<T> & { prop2: Cat | Dog; }
> : ^^^^^^^^^^^^^^^^^^^^ ^^^
>prop2 : Dog | Cat
> : ^^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type1<T> & { prop2: Cat | Dog; }
> : ^^^^^^^^^^^^^^^^^^^^ ^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function g9<T extends boolean>([ prop ]: [T]): Ret<T> { // Unsupported.
>g9 : <T extends boolean>([prop]: [T]) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>prop : T
> : ^
return prop ? 1 : 2;
>prop ? 1 : 2 : 1 | 2
> : ^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function g10<T extends boolean>(param: [T]): Ret<T> { // Unsupported.
>g10 : <T extends boolean>(param: [T]) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : [T]
> : ^^^
return param[0] ? 1 : 2;
>param[0] ? 1 : 2 : 1 | 2
> : ^^^^^
>param[0] : T
> : ^
>param : [T]
> : ^^^
>0 : 0
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
function g11<T extends boolean>(param: T[]): Ret<T> { // Bad.
>g11 : <T extends boolean>(param: T[]) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : T[]
> : ^^^
return param[0] ? 1 : 2;
>param[0] ? 1 : 2 : 1 | 2
> : ^^^^^
>param[0] : T
> : ^
>param : T[]
> : ^^^
>0 : 0
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
type Type5<S> = {
>Type5 : Type5<S>
> : ^^^^^^^^
prop: S,
>prop : S
> : ^
prop2: string[],
>prop2 : string[]
> : ^^^^^^^^
}
function g12<T extends boolean>(param: Type5<T>): Ret<T> {
>g12 : <T extends boolean>(param: Type5<T>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : Type5<T>
> : ^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type5<T>
> : ^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
type Type6<S> = {
>Type6 : Type6<S>
> : ^^^^^^^^
prop: S,
>prop : S
> : ^
prop2: S[],
>prop2 : S[]
> : ^^^
}
function g13<T extends boolean>(param: Type6<T>): Ret<T> { // Bad.
>g13 : <T extends boolean>(param: Type6<T>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : Type6<T>
> : ^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type6<T>
> : ^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
type Type7<T> = {
>Type7 : Type7<T>
> : ^^^^^^^^
[Key in "prop"]: T
}
function g14<T extends boolean>(param: Type7<T>): Ret<T> { // Unsupported.
>g14 : <T extends boolean>(param: Type7<T>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : Type7<T>
> : ^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type7<T>
> : ^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
class Class1<T> {
>Class1 : Class1<T>
> : ^^^^^^^^^
prop!: T;
>prop : T
> : ^
}
function g15<T extends boolean>(param: Class1<T>): Ret<T> { // Unsupported.
>g15 : <T extends boolean>(param: Class1<T>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : Class1<T>
> : ^^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Class1<T>
> : ^^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
type Type8<T> = {
>Type8 : Type8<T>
> : ^^^^^^^^
prop: T,
>prop : T
> : ^
}
type Type9<T> = {
>Type9 : Type9<T>
> : ^^^^^^^^
prop2: T,
>prop2 : T
> : ^
}
function g16<T extends boolean>(param: Type8<Type9<T>["prop2"]>): Ret<T> { // Unsupported.
>g16 : <T extends boolean>(param: Type8<Type9<T>["prop2"]>) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : Type8<T>
> : ^^^^^^^^
return param.prop ? 1 : 2;
>param.prop ? 1 : 2 : 1 | 2
> : ^^^^^
>param.prop : T
> : ^
>param : Type8<T>
> : ^^^^^^^^
>prop : T
> : ^
>1 : 1
> : ^
>2 : 2
> : ^
}
// Tests for shadowing and resolving the constructed narrowable reference.
function h1<T extends boolean>(param: T): Ret<T> {
>h1 : <T extends boolean>(param: T) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : T
> : ^
if (param) {
>param : T
> : ^
const param = false;
>param : false
> : ^^^^^
>false : false
> : ^^^^^
return 1;
>1 : 1
> : ^
}
return 2;
>2 : 2
> : ^
}
function h2<T extends boolean>({ prop }: { prop: T}): Ret<T> {
>h2 : <T extends boolean>({ prop }: { prop: T; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>prop : T
> : ^
>prop : T
> : ^
if (prop) {
>prop : T
> : ^
const prop = false;
>prop : false
> : ^^^^^
>false : false
> : ^^^^^
return 1;
>1 : 1
> : ^
}
return 2;
>2 : 2
> : ^
}
function h3<T extends boolean>(param: { prop: T}): Ret<T> {
>h3 : <T extends boolean>(param: { prop: T; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : { prop: T; }
> : ^^^^^^^^ ^^^
>prop : T
> : ^
if (param.prop) {
>param.prop : T
> : ^
>param : { prop: T; }
> : ^^^^^^^^ ^^^
>prop : T
> : ^
const param = { prop: false };
>param : { prop: boolean; }
> : ^^^^^^^^^^^^^^^^^^
>{ prop: false } : { prop: boolean; }
> : ^^^^^^^^^^^^^^^^^^
>prop : boolean
> : ^^^^^^^
>false : false
> : ^^^^^
return 1;
>1 : 1
> : ^
}
return 2;
>2 : 2
> : ^
}
function h4<T extends boolean>(param: { "some prop": T }): Ret<T> {
>h4 : <T extends boolean>(param: { "some prop": T; }) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : { "some prop": T; }
> : ^^^^^^^^^^^^^^^ ^^^
>"some prop" : T
> : ^
if (param["some prop"]) {
>param["some prop"] : T
> : ^
>param : { "some prop": T; }
> : ^^^^^^^^^^^^^^^ ^^^
>"some prop" : "some prop"
> : ^^^^^^^^^^^
const param = { "some prop": false };
>param : { "some prop": boolean; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>{ "some prop": false } : { "some prop": boolean; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>"some prop" : boolean
> : ^^^^^^^
>false : false
> : ^^^^^
return 1;
>1 : 1
> : ^
}
return 2;
>2 : 2
> : ^
}
function h5<T extends boolean>(param: T): Ret<T> {
>h5 : <T extends boolean>(param: T) => Ret<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>param : T
> : ^
{
const param = true;
>param : true
> : ^^^^
>true : true
> : ^^^^
if (param) {
>param : true
> : ^^^^
return 1; // Bad.
>1 : 1
> : ^
}
return 2;
>2 : 2
> : ^
}
}
@@ -0,0 +1,212 @@
// @noEmit: true
// @strict: true
type Ret<T extends boolean> =
T extends true ? 1 :
T extends false ? 2 :
never;
// Tests for constructing narrowable reference.
function f1<T extends boolean>(param: T): Ret<T> {
return param ? 1 : 2;
}
function f2<T extends boolean>(param: { prop: T }): Ret<T> {
return param.prop ? 1 : 2;
}
function f3<T extends boolean>({ prop }: { prop: T }): Ret<T> {
return prop ? 1 : 2;
}
function f4<T extends boolean>({ prop1 }: { prop1: { prop2: T } }): Ret<T> {
return prop1.prop2 ? 1 : 2;
}
function f5<T extends boolean>(param: { prop1: { prop2: T } }): Ret<T> {
return param.prop1.prop2 ? 1 : 2;
}
function f6<T extends boolean>({ prop1: { prop2: a } }: { prop1: { prop2: T } }): Ret<T> {
return a ? 1 : 2;
}
function f7<T extends boolean>({ prop1: { prop2 } }: { prop1: { prop2: T } }): Ret<T> {
return prop2 ? 1 : 2;
}
function f8<T extends boolean>({ prop1 }: T): Ret<T> { // Bad.
return prop1 ? 1 : 2;
}
function f9<T extends boolean>(param: { "some prop": T }): Ret<T> {
return param["some prop"] ? 1 : 2;
}
// Tests for detection of valid narrowable type parameter references.
function g1<T extends boolean>(param: T): Ret<T> {
return param ? 1 : 2;
}
function g2<T extends boolean>(param: { prop: T }): Ret<T> {
return param.prop ? 1 : 2;
}
class Dog {
bark(): void {}
}
class Cat {
meow(): void {}
}
type Type1<T> = { prop: T, prop2: Cat | Dog }
function g3<T extends boolean>(param: Type1<T>): Ret<T> {
return param.prop ? 1 : 2;
}
type TypeUnused<T> = string;
function g4<T extends boolean>(param: Type1<T>, other: TypeUnused<T>): Ret<T> { // Bad.
return param.prop ? 1 : 2;
}
interface Type2<T extends boolean> {
prop: T,
[s: string]: boolean | undefined,
}
function g5<T extends boolean>(param: Type2<T>): Ret<T> {
return param.prop ? 1 : 2;
}
interface Type3<T extends boolean> {
prop: T,
}
interface Type3<T extends boolean> {
prop2: Cat | Dog,
}
function g6<T extends boolean>(param: Type3<T>): Ret<T> { // Unsupported for now: interface merging.
return param.prop ? 1 : 2;
}
type Type4<T, S> = {
prop: T,
prop2: S[],
}
function g7<T extends boolean, S>(param: Type4<T, S>): Ret<T> {
return param.prop ? 1 : 2;
}
function g8<T extends boolean>(param: Type1<T> & { prop2: Cat | Dog }): Ret<T> {
return param.prop ? 1 : 2;
}
function g9<T extends boolean>([ prop ]: [T]): Ret<T> { // Unsupported.
return prop ? 1 : 2;
}
function g10<T extends boolean>(param: [T]): Ret<T> { // Unsupported.
return param[0] ? 1 : 2;
}
function g11<T extends boolean>(param: T[]): Ret<T> { // Bad.
return param[0] ? 1 : 2;
}
type Type5<S> = {
prop: S,
prop2: string[],
}
function g12<T extends boolean>(param: Type5<T>): Ret<T> {
return param.prop ? 1 : 2;
}
type Type6<S> = {
prop: S,
prop2: S[],
}
function g13<T extends boolean>(param: Type6<T>): Ret<T> { // Bad.
return param.prop ? 1 : 2;
}
type Type7<T> = {
[Key in "prop"]: T
}
function g14<T extends boolean>(param: Type7<T>): Ret<T> { // Unsupported.
return param.prop ? 1 : 2;
}
class Class1<T> {
prop!: T;
}
function g15<T extends boolean>(param: Class1<T>): Ret<T> { // Unsupported.
return param.prop ? 1 : 2;
}
type Type8<T> = {
prop: T,
}
type Type9<T> = {
prop2: T,
}
function g16<T extends boolean>(param: Type8<Type9<T>["prop2"]>): Ret<T> { // Unsupported.
return param.prop ? 1 : 2;
}
// Tests for shadowing and resolving the constructed narrowable reference.
function h1<T extends boolean>(param: T): Ret<T> {
if (param) {
const param = false;
return 1;
}
return 2;
}
function h2<T extends boolean>({ prop }: { prop: T}): Ret<T> {
if (prop) {
const prop = false;
return 1;
}
return 2;
}
function h3<T extends boolean>(param: { prop: T}): Ret<T> {
if (param.prop) {
const param = { prop: false };
return 1;
}
return 2;
}
function h4<T extends boolean>(param: { "some prop": T }): Ret<T> {
if (param["some prop"]) {
const param = { "some prop": false };
return 1;
}
return 2;
}
function h5<T extends boolean>(param: T): Ret<T> {
{
const param = true;
if (param) {
return 1; // Bad.
}
return 2;
}
}