microsoft / microsoft/TypeScript

Arguments cease to be assignable when parameter is broadened via conditional

Offen
#52,310 5 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bug Domain: Conditional Types Help Wanted
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.4k
Ø Merge
1 T. 19 Std.
Gemergte PRs (30 T.)
117

Beschreibung

Bug Report

🔎 Search Terms

conditional parameter assignable broader

🕗 Version & Regression Information
  • The error messages changed to be a bit less informative over time, but the core error was there in all the versions I tested, and I reviewed the FAQ for entries about conditional types and parameters.
  • Nightly version at time of testing: v5.0.0-dev.20230119
⏯ Playground Link

Playground link with relevant code

💻 Code
type AttributeMap = {
    Animal: { swims: boolean; lifespan: number; };
    Robot: { swims: boolean; serial: string; };
}
type Mover = keyof AttributeMap;
type Mountain = { name: string; elevation: number;}
type MountainAttribute = keyof Mountain;
type MoverOrMountain = Mover | 'Mountain';
type BroaderAttributeName<M extends MoverOrMountain> = (
    M extends Mover ?
    keyof AttributeMap[M] :
    MountainAttribute
) & string;
declare function actOnAttribute<M extends Mover>(
    mover : M,
    attr : keyof AttributeMap[M] & string,
) : void ;
declare function actOnAttributeBroader<M extends MoverOrMountain>(
    moverOrMountain : M,
    attr : BroaderAttributeName<M>,
) : void ;
//Sometimes-possible workaround:
interface ExtendedAttributeMap extends AttributeMap {
    Mountain: { name: string; elevation: number };
}
declare function actOnAttributeBroaderWorkaround<
    M extends keyof ExtendedAttributeMap,
>(
    moverOrMountain : M,
    attr : keyof ExtendedAttributeMap[M] & string,
) : void ;
export const demoFunction = function<M extends Mover> (
    mover : M,
    attr : keyof AttributeMap[M] & string,
) {
    actOnAttribute(mover, attr); //works, as expected
    actOnAttributeBroader(mover, attr); //Err: 2nd arg not assignable
    actOnAttributeBroader<M>(mover, attr); //specifying M doesn't help
    actOnAttributeBroaderWorkaround(mover, attr); //works, as expected
}

Note: Dropping instances of ‘& string’ just results in a more complicated error message; it doesn’t change the core issue.

🙁 Actual behavior

actOnAttributeBroader accepts a superset of the valid parameters of actOnAttribute.
In this calling context, these two versions of the called function are equivalent, since all types in that context are limited to the more narrow set accepted by actOnAttribute. However, the TypeScript compiler doesn't even try to figure out that the one conditional type of this example code simplifies to the true branch in the context where the error is triggered, so there isn't actually a need to trigger an error. It triggers an error.

🙂 Expected behavior

Making a reusable function more broadly reusable by accepting a broader set of parameter types should (a) possibly allow some calls that wouldn't work before the broadening to work, and (b) not cause any calls that were working fine before the broadening to suddenly start throwing Typescript compilation failures. Generic, reusable code should be considered a good thing and TypeScript should support that goal (as it seems to in the marketing that convinces technical executives to trigger conversions) rather than fight against it (as it does in practice with in-practice design choices and implementation defects, where this issue is an example).

Where Typescript correctly validates all parameters to a call to actOnAttribute and has enough information to determine which side of the conditional will apply (as it does here), it should do so and simplify the broader possibility of the reusable function down to the simpler original version where it can correctly validate types. There should be no error.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit der verlinkten TypeScript Playground-Reproduktion und vergleiche actOnAttribute mit actOnAttributeBroader in demoFunction. Verfolge, wie der Compiler den bedingten Typ BroaderAttributeName gegen den generischen Parameter attr prüft. Als erledigt gilt, dass der breitere Aufruf fehlerfrei kompiliert, während bestehende ungültige Aufrufe weiterhin abgelehnt werden, mit einem Regressionstest für das gemeldete Beispiel.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
typescript
Bereich
compilers
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
38/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.