You will meet both in older code; neither is a choice for new work.
PropTypes 4,446 checked props at runtime, in development builds only, warning in the console when a value had the wrong type or a required prop was missing. Declarations hung off the component as a static property — Greeting.propTypes = { name: PropTypes.string, children: PropTypes.element.isRequired }. React 19 7,897 dropped support: propTypes on a function component is ignored, so such code runs but checks nothing. The prop-types package remains on npm 2,036 at 15.8.1, last published in 2023, for older React versions.
| PropTypes | TypeScript |
|---|---|
| PropTypes.string | name?: string |
| PropTypes.string.isRequired | name: string |
| PropTypes.oneOf(['a', 'b']) | kind: 'a' | 'b' |
| PropTypes.node / .element | ReactNode / ReactElement |
| PropTypes.shape({...}) | an interface |
The two differ in kind. PropTypes validated values that arrived, one render at a time, in the browser; TypeScript validates call sites, all of them, before the code ships — which is why a component nobody rendered during testing went unchecked.
Flow is Meta's own static checker, built alongside React and still released regularly — version 0.331 appeared in September 2026 — but its use outside Meta has collapsed. Its syntax is close enough to TypeScript's (type Props = { name: string }) that converting a file is usually mechanical. Its distinguishing feature is aggressive inference: a file marked // @flow is checked even with no annotations, so square("2") against function square(n) { return n * n; } is an error. flow-remove-types strips the annotations when you migrate away.