Skip to content

Design Meeting Notes, 10/13/2021 #46365

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
DanielRosenwasser opened this issue Oct 14, 2021 · 1 comment
Closed

Design Meeting Notes, 10/13/2021 #46365

DanielRosenwasser opened this issue Oct 14, 2021 · 1 comment
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

Type-Unreachable Code

#46268 (comment)

  • Trend over the last few months - people keep asking us to flag code that can never be reached.

  • The analyses are unrelated, but they are all similar in spirit.

  • One example

    interface Range {
        isEmpty(): boolean;
    }
    
    function isNotEmpty(r1: Range): boolean {
        return !r1.isEmpty // oops - forgot to call this
    }
    • We catch these in if, but we don't catch this in other conditions.
    // right side is unreachable
    let check = this.isEmpty || that.isEmpty;
    
    // also fishy?
    let result: boolean = !check;
    declare const a: {
        b: number
    };
    
    // why are you using a '?.'?
    const bar = a?.b;
  • These are to support defensive checks, but unclear if it carries its weight.

  • We have some checks for Promises and uncalled functions in conditions.

  • For nullish-coalescing, we have a non-null assertion operator (postfix !), but we don't have a "possibly null assertion operator".

    • We use node.parent, and it's more convenient for us to say "this property is never undefined", so we declare it as parent: Node which is not technically valid.
  • Ideally a lot of these would go into a linter - but

    • Seems like type lint rules are slow.
    • Also, do people actually run these lint rules by default?
  • The complexity comes from the fact that "these are not accurate".

  • One issue is you're able to say "I can use this as if it's not nullable" - could have something like "I can use this if it's not nullable - but don't warn me if I try to check if it's nullish."

  • We have suggestion diagnostics - why not leverage that?

    • They show up in the editor, not at compilations.
  • Need an implementation - maybe "strict boolean checking".

    • Feels like there's an existing issue for this, can't find it offhand.

Correlating Union Members Between Each Other

#30581

  • Want to be able to grab the type of one property and know that its type "corresponds" to the underlying consistuent of the union.

  • Kind of need to create a type variable to describe this - don't have that except in conditional types.

  • Very "dependent type"y.

  • Could imagine

    type FindArg = {
        readonly fn: (x: infer T) => void;
        readonly arg: infer T;
    }
  • How does this tie in with usage?

    const dispatchTable: FnAndArg[] = [
        // ...
    ];
    
    const entry1 = dispatchTable[someValue];
    
    const { fn, arg } = dispatchTable[x];
    
    fn(arg); // want this to succeed
    • Could say that if these are all readonly and const, we can analyze these right.
  • Why not have a local type variable and make FindArg generic?

    type FindArg = {
        readonly fn: (x: infer T) => void;
        readonly arg: infer T;
    }
    
    const dispatchTable: FnAndArg[] = [
        // ...
    ];
    
    const entry1 = dispatchTable[someValue];
    
    const { fn, arg } = dispatchTable[x];
    
    fn(arg); // want this to succeed
    • The type variable doesn't live at the use-site, it's local to each type.
  • Can sort of emulate this today

    <T>() => ({ arg: T, callback: (x: T) => void }
  • Pretty much associated types - should revisit that issue too!

Overriding Subtype Reduction Between any and unknown

#46347

  • Lots of cases where people want stricter results for places that return any such as JSON.parse, fetch, axios, stricter DOM types, etc.

  • Idea - during subtype reduction of a union, we would have unknown take precedence over any.

  • Feel like we had an experiment of this at some point.

    What's happening with strictAny? #24737

    • This mode didn't work because any is a sledgehammer to say "lemme do it!"
  • Problem with this is that a lot of places will assume the types are reduced.

    • The proposal is that it always reduces - this is doable.
  • Concern: people might use any | unknown everywhere - not always desirable when using contravariant positions

    • e.g. (...args: any[]) => any can be assigned any function
    • (...args: unknown[]) => unknown) doesn't work because you flip assignability for the parameters
    • (...args: never[]) => unknown is the "safe any function", but nobody can build the right intuition about what it means and whether it's useful - also barely buys you anything over(...args: any[]) => any.
  • Another concern: instantiation assumes T | U could instantiate to unknown instead of any whereas it would have previously been unknown. That's a break.

  • A new type that's different from a union?

    • Could be persuaded of that.
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label Oct 14, 2021
@fatcerberus
Copy link

fatcerberus commented Oct 14, 2021

I feel like correlated types could be implemented pretty easily if TypeScript had a way, internally, to represent a "deferred" indexed-access type that refers back to the original variable, so that for example:

const dispatchTable: FnAndArg[] = [
    // ...
];

const entry1 = dispatchTable[someValue];

const { fn, arg } = dispatchTable[x];

fn;   // hover type is (typeof dispatchTable)["fn"]
arg;  // hover type is (typeof dispatchTable)["arg"]

...and then only resolve those to their underlying types as necessary. Maybe I'm wrong, though; this is just my outsider perspective.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

2 participants