Skip to content

More consistently backport type system fixes #38237

@AnyhowStep

Description

@AnyhowStep

Search Terms

backport, fixes, type system

Suggestion

When a type system bug is introduced in version X, and later fixed in version X+n,
the fix should be backported all the way to X (or at least a reasonable number of past releases).

Use Cases

This feature request is mostly for library authors with source code in native TypeScript.

When a new version of TypeScript is released, library authors have to scramble to check that it doesn't break their .d.ts files (handwritten or tsc-generated). If it is broken, they have to somehow fix it so that it works on existing versions of TS, and also the new version.

Over time, the result is a lot of duplicated .d.ts files that may go out of sync, and are prone to mistakes.

Surprisingly, JS library authors will have an easier time with this problem, since they will probably already be writing their own .d.ts files and use typesVersions.

Examples

export type AnyExtendedMapper =
    ExtendedMapper<any, any, any[]>
;
export type ExtendedMapper<HandledInputT, OutputT, ArgsT extends any[]> =
    (name : string, mixed : HandledInputT, ...args : ArgsT) => OutputT
;

declare function extraParamsOfImpl<F extends AnyExtendedMapper> (f : F) : F;

declare const mixed_1: ExtendedMapper<unknown, never, []>;

export const test_1 = extraParamsOfImpl(mixed_1);
//                                      ~~~~~~~
//                                      3.3.3 works
//                                      3.5.1 does not work
//                                      3.6.3 does not work
//                                      3.7.4 does not work
//                                      3.8.3 works

type ExtraParamsOfImpl<F extends AnyExtendedMapper> = F

type Test = ExtraParamsOfImpl<ExtendedMapper<unknown, never, []>>
//                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//                            3.3.3 works
//                            3.5.1 does not work
//                            3.6.3 does not work
//                            3.7.4 does not work
//                            3.8.3 works

Playground

Since the fix in 3.8.3 was not backported to 3.5.1, 3.6.3, 3.7.4, my options are the following,

  • Only support 3.3.3
    This is bad because over time, the library will just become more and more irrelevant

  • Only support 3.8.3
    This is bad because it alienates old users, or extra effort has to be put in to backport new features

  • Find a way to write the type such that it works on all versions of TS
    This is bad because it is not always possible, or may require significant effort to shuffle types around.
    And you also have to write compile-time (type-level) tests for each TS version you want to support, to make sure the fix works for all versions of TS.

  • Write a custom .d.ts file for 3.5.1, 3.6.3, 3.7.5 and use typesVersions
    This is bad because you now have to write one set of .d.ts per TS version.
    Requires compile-time tests for each handwritten set of .d.ts files, and tsc-generated files.
    Very error-prone.

  • Use downlevel-dts, hope it does not produce broken emit for older TS versions, and use typesVersions
    Also bad because "generate output that does not break on older releases due to introduced compiler bugs" is probably not a use case downlevel-dts was intended to solve.
    Generated output still needs to be fixed by humans.
    Requires compile-time tests for each set of downlevel-dts .d.ts files, and tsc-generated files.
    Very error-prone.


In some cases, it's possible that an entire library becomes completely useless because type system fixes were not backported, and new bugs were introduced.

  1. TS 3.3.3 is OK
  2. TS 3.5.1 introduces type system bug A
  3. TS 3.6.3 fixes type system bug A (not backported)
  4. TS 3.6.3 introduces type system bug B

The library is stuck on TS 3.3.3 because 3.5.1 has bug A, and 3.6.3 has bug B.

The library author has to somehow find a workaround for both bugs to support 3.5.1 and 3.6.3.

The problem gets worse as new versions are added.


I'm actually running into such a problem, at this point.

Exhibit A: Playground

Exhibit B: #38235

Bugs with each TS version,

  • 3.3.3: -NA-
  • 3.5.1: A
  • 3.6.3: A
  • 3.7.5: A
  • 3.8.3: B

So, I'm stuck on TS 3.3.3 because any later version gives me some kind of bug I have to work around.


In other cases, a project may find it impossible to update their TS version.

  1. TS 3.3.3 is OK
  2. TS 3.5.1 introduces type system bug A
  3. TS 3.6.3 fixes type system bug A (not backported)
  4. TS 3.6.3 introduces type system bug B

The project is stuck on TS 3.3.3 if library L triggers bug A, and library M triggers bug B.

  • Upgrading to TS 3.5.1 breaks L.
  • Upgrading to TS 3.6.3 breaks M.

The project now needs to wait for a new TS version that fixes both A and B in the same release, or wait for L and M to find workarounds... Or find other libraries that support the new TS version.

The more libraries the project uses, the greater the chance of being unable to update their TS version.


Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

I understand that asking for type system fixes to be backported many versions increases the burden on the TS team, but it makes life easier for library authors.

And also makes life easier for library consumers, I suppose.
Imagine filing a bug report like,
"Your library does not work for TS version X",

and then being told,
"Downgrade TS to X-k".

And then downgrading causes errors for 10 other libraries due to other compiler bugs with fixes that were not backported.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DeclinedThe issue was declined as something which matches the TypeScript visionSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions