Skip to content

Bloomberg feedback for 5.0 Beta #52670

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dragomirtitian opened this issue Feb 8, 2023 · 0 comments
Closed

Bloomberg feedback for 5.0 Beta #52670

dragomirtitian opened this issue Feb 8, 2023 · 0 comments
Assignees
Labels
Discussion Issues which may not have code impact

Comments

@dragomirtitian
Copy link
Contributor

dragomirtitian commented Feb 8, 2023

By @molisani & @dragomirtitian

We are in the process of evaluating the impact of upgrading to TypeScript 5.0 on our codebase. Here are some preliminary findings.

This is shaping up to be a medium impact release. The following table lists changes that affected our codebase, and where appropriate a link to a separate Issue:

# Change Affects Release notes Packages affected Reported as
1 Union with any does not reduce to any Type Checking Not Announced ~6% #52568
2 No implicit coercions in relational operators Type Checking Yes ~2%
3 Type inference for declared enum member assignment Type Checking Not Announced ~2% #52531
4 Circular constraints don’t type check sometimes Type Checking Not Announced ~1% #52570
5 instanceof narrows to never on else branch Type Checking Not Announced 1 #52571
6 Nested callbacks are not contextually typed Type Checking Not Announced 1 #52575
7 Declarations no longer include default type parameters Declaration Emit Not Announced ~1%
8 Misc type checking improvements Type Checking Not Announced 2

Union with any does not reduce to any

Generally T | any will reduce to any regardless of the origin of such a union. In TS 5.0 this is not the case for unions originating from a conditional type such as below.

Reported as #52568 (fixed)

First appeared in 5.0.0-dev.20221208. A cursory look at merged PRs doesn’t reveal an immediate culprit.

type Spec = any extends object ? any : string;

type WithSpec<T extends number> = T

type R = WithSpec<Spec>

Playground Link

No implicit coercions in relational operators

TypeScript now forbids implicit coercions when using relational operators as described here. We investigated a number of errors raised by this new check but none of them seem to be real runtime issues for us.

Circular constraints don’t type check sometimes

This is a very hard to reproduce issue. It only occurs in VS Code when you first open the file and can’t be reproduced using the CLI. Unfortunately it impacts our build tool which uses the compiler API.

Reported as #52570

Give these files:

// types.ts
export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
    [key in keyof T]: T[key];
};

// index.ts
export declare const value2: {
    sliceSelectors: <FuncMap extends import('./types').SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
};

We get these errors when we first open the types in VS Code.

Type parameter 'FuncMap' has a circular constraint.

Type 'FuncMap[P]' does not satisfy the constraint '(...args: any) => any'.
  Type 'FuncMap[keyof FuncMap]' is not assignable to type '(...args: any) => any'.
    Type 'FuncMap[string] | FuncMap[number] | FuncMap[symbol]' is not assignable to type '(...args: any) => any'.
      Type 'FuncMap[string]' is not assignable to type '(...args: any) => any'.

Any subsequent editing will make the errors go away.

Given the very unstable nature of this bug, it might be a question of file ordering. Moving the SelectorMap to the same file and dropping the import makes the error go away.

In our case these types appear in generated declaration files.

The circular constraint which is present doesn’t seem to make much sense in our case, so we took the opportunity to clean up the types, so this is not blocking for us, but the behavior is still very strange.

instanceof narrows to never on else branch

When testing with instanceof using a class that extends Function as the class, Typescript would previously not narrow the type on any branch. Now it narrows to never on the else branch. This causes some mixin code to break for us.

First appeared in 5.0.0-dev.20221130.

Reported as #52571 (fixed)

class PersonMixin extends Function {
    public [Symbol.hasInstance](o: any) {
        return typeof o === "object" && o !== null && o instanceof Person;
    }    
}
const cls = new PersonMixin();


function test(o:  Person | Car) {
    if (o instanceof cls) {
        console.log("Is Person");
        (o as Person).work()
    }
    else {
        console.log("Is Car")
        o.sayHi(); //o is never, was Person | Car
    }
}

Playground Link

Declarations no longer include default type parameters

On imported types with a type parameter that has a default, the default type for the type parameter is no longer included in the declaration emit (this is not the case if the type is in the same file):

// types.ts
export declare type Table<S = string> = { value: S };
 
// Emitted in both 4.9 and 5.0 as
// export declare const o: Table<string>;
export const o = null! as Table
// index.ts
import { Table } from "./type";


// Emitted in 5.0 as
// export declare const o: Table;
// Emitted in 4.9 as
// export declare const o: Table<string>;
export const o = null! as Table

This is arguably a very good improvement to declaration emit as it makes declarations not depend on the default of the original type, allowing it to change without the need to rebuild all downstream declarations.

Nested callbacks are not contextually typed

Nested callback parameters are not contextually typed if the signature comes from an indexed type, indexed with a type parameter.

Reported as #52575

export interface Event<T> {
    callback: (response: T) => void;
    nested: {
        callback: (response: T) => void;
    }
}


export type CustomEvents = {
    a: Event<string>
    b: Event<number> // If only one candidate type exists it works
};


declare function emit<T extends keyof CustomEvents>(type: T, data: CustomEvents[T]): void


emit('a', {
    callback: (r) => {},
    nested: {
        callback: (response) => {


        },
    },
});

Playground Link

Misc type checking improvements

The following code now errors, as it should, where it did not in 4.9:

let exports: { x?: unknown; foo?: unknown } = {};
exports = exports.foo; // error in 5.0 not in 4.9

Playground Link

Destructuring from unknown inside a catch error variable is now an error:

try {
} catch ({
    status, // error in 5.0 not in 4.9
}: unknown) {
}

Playground Link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Discussion Issues which may not have code impact
Projects
None yet
Development

No branches or pull requests

3 participants