microsoft / microsoft/TypeScript

Design Meeting Notes, 2026-07-21

未关闭
#63,673 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

Design Notes
主要语言
Go
星标
111k
派生
14.3k
平均合并
2 天 4 小时
30 天内合并 PR
132

描述

Strict nil Checking

  • Lots of issues you can see from the new codebase by searching the repo for "nil dereference".

  • Tools exist for static analysis in Go like nilaway

    • However, we ended up with over 1000 errors which seemed like too many to address.

    • One of the issues with nilaway is that it doesn't have a way of encoding invariants in the type system.

    • For example:

      func IsParenthesizedTypeNode(node *Node) bool {
          return node.Kind == SyntaxKind.ParenthesizedType
      }
      
      func SkipTypeParentheses(node *Node) *Node {
          for IsParenthesizedTypeNode(node) {
              node = node.Type()
          }
          return node
      }
      
      // Acts as a helper to just grab the `Type` property
      // from various node types.
      func (n *Node) Type() *Node {
          switch n.Kind {
            case SyntaxKind.ParenthesizedType:
                return n.AsParenthesizedType().Type
            // ...
      }
      
    • In that example, nilaway complains that node may be nil in the call to node.Type(), but we know that it can't be because of the invariant established by IsParenthesizedTypeNode.

      • Back in TypeScript, we would just grab the property node.type because IsParenthesizedTypeNode would have been a type guard that would narrow the type of node to ParenthesizedTypeNode.
      • Now we have a virtual call and nilaway can't link whatever we've learned from the call to IsParenthesizedTypeNode.
  • So @gabritto has been prototyping a linting pass that is able to encode much of the same information from TypeScript's control flow analysis and type guards over our Go codebase.

  • [[ Example of it catching issues like https://github.com/microsoft/typescript-go/issues/1948 ]]

  • Uses comment suffixes.

    // Type alias that is purely for documentation purposes.
    type CallExpressionNode = Node                    //ref: struct { Kind KindCallExpression; data DefPtr[CallExpression] }
    
    // DefCallExpressionNode is a non-nilable pointer to a CallExpressionNode.
    type DefCallExpressionNode = *CallExpressionNode  //ref: nonnil
    
    // A type guard:
    //ref: node is DefCallExpressionNode
    func IsCallExpression(node DefNode) bool {
        return node.Kind == SyntaxKind.CallExpression
    }
    
    // A union type!
    type NodeWithText = Node              //ref: IdentifierNode | NumberLiteralNode
    type DefNodeWithText = *NodeWithText  //ref: nonnil
    
  • Could we try to make the default non-nilable?

    • Would probably make a lot of stuff less-specially-annotated.
    • Would we be doing this checking on all types or just some subset of ours?
      • All right now.
  • Does this work well given that these are just aliases in Go?

    • Go is good at preserving type aliases.
  • How does this system know that something is a "discriminated union"?

    • It's similar to what we do in TypeScript.
    • We basically look for specific literal values in a common property across the set of types.
  • Basically the comment format uses Go syntax for structs along with new syntax for unions.

  • Looks extremely promising so far.

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

未指定文件、测试或具体入口点。首先查看严格 nil 检查的讨论以及原型的注释后缀格式;要视为完成,需要确定 linting 遍历的范围、其 nilability 默认值,以及它对 type guards 和判别联合的处理方式。

由索引模型根据 Issue 内容生成。

评估

技术栈
go
领域
compilers
Issue 类型
功能
难度
5/5
预计耗时
一周以上
活跃度
冷清
描述清晰度
需要澄清
新手友好度
30/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。