33 *
44 * This source code is licensed under the MIT license found in the
55 * LICENSE file in the root directory of this source tree.
6+ *
7+ * @flow
68 */
79
10+ import type { ReactNodeList } from 'shared/ReactTypes' ;
11+
812import invariant from 'shared/invariant' ;
913import {
1014 getIteratorFn ,
@@ -25,13 +29,13 @@ const SUBSEPARATOR = ':';
2529 * @param {string } key to be escaped.
2630 * @return {string } the escaped key.
2731 */
28- function escape ( key ) {
32+ function escape ( key : string ) : string {
2933 const escapeRegex = / [ = : ] / g;
3034 const escaperLookup = {
3135 '=' : '=0' ,
3236 ':' : '=2' ,
3337 } ;
34- const escapedString = ( '' + key ) . replace ( escapeRegex , function ( match ) {
38+ const escapedString = key . replace ( escapeRegex , function ( match ) {
3539 return escaperLookup [ match ] ;
3640 } ) ;
3741
@@ -46,33 +50,35 @@ function escape(key) {
4650let didWarnAboutMaps = false ;
4751
4852const userProvidedKeyEscapeRegex = / \/ + / g;
49- function escapeUserProvidedKey ( text ) {
50- return ( '' + text ) . replace ( userProvidedKeyEscapeRegex , '$&/' ) ;
53+ function escapeUserProvidedKey ( text : string ) : string {
54+ return text . replace ( userProvidedKeyEscapeRegex , '$&/' ) ;
5155}
5256
5357/**
54- * Generate a key string that identifies a component within a set.
58+ * Generate a key string that identifies a element within a set.
5559 *
56- * @param {* } component A component that could contain a manual key.
60+ * @param {* } element A element that could contain a manual key.
5761 * @param {number } index Index that is used if a manual key is not provided.
5862 * @return {string }
5963 */
60- function getComponentKey ( component , index ) {
64+ function getElementKey ( element : any , index : number ) : string {
6165 // Do some typechecking here since we call this blindly. We want to ensure
6266 // that we don't block potential future ES APIs.
63- if (
64- typeof component === 'object' &&
65- component !== null &&
66- component . key != null
67- ) {
67+ if ( typeof element === 'object' && element !== null && element . key != null ) {
6868 // Explicit key
69- return escape ( component . key ) ;
69+ return escape ( '' + element . key ) ;
7070 }
7171 // Implicit key determined by the index in the set
7272 return index . toString ( 36 ) ;
7373}
7474
75- function mapIntoArray ( children , array , escapedPrefix , nameSoFar , callback ) {
75+ function mapIntoArray (
76+ children : ?ReactNodeList ,
77+ array : Array < React$Node > ,
78+ escapedPrefix : string ,
79+ nameSoFar : string ,
80+ callback : ( ?React$Node ) = > ?ReactNodeList ,
81+ ) : number {
7682 const type = typeof children ;
7783
7884 if ( type === 'undefined' || type === 'boolean' ) {
@@ -91,7 +97,7 @@ function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
9197 invokeCallback = true ;
9298 break ;
9399 case 'object' :
94- switch ( children . $$typeof ) {
100+ switch ( ( children : any ) . $$typeof ) {
95101 case REACT_ELEMENT_TYPE :
96102 case REACT_PORTAL_TYPE :
97103 invokeCallback = true ;
@@ -105,22 +111,24 @@ function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
105111 // If it's the only child, treat the name as if it was wrapped in an array
106112 // so that it's consistent if the number of children grows:
107113 let childKey =
108- nameSoFar === '' ? SEPARATOR + getComponentKey ( child , 0 ) : nameSoFar ;
114+ nameSoFar === '' ? SEPARATOR + getElementKey ( child , 0 ) : nameSoFar ;
109115 if ( Array . isArray ( mappedChild ) ) {
110116 let escapedChildKey = '' ;
111117 if ( childKey != null ) {
112118 escapedChildKey = escapeUserProvidedKey ( childKey ) + '/' ;
113119 }
114- mapIntoArray ( mappedChild , array , escapedChildKey , c => c ) ;
120+ mapIntoArray ( mappedChild , array , escapedChildKey , '' , c => c ) ;
115121 } else if ( mappedChild != null ) {
116122 if ( isValidElement ( mappedChild ) ) {
117123 mappedChild = cloneAndReplaceKey (
118124 mappedChild ,
119125 // Keep both the (mapped) and old keys if they differ, just as
120126 // traverseAllChildren used to do for objects as children
121127 escapedPrefix +
128+ // $FlowFixMe Flow incorrectly thinks React.Portal doesn't have a key
122129 ( mappedChild . key && ( ! child || child . key !== mappedChild . key )
123- ? escapeUserProvidedKey ( mappedChild . key ) + '/'
130+ ? // $FlowFixMe Flow incorrectly thinks existing element's key can be a number
131+ escapeUserProvidedKey ( '' + mappedChild . key ) + '/'
124132 : '' ) +
125133 childKey ,
126134 ) ;
@@ -139,7 +147,7 @@ function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
139147 if ( Array . isArray ( children ) ) {
140148 for ( let i = 0 ; i < children . length ; i ++ ) {
141149 child = children [ i ] ;
142- nextName = nextNamePrefix + getComponentKey ( child , i ) ;
150+ nextName = nextNamePrefix + getElementKey ( child , i ) ;
143151 subtreeCount += mapIntoArray (
144152 child ,
145153 array ,
@@ -151,18 +159,21 @@ function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
151159 } else {
152160 const iteratorFn = getIteratorFn ( children ) ;
153161 if ( typeof iteratorFn === 'function' ) {
162+ const iterableChildren : Iterable < React$Node > & {
163+ entries : any ,
164+ } = (children: any);
154165 if (disableMapsAsChildren) {
155166 invariant (
156- iteratorFn !== children . entries ,
167+ iteratorFn !== iterableChildren . entries ,
157168 'Maps are not valid as a React child (found: %s). Consider converting ' +
158169 'children to an array of keyed ReactElements instead.' ,
159- children ,
170+ iterableChildren ,
160171 ) ;
161172 }
162173
163174 if (__DEV__) {
164175 // Warn about using Maps as children
165- if ( iteratorFn === children . entries ) {
176+ if ( iteratorFn === iterableChildren . entries ) {
166177 if ( ! didWarnAboutMaps ) {
167178 console . warn (
168179 'Using Maps as children is deprecated and will be removed in ' +
@@ -174,12 +185,12 @@ function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
174185 }
175186 }
176187
177- const iterator = iteratorFn . call ( children ) ;
188+ const iterator = iteratorFn . call ( iterableChildren ) ;
178189 let step ;
179190 let ii = 0 ;
180191 while ( ! ( step = iterator . next ( ) ) . done ) {
181192 child = step . value ;
182- nextName = nextNamePrefix + getComponentKey ( child , ii ++ ) ;
193+ nextName = nextNamePrefix + getElementKey ( child , ii ++ ) ;
183194 subtreeCount += mapIntoArray (
184195 child ,
185196 array ,
@@ -196,12 +207,12 @@ function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
196207 'instead.' +
197208 ReactDebugCurrentFrame . getStackAddendum ( ) ;
198209 }
199- const childrenString = '' + children ;
210+ const childrenString = '' + ( children : any ) ;
200211 invariant (
201212 false ,
202213 'Objects are not valid as a React child (found: %s).%s' ,
203214 childrenString === '[object Object]'
204- ? 'object with keys {' + Object . keys ( children ) . join ( ', ' ) + '}'
215+ ? 'object with keys {' + Object . keys ( ( children : any ) ) . join ( ', ' ) + '}'
205216 : childrenString ,
206217 addendum ,
207218 ) ;
@@ -211,6 +222,8 @@ function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
211222 return subtreeCount ;
212223}
213224
225+ type MapFunc = ( child : ?React$Node ) => ?ReactNodeList ;
226+
214227/**
215228 * Maps children that are typically specified as `props.children`.
216229 *
@@ -224,22 +237,19 @@ function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
224237 * @param {* } context Context for mapFunction.
225238 * @return {object } Object containing the ordered map of results.
226239 */
227- function mapChildren ( children , func , context ) {
240+ function mapChildren (
241+ children : ?ReactNodeList ,
242+ func : MapFunc ,
243+ context : mixed ,
244+ ) : ?Array < React$Node > {
228245 if ( children == null ) {
229246 return children ;
230247 }
231248 const result = [ ] ;
232249 let count = 0 ;
233- mapIntoArray (
234- children ,
235- result ,
236- '' ,
237- '' ,
238- function ( child ) {
239- return func . call ( context , child , count ++ ) ;
240- } ,
241- context ,
242- ) ;
250+ mapIntoArray ( children , result , '' , '' , function ( child ) {
251+ return func . call ( context , child , count ++ ) ;
252+ } ) ;
243253 return result ;
244254}
245255
@@ -252,12 +262,17 @@ function mapChildren(children, func, context) {
252262 * @param {?* } children Children tree container.
253263 * @return {number } The number of children.
254264 */
255- function countChildren ( children ) {
265+ function countChildren ( children : ? ReactNodeList ) : number {
256266 let n = 0 ;
257- mapChildren ( children , ( ) => n ++ ) ;
267+ mapChildren ( children , ( ) => {
268+ n ++ ;
269+ // Don't return anything
270+ } ) ;
258271 return n ;
259272}
260273
274+ type ForEachFunc = ( child : ?React$Node ) => void ;
275+
261276/**
262277 * Iterates through children that are typically specified as `props.children`.
263278 *
@@ -270,7 +285,11 @@ function countChildren(children) {
270285 * @param {function(*, int) } forEachFunc
271286 * @param {* } forEachContext Context for forEachContext.
272287 */
273- function forEachChildren ( children , forEachFunc , forEachContext ) {
288+ function forEachChildren (
289+ children : ?ReactNodeList ,
290+ forEachFunc : ForEachFunc ,
291+ forEachContext : mixed ,
292+ ) : void {
274293 mapChildren (
275294 children ,
276295 function ( ) {
@@ -287,7 +306,7 @@ function forEachChildren(children, forEachFunc, forEachContext) {
287306 *
288307 * See https://reactjs.org/docs/react-api.html#reactchildrentoarray
289308 */
290- function toArray ( children ) {
309+ function toArray ( children : ? ReactNodeList ) : Array < React$Node > {
291310 return mapChildren ( children , child => child ) || [ ] ;
292311}
293312
@@ -305,7 +324,7 @@ function toArray(children) {
305324 * @return {ReactElement } The first and only `ReactElement` contained in the
306325 * structure.
307326 */
308- function onlyChild ( children ) {
327+ function onlyChild < T > (children: T): T {
309328 invariant (
310329 isValidElement ( children ) ,
311330 'React.Children.only expected to receive a single React element child.' ,
0 commit comments