Flow中对象映射类型约束与键访问编译检查咨询
Hey there! Let's tackle your two Flow-related questions one by one with clear, practical examples:
1. Modify IconMap to accept only sealed objects with the exact viewbox + path structure
In Flow, to enforce a strict "sealed" object that rejects extra, undeclared properties, you need to use exact type syntax ({| ... |}). This ensures the object can only have the properties you explicitly define—no more, no less.
First, define a precise type for individual icons, then update IconMap to use this sealed type:
// @flow import React from 'react'; // Sealed type for a single icon: only viewbox (string) and path (function) are allowed type IconType = {| viewbox: string, path: (props: {}) => React.Node // Adjust props type here if your path uses specific props, e.g., React.PropsWithChildren<any> |}; // IconMap now maps string keys to our sealed IconType type IconMap = { [name: string]: IconType }; export const icons: IconMap = { circle: { viewbox: '0 0 473.66 473.66', path(props) { return ( <g id="Layer_2" data-name="Layer 2" {...props}> <g id="Layer_1-2" data-name="Layer 1"> <circle cx="236.83" cy="236.83" r="236.83" /> </g> </g> ); } } };
Try adding an extra property like extra: "test" to the circle object—Flow will throw an error immediately, since IconType doesn't allow unapproved properties.
2. Get compile-time errors when accessing non-existent keys in icons
The issue with using an index signature ({ [name: string]: IconType }) is that Flow can't track which specific keys exist. To fix this, we need to type icons as an exact object with explicit known keys instead of a flexible index signature.
You have two solid options:
Option 1: Explicitly define the icons structure (great for static sets)
If your icon list doesn't change often, manually define the exact type for icons:
// @flow import React from 'react'; type IconType = {| viewbox: string, path: (props: {}) => React.Node |}; // Exact type listing all valid icon keys type Icons = {| circle: IconType |}; export const icons: Icons = { circle: { viewbox: '0 0 473.66 473.66', path(props) { return ( <g id="Layer_2" data-name="Layer 2" {...props}> <g id="Layer_1-2" data-name="Layer 1"> <circle cx="236.83" cy="236.83" r="236.83" /> </g> </g> ); } } }; // ✅ Valid: No error, since 'circle' is a known key const validIcon = icons['circle']; // ❌ Invalid: Flow throws a compile error—'square' isn't in the Icons type const invalidIcon = icons['square'];
Option 2: Auto-derive the type (better for dynamic icon sets)
If you add/remove icons frequently, let Flow auto-derive the type from the actual icons object using typeof and $Exact to keep it sealed:
// @flow import React from 'react'; type IconType = {| viewbox: string, path: (props: {}) => React.Node |}; // First define the icon object without a type annotation const _icons = { circle: { viewbox: '0 0 473.66 473.66', path(props) { return ( <g id="Layer_2" data-name="Layer 2" {...props}> <g id="Layer_1-2" data-name="Layer 1"> <circle cx="236.83" cy="236.83" r="236.83" /> </g> </g> ); } } }; // Auto-derive the exact type from _icons export type Icons = $Exact<typeof _icons>; export const icons: Icons = _icons; // ❌ Still throws an error for non-existent keys const invalidIcon = icons['square'];
This way, whenever you add a new icon to _icons, the Icons type updates automatically—no manual type edits needed!
内容的提问来源于stack exchange,提问作者Sammy

