microsoft / microsoft/TypeScript
Design Meeting Notes, 2026-07-21
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Go
- Sterne
- 111k
- Forks
- 14.3k
- Ø Merge
- 2 T. 4 Std.
- Gemergte PRs (30 T.)
- 132
Beschreibung
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
nodemay be nil in the call tonode.Type(), but we know that it can't be because of the invariant established byIsParenthesizedTypeNode.- Back in TypeScript, we would just grab the property
node.typebecauseIsParenthesizedTypeNodewould have been a type guard that would narrow the type ofnodetoParenthesizedTypeNode. - Now we have a virtual call and nilaway can't link whatever we've learned from the call to
IsParenthesizedTypeNode.
- Back in TypeScript, we would just grab the property
-
-
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.
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Es werden keine Dateien, Tests oder konkreten Einstiegspunkte genannt. Beginne mit der Durchsicht der Diskussion über die strikte Nil-Prüfung und des Kommentar-Suffix-Formats des Prototyps; als abgeschlossen würde gelten, wenn der Umfang des Linting-Durchlaufs, seine Nilability-Defaults sowie sein Umgang mit Type Guards und diskriminierten Unions festgelegt sind.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- go
- Bereich
- compilers
- Issue-Typ
- Feature
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Ruhig
- Klarheit
- Muss geklärt werden
- Anfängerfreundlichkeit
- 30/100