microsoft / microsoft/TypeScript
Narrowing via property check fails when adding parent type to declaration
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Go
- Sterne
- 111k
- Forks
- 14.4k
- Ø Merge
- 1 T. 19 Std.
- Gemergte PRs (30 T.)
- 117
Beschreibung
TypeScript Version: 3.8.3
Search Terms:
- property check refinement
Expected behavior: No error, type is narrowed to SubA.
Actual behavior: Type is narrowed to never and produces an error.
Related Issues:
Code
This code type checks:
interface Base {
base: number;
}
interface SubA extends Base {
a: string;
other: boolean;
}
interface SubB extends Base {
b: string;
}
function foo(x: SubA | SubB | null) {
x = x || {base: 1, b: 'b'};
if (x && 'a' in x && x.a == 'str') {
x.other; // ok
}
}
A very tiny tweak (adding Base | to the parameter type) breaks things, though:
function foo(x: Base | SubA | SubB | null) {
x = x || {base: 1, b: 'b'};
if (x && 'a' in x && x.a == 'str') { // <-- Property 'a' does not exist on type 'never'. (2339)
x.other; // <-- Property 'other' does not exist on type 'never'. (2339)
}
}
This makes some sense since foo could be called with something assignable to Base that has an a but is not specifically a SubA. But what doesn't make sense to me is that removing the assignment on the first line makes the error go away:
function foo(x: Base | SubA | SubB | null) {
if (x && 'a' in x && x.a == 'str') { // ok
x.other; // ok
}
}
That assignment seeming has no bearing on if statement (the default value doesn't have an a property). So why does it affect the inferred type in it?
Either the second and third example should both error or neither of them should.
Output
"use strict";
function foo(x) {
x = x || {base: 1, b: 'b'};
if (x && 'a' in x && x.a == 'str') {
x.other;
}
}
Compiler Options
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"alwaysStrict": true,
"esModuleInterop": true,
"declaration": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": 2,
"target": "ES2017",
"jsx": "React",
"module": "ESNext"
}
}
Playground Link: Provided
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne mit der bereitgestellten TypeScript Playground-Reproduktion und vergleiche die drei foo-Beispiele. Konzentriere dich dabei darauf, wie die Zuweisung das Narrowing durch Eigenschaftsprüfungen verändert. Das Issue ist abgeschlossen, wenn sich das Verhalten in diesen Beispielen konsistent verhält und die gemeldeten never-Fehler behoben oder ausdrücklich dokumentiert sind.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- typescript
- Bereich
- compilers
- Issue-Typ
- Bug
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Veraltet
- Klarheit
- Muss geklärt werden
- Anfängerfreundlichkeit
- 25/100