question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Function declarations inside function expressions should inherit control flow narrowings of the parent function expression

See original GitHub issue

I am trying to avoid typing null checks for properties that are formerly optional on the outer interface, but are then assigned with default values for the whole context of the function body.

I used a type guard for it, the problem is that the guarded type is lost in a function, but not lost in an arrow function, even though it can’t be hoisted before the type guard.

I don’t want to introduce new variables for every function parameter in a similar manner and I don’t want to call other functions with casting as printMenu(options as DefinedOptions).

TypeScript Version: 3.7.3, 3.8.0-beta

Search Terms: typescript type guard function arrow function Code

export interface Options {
  header?: string
  border?: boolean
  pageSize?: number
  helpMessage?: string
  showKeypress?: boolean
}

interface DefinedOptions extends Options {
  pageSize: number
  helpMessage: string
}

const isType = <T>(arg: any): arg is T => true


export default async function menu(options: Options) {

  options // Options

  options.pageSize = options.pageSize ?? 0
  options.helpMessage = options.helpMessage ?? 'Default message'
  if (!isType<DefinedOptions>(options)) return null


  options // DefinedOptions


  return new Promise((resolve, reject) => {

    function handleMenuKeypress(key: any) {
      options // Options  -  should be DefinedOptions

      printMenu(options) // error
    }

    const candleMenuKeypress = (key: any) => {
      options // DefinedOptions

      printMenu(options) // no error
    }
  })
}

function printMenu(options: DefinedOptions) {

}

Playground Link

Expected behavior:

Type should be DefinedOptions in both.

Actual behavior:

Type is Options in function but DefinedOptions in arrow function.

Related: #10927

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
falsandtrucommented, Mar 10, 2020

Another standard case:

function foo(opts?: object) {
  opts = opts || {};
  opts; // object
  return () => opts; // object | undefined <- wrong
}
function bar(a?: string | object, opts?: object) {
  if (typeof a === 'object') [a, opts] = [undefined, a];
  a; // string | undefined
  return () => a; // string | undefined | object <- wrong
}

http://www.typescriptlang.org/play/?ts=3.8.0-dev.20200124&ssl=1&ssc=1&pln=10&pc=2#code/GYVwdgxgLglg9mABMOcAUcAOUDOB+ALkTgCMArAU2gEpEBvAKEWOx0QF4XdEAfH+gL4BuJlxxDEAeknFyVKKIBOFKCEVI0tdgD4xE6bMrReicABMKwGGApnEAHgC0iAO6KEAcwYCGoSLAREEgBDRTRgwkQcKEVrDxNSIygAGjFIxPlaRmYYYEQ0KABPTAo4POCOdk4AcgzoatoAbWDUrFwAXQ5ERvNLa1tU4PaRZmD9GWjYsHj+XqsbMyUVNQ0tXTGpCZi4kzn+u346qAdnN09vIA

2reactions
nmain100commented, Jan 29, 2020

@AleksandrGilmanov That’s a duplicate of #9998; typescript doesn’t know that the function passed to forEach is called at that point, and if all narrowings were pessimistically reset after every function call, narrowing would be mostly useless.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Function expression - JavaScript - MDN Web Docs
The function keyword can be used to define a function inside an expression.
Read more >
Inconsistent narrowing in arrow function · Issue #32300 - GitHub
Inconsistent narrowing in arrow function #32300 ... The root cause is that control flow narrowing applies to arrows and function expressions ...
Read more >
Function expressions - The Modern JavaScript Tutorial
In most cases when we need to declare a function, a Function Declaration is preferable, because it is visible prior to the declaration...
Read more >
C++ Core Guidelines - GitHub Pages
What is expressed in code has defined semantics and can (in ... (Simple) A function should not make control-flow decisions based on the ......
Read more >
Functions in Javascript (Declaration, Expression, Arrow)
Function Expressions are created inside another expression or statement, such as a variable declaration. The function below is treated like ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found