CFA for dependent parameters typed by generic constraints (#48411)

* Obtain apparent type in parameter destructuring check

* Add regression test
This commit is contained in:
Anders Hejlsberg 2022-03-30 16:33:01 -07:00 committed by GitHub
parent 3f483d87b4
commit fd601ddf20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 1 deletions

View File

@ -25450,7 +25450,7 @@ namespace ts {
if (func.parameters.length >= 2 && isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
const contextualSignature = getContextualSignature(func);
if (contextualSignature && contextualSignature.parameters.length === 1 && signatureHasRestParameter(contextualSignature)) {
const restType = getTypeOfSymbol(contextualSignature.parameters[0]);
const restType = getReducedApparentType(getTypeOfSymbol(contextualSignature.parameters[0]));
if (restType.flags & TypeFlags.Union && everyType(restType, isTupleType) && !isSymbolAssigned(symbol)) {
const narrowedType = getFlowTypeOfReference(func, restType, restType, /*flowContainer*/ undefined, location.flowNode);
const index = func.parameters.indexOf(declaration) - (getThisParameter(func) ? 1 : 0);

View File

@ -295,6 +295,19 @@ let fooAsyncGenM: FooAsyncGenMethod = {
}
}
};
// Repro from #48345
type Func = <T extends ["a", number] | ["b", string]>(...args: T) => void;
const f60: Func = (kind, payload) => {
if (kind === "a") {
payload.toFixed(); // error
}
if (kind === "b") {
payload.toUpperCase(); // error
}
};
//// [dependentDestructuredVariables.js]
@ -529,6 +542,14 @@ let fooAsyncGenM = {
});
}
};
const f60 = (kind, payload) => {
if (kind === "a") {
payload.toFixed(); // error
}
if (kind === "b") {
payload.toUpperCase(); // error
}
};
//// [dependentDestructuredVariables.d.ts]
@ -644,3 +665,5 @@ declare type FooAsyncGenMethod = {
]): AsyncGenerator<any, any, any>;
};
declare let fooAsyncGenM: FooAsyncGenMethod;
declare type Func = <T extends ["a", number] | ["b", string]>(...args: T) => void;
declare const f60: Func;

View File

@ -752,3 +752,35 @@ let fooAsyncGenM: FooAsyncGenMethod = {
}
};
// Repro from #48345
type Func = <T extends ["a", number] | ["b", string]>(...args: T) => void;
>Func : Symbol(Func, Decl(dependentDestructuredVariables.ts, 295, 2))
>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 299, 13))
>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 299, 54))
>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 299, 13))
const f60: Func = (kind, payload) => {
>f60 : Symbol(f60, Decl(dependentDestructuredVariables.ts, 301, 5))
>Func : Symbol(Func, Decl(dependentDestructuredVariables.ts, 295, 2))
>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 301, 19))
>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 301, 24))
if (kind === "a") {
>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 301, 19))
payload.toFixed(); // error
>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 301, 24))
>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
}
if (kind === "b") {
>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 301, 19))
payload.toUpperCase(); // error
>payload.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 301, 24))
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
}
};

View File

@ -855,3 +855,39 @@ let fooAsyncGenM: FooAsyncGenMethod = {
}
};
// Repro from #48345
type Func = <T extends ["a", number] | ["b", string]>(...args: T) => void;
>Func : Func
>args : T
const f60: Func = (kind, payload) => {
>f60 : Func
>(kind, payload) => { if (kind === "a") { payload.toFixed(); // error } if (kind === "b") { payload.toUpperCase(); // error }} : <T extends ["a", number] | ["b", string]>(kind: T[0], payload: T[1]) => void
>kind : T[0]
>payload : T[1]
if (kind === "a") {
>kind === "a" : boolean
>kind : "a" | "b"
>"a" : "a"
payload.toFixed(); // error
>payload.toFixed() : string
>payload.toFixed : (fractionDigits?: number | undefined) => string
>payload : number
>toFixed : (fractionDigits?: number | undefined) => string
}
if (kind === "b") {
>kind === "b" : boolean
>kind : "a" | "b"
>"b" : "b"
payload.toUpperCase(); // error
>payload.toUpperCase() : string
>payload.toUpperCase : () => string
>payload : string
>toUpperCase : () => string
}
};

View File

@ -299,3 +299,16 @@ let fooAsyncGenM: FooAsyncGenMethod = {
}
}
};
// Repro from #48345
type Func = <T extends ["a", number] | ["b", string]>(...args: T) => void;
const f60: Func = (kind, payload) => {
if (kind === "a") {
payload.toFixed(); // error
}
if (kind === "b") {
payload.toUpperCase(); // error
}
};