8000 Design Meeting Notes, 10/13/2021 · Issue #46365 · microsoft/TypeScript · GitHub
[go: up one dir, main page]

Skip to content
Design Meeting Notes, 10/13/2021 #46365
Closed
@DanielRosenwasser

Description

@DanielRosenwasser

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design NotesNotes from our design meetings

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0