Repository navigation
Type predicate doesn't narrow down function overload (but assertion works)Β #58660
Copy link
Copy link
Closed as not planned
Closed as not planned
Copy link
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixed
Description
π Search Terms
type predicate, function overload, discriminating unions
π Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about method overload, unions
β― Playground Link
π» Code
type A_T = `A${string}`;
type B_T = `B${string}`;
type A_non_literal = 'ASD';
type B_non_literal = 'BSD';
const typePredicateA_non_literal = (val: any): val is A_non_literal => val.startsWith('A');
const typePredicateB_non_literal = (val: any): val is B_non_literal => val.startsWith('A');
function fntypePredicateA_non_literal(val: any): val is A_non_literal { return val.startsWith('A')};
function assertIsA_non_literal(val: any): asserts val is A_non_literal {
if (!typePredicateA(val)) {
throw new Error("Not a string!");
}
}
const typePredicateA = (val: any): val is A_T => val.startsWith('A');
const typePredicateB = (val: any): val is B_T => val.startsWith('B');
function fntypePredicateA(val: any): val is A_T { return val.startsWith('A');}
function assertIsA(val: any): asserts val is A_T {
if (!typePredicateA(val)) {
throw new Error("Not a string!");
}
}
function assertIsB(val: any): asserts val is B_T {
if (!typePredicateB(val)) {
throw new Error("Not a string!");
}
}
function createAorB(a: A_T, p0: number): number
function createAorB(b: B_T, p0: string): number
function createAorB(...[aOrB, p0]: [a: A_T, p0: number] | [b: B_T, p0: string] ): number {
if(typePredicateA(aOrB)){
console.log(Math.sqrt(p0)); // this throws compilation error
}
if(fntypePredicateA(aOrB)){
console.log(Math.sqrt(p0)); // this throws compilation error
}
assertIsA(aOrB);
console.log(Math.sqrt(p0));
return 0;
}
function create2AorB(a: A_non_literal, p0: number): number
function create2AorB(b: B_non_literal, p0: string): number
function create2AorB(...[aOrB, p0]: [a: A_non_literal, p0: number] | [b: B_non_literal, p0: string] ): number {
if(typePredicateA_non_literal(aOrB)){
console.log(Math.sqrt(p0)); // this throws compilation error
}
if(fntypePredicateA_non_literal(aOrB)){
console.log(Math.sqrt(p0)); // this throws compilation error
}
assertIsA_non_literal(aOrB);
console.log(Math.sqrt(p0));
return 0;
}π Actual behavior
After the type predicate, the second parameter isn't narrowed down to number, hence the error:
Argument of type 'string | number' is not assignable to parameter of type 'number'.
Type 'string' is not assignable to type 'number'.After the assertion, the code works as expected.
π Expected behavior
Type predicate to do the same narrowing as type assertion.
Additional information about the issue
No response
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixed
Activity
jcalz commentedon May 26, 2024
I don't see what this has to do with overloads, per se... you could remove those call signatures and the problem persists.
Looks like #46266 (comment) alludes to this... type predicates don't seem to work to discriminate destructured discriminated unions. Not sure if there's another issue open for it somewhere.
eachirei commentedon May 27, 2024
hey Joe Calzaretta (@jcalz)! you're correct, I just assumed that maybe there's some special logic that's used for choosing the overload. What I find surprising is that type assertion works. Would it be possible to replicate this behavior for type predicates?
fatcerberus commentedon May 27, 2024
Overloads only matter for the caller. The type checker doesn't care about any overloads when checking the function body (which is why you need a separate implementation signature); what narrowing you do see here, with the assertion function, is just normal discriminated union narrowing. If you were to declare the implementation as, e.g.
(ab: string, p0: string | number)then you wouldn't have a discriminated union anymore and would no longer be able to narrowp0based onabat all.Anyway, it's likely just a bug that the assertion works but the type predicate doesn't.
RyanCavanaugh commentedon Jun 6, 2024
Please provide a minimal repro; this doesn't sound based on the description like it needs 70 lines to demonstrate
fuxichen commentedon Jun 7, 2024
Why can't I deduce the type of data??
Please help to see why the type of data cannot be inferred,
As shown in the following demo:
Function overload has restricted the input type, if
type=TestTypeWhen A, the data must beTypeAData.I think
type=TestTypewas determined through the switch At time A, it should be inferred thatdata=TypeADatahttps://www.typescriptlang.org/play/?ts=5.4.5#code/KYOwrgtgBAKsDOAXGBPADsKBvAUFKAglALxQDkAhmQDR5QBCJ59NOAvjjgJYiLABOAMwoBjTKgwEAIhUQVsdROmAAuWAmTKAdAVr4A9PqhaTW9px58ho8cvoy5C-Eoxq4SCcC309UQ8ZNzHEEwEBFELgB7ECgXYAIAMVCACgATWQo3ZWkMgEonPyNTcxCwiOjYuySQNIysjHs8gv9ijmDQ8KiYuOrkuLcNTx1qKHS5eviHCly1ADdIrlT2sq7KjF7+9Q9tH1G62Dspmah5xeXOip6UzfdNDBGxzIPJKagAH2fgRrlj09SC+AAdy4iBEAAsoH1lPlcPh8CIKPBxINtAQVHQ4Wt4r1HrkANyFKAAdTBKCgCJAZEQUAAkqNgKkwGJYmDMHEoJFBHs5AB+HkYuEAI34wAoAGs8QKEUitncvPR0ZjnFUUo8oIjPt9ppKlVBhaKJQLUsBhGAADaIRVQDhsIA
fuxichen commentedon Jun 7, 2024
Please help to see why the type of data cannot be inferred,
As shown in the following demo:
Function overload has restricted the input type, if
type=TestTypeWhen A the data must beTypeAData.I think
type=TestTypewas determined through theswitchAt time A, it should be inferred thatdata=TypeADatahttps://www.typescriptlang.org/play/?ts=5.4.5#code/KYOwrgtgBAKsDOAXGBPADsKBvAUFKAglALxQDkAhmQDR5QBCJ59NOAvjjgJYiLABOAMwoBjTKgwEAIhUQVsdROmAAuWAmTKAdAVr4A9PqhaTW9px58ho8cvoy5C-Eoxq4SCcC309UQ8ZNzHEEwEBFELgB7ECgXYAIAMVCACgATWQo3ZWkMgEonPyNTcxCwiOjYuySQNIysjHs8gv9ijmDQ8KiYuOrkuLcNTx1qKHS5eviHCly1ADdIrlT2sq7KjF7+9Q9tH1G62Dspmah5xeXOip6UzfdNDBGxzIPJKagAH2fgRrlj09SC+AAdy4iBEAAsoH1lPlcPh8CIKPBxINtAQVHQ4Wt4r1HrkANyFKAAdTBKCgCJAZEQUAAkqNgKkwGJYmDMHEoJFBHs5AB+HkYuEAI34wAoAGs8QKEUitncvPR0ZjnFUUo8oIjPt9ppKlVBhaKJQLUsBhGAADaIRVQDhsIA
RyanCavanaugh commentedon Jun 13, 2024
Function overloads don't have any effects on narrowing. For this case you'd have to write something like
typescript-bot commentedon Jun 16, 2024
This issue has been marked as "Design Limitation" and has seen no recent activity. It has been automatically closed for house-keeping purposes.