Skip to content
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

Improve flow typing #12135

Closed
wants to merge 1 commit into from
Closed

Conversation

MichaReiser
Copy link
Contributor

@MichaReiser MichaReiser commented Oct 2, 2020

Q                       A
Fixed Issues? RFC: babel/rfcs#7
Patch: Bug Fix? No
Major: Breaking Change? Yes
Minor: New Feature? No
Tests Added + Pass? No
Documentation PR Link
Any Dependency Changes? No
License MIT

The goal of this PR is to improve the @babel/types typing for Flow. This is a RFC because some of the changes are not backwards compatible.

Current Flow Types

The current script generates classes for each node type and specifies type refinements (%checks (node instanceof MemberExpression)) for the is* methods.

That means, the following is possible.

const {isIdentifier = require('@babel/types');

if (isIdentifier(node)) {
  console.log(node.name);
}

Shortcomings

The todays system has mainly two shortcomings.

  • Exporting the node types as classes is incorrect. @babel/types does not implement the node types as classes nor does it export any value for each type. Declaring the node types as classes might misguide users to check for a certain node type using node instanceof Identifier or to create a new node using a constructor new Identifier().
  • Flow only supports %checks refinements on function declarations and only if the function is called as a method. For example, isIdentifier(node) is supported but t.isIdentifier(node) (method invocation) or path.isIdentifier() are not.

Proposal

The proposal of this PR is to change the today's typing to

  • Use types instead of classes to make it clear that @babel/types does not export a value for the node types.
  • Use a union type for BabelNode rather than a base class. This allows to refine on node types using node.type === 'Identifier'.
  • Refine on the type for is* methods

Example Usage:

import * as t from '@babel/types';
import {isStringLiteral} from '@babel/types';
import type {StringLiteral, NumericLiteral} from '@babel/types';

function asStringLiteral(ast: ?StringLiteral | NumericLiteral): BabelNodeStringLiteral | null {
  if (ast == null) {
      return t.stringLiteral("null");
  }

  if (isStringLiteral(ast)) { // or ast.type === 'StringLiteral'
    return ast;
  }

  return t.stringLiteral(String(ast.value));
}

This will also allow flow to e.g. refine Path by using path.node.type === 'Identifier' && path.node.name === 'test';

Generated types

Regression

Changing the node types to classes means that custom %checks declaration must be rewritten from e.g.

declare function isMemberX(node: BabelNode) %checks (node instanceof BabelNodeMemberExpression)

to

declare function isMemberX(node: BabelNode) %checks (node.type === 'MemberExpression');

Other Changes

  • Create module scoped type declarations for each node type without the NODE_PREFIX. The goal of this is to have shorter type names and allow consumers to explicitly import the types vs using the global declarations.
  • Change the special case for the super and import functions to be declared as var instead of functions to work around a parsing error in some linters. This doesn't change the semantics.
  • Added %checks declaration for alias types, e.g. isLiteral

@codesandbox-ci
Copy link

codesandbox-ci bot commented Oct 2, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 33d7851:

Sandbox Source
babel-repl-custom-plugin Configuration
babel-plugin-multi-config Configuration

@JLHwung
Copy link
Contributor

JLHwung commented Oct 2, 2020

@MichaReiser Thanks for the writings. We have an RFC repo for this specific purpose, can you open an RFC PR on https://github.com/babel/rfcs?

@JLHwung JLHwung closed this Oct 2, 2020
@JLHwung JLHwung reopened this Oct 2, 2020
@babel-bot
Copy link
Collaborator

babel-bot commented Oct 2, 2020

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/32555/

@MichaReiser
Copy link
Contributor Author

RFC Discussion: babel/rfcs#7

@ExE-Boss
Copy link
Contributor

See also: #11883

@MichaReiser MichaReiser changed the title [RFC] Improve flow typing Improve flow typing Oct 19, 2020
@MichaReiser
Copy link
Contributor Author

See also: #11883

Rebased on top of #11883

@nicolo-ribaudo
Copy link
Member

@MichaReiser Could you try running make flow without this PR and with this this PR, to see if there is any outstanding perf difference?

@MichaReiser
Copy link
Contributor Author

@nicolo-ribaudo There's a performance difference when running a full-check on the repository. I haven't figured out how to measure the incremental performance which, in my view, is the more important performance.

Flow 0.123

~/g/babel [babel-types-flow-types] » time make flow                    
yarn flow check --strip-root
Found 0 errors

________________________________________________________
Executed in   19.09 secs   fish           external 
   usr time    7.96 secs   99.00 micros    7.96 secs 
   sys time    4.15 secs  637.00 micros    4.15 secs 
   
   
   
~/g/babel [master] » time make flow                                                                                                                                      
yarn flow check --strip-root
Found 0 errors

________________________________________________________
Executed in   14.32 secs   fish           external 
   usr time    4.02 secs   80.00 micros    4.02 secs 
   sys time    3.77 secs  449.00 micros    3.77 secs 

flow 0.137

~/g/babel [babel-types-flow-types] » time flow check --strip-root  
Executed in   13.39 secs   fish           external 
   usr time    4.34 secs  140.00 micros    4.34 secs 
   sys time    2.42 secs  849.00 micros    2.42 secs 

~/g/babel [master] » time flow check --strip-root  
________________________________________________________
Executed in   13.07 secs   fish           external 
   usr time    2.61 secs  102.00 micros    2.61 secs 
   sys time    2.63 secs  667.00 micros    2.63 secs 

I overall expected that the check performance would decrease and the results are around what I expected. Other types I tried had check times where a single file took more than 8s.

@MichaReiser MichaReiser closed this Mar 4, 2023
@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Jun 4, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 4, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: flow outdated A closed issue/PR that is archived due to age. Recommended to make a new issue pkg: types
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants