In a React Native codegenNativeComponent spec, what does CodegenTypes.WithDefault do, and what do other props default to natively?
answer
- the native side never sees undefined
- WithDefault<Type, Value> sets the native default
- the prop must be optional
- numbers need Int32, Float or Double
- string unions demand a default
basics
~10 sWithDefault<Type, Value> sets the native default of an optional prop, used when JavaScript omits or removes it. Props without it get Codegen's type default: 0 for numbers, false for booleans, null for strings.
solid answer
~40 sCodegen turns a component spec into native props structures, and native code has no `undefined`: every prop needs a concrete value when JavaScript does not pass one. `CodegenTypes.WithDefault<CodegenTypes.Float, 3>` records that value — the generated props start at 3, and on Android the generated delegate passes 3 to your setter when the prop arrives as `null`, which is what happens when JavaScript stops passing it. Without `WithDefault`, Codegen picks the type's default: `0` for `Int32`, `Float` and `Double`, `false` for `boolean`, `null` for `string`. The parser also enforces rules: a `WithDefault` prop must be optional (`?`), a top-level plain `number` is rejected in favour of `Int32`, `Float` or `Double`, and a string-union prop requires a default, so it is written as `WithDefault<'pen' | 'marker', 'pen'>`.
code
typescript · 18 lines// specs/SignaturePadNativeComponent.ts
import type {CodegenTypes, ColorValue, HostComponent, ViewProps} from 'react-native';
import {codegenNativeComponent} from 'react-native';
export interface NativeProps extends ViewProps {
strokeColor?: ColorValue;
// native default 3; plain `number` would be rejected by Codegen
strokeWidth?: CodegenTypes.WithDefault<CodegenTypes.Float, 3>;
// a string union must carry a default
penMode?: CodegenTypes.WithDefault<'pen' | 'marker', 'pen'>;
disabled?: CodegenTypes.WithDefault<boolean, false>;
// no WithDefault: Codegen's default for Int32 is 0
maxStrokes?: CodegenTypes.Int32;
}
export default codegenNativeComponent<NativeProps>(
'SignaturePad',
) as HostComponent<NativeProps>;go deeper
Remember that native views always need a value for each prop, and WithDefault is how a spec says what that value is.
Explain the generated defaults (0, false, null), the optional-prop rule, the numeric type requirement and why string unions need WithDefault.
Design props so unset and removed values reset the view predictably on both platforms, and write setters that treat every call as a full new value.
Treat component defaults as part of a public API: agree them across platforms, document them, and version changes that alter baked-in native behaviour.
## Why component props need defaults at all A **Fabric native component** is described by a TypeScript spec whose `NativeProps` interface lists the props JavaScript may pass. **Codegen** turns that interface into typed native structures: a C++ props struct shared by both platforms, a Java interface and delegate for Android, and a protocol and helpers for iOS. Native code has no `undefined`. If JavaScript never sets `strokeWidth`, the native view still needs *some* number, and when a prop that was set is later removed, native code must learn what to go back to. That value is the prop's **default**, and it is decided at code-generation time. ## What WithDefault does `CodegenTypes.WithDefault<Type, Value>` is a type-level annotation — at runtime it is just an optional `Type` — that tells Codegen the default: ```typescript export interface NativeProps extends ViewProps { strokeWidth?: CodegenTypes.WithDefault<CodegenTypes.Float, 3>; penMode?: CodegenTypes.WithDefault<'pen' | 'marker', 'pen'>; disabled?: CodegenTypes.WithDefault<boolean, false>; } ``` The effect on the generated code: - The native props start with `strokeWidth` = 3, `penMode` = `pen`, `disabled` = `false`. - On Android, the generated `SignaturePadManagerDelegate` maps each prop name to your setter and substitutes the default when the incoming value is `null`, for example `value == null ? 3 : ...`. A removed prop therefore resets the view to the default instead of leaving the old value in place. - On iOS, the generated C++ props struct is initialised with the same defaults, so `updateProps:oldProps:` compares against well-defined values. ## Defaults when you do not write WithDefault | Spec type | Default Codegen uses | |---|---| | `CodegenTypes.Int32`, `Float`, `Double` | `0` | | `boolean` | `false` | | `string` | `null` | | String union (`'pen' \| 'marker'`) | none — Codegen requires one | So a signature pad declaring `strokeWidth?: CodegenTypes.Float` draws zero-width strokes until JavaScript passes a width, while one declaring `WithDefault<CodegenTypes.Float, 3>` works out of the box. ## Rules the Codegen parser enforces Codegen fails the build, with an explicit message, when a spec breaks these rules: 1. **A `WithDefault` prop must be optional.** Writing `strokeWidth: WithDefault<Float, 3>` without `?` fails with "must be optional if used with WithDefault<> annotation". 2. **Top-level numbers must say how wide they are.** A plain `number` prop fails with "must use a specific numeric type like Int32, Double, or Float", because each maps to a different native type. 3. **String unions need a default.** An enum-like prop without `WithDefault` fails with "A default enum value is required". 4. **Event props need an event type.** A plain function type fails; handlers must be `DirectEventHandler` or `BubblingEventHandler`. 5. **The file name matters.** Only files ending in `NativeComponent` are treated as component specs. ## Where defaults show up in native code - **Android:** your view manager implements the generated `SignaturePadManagerInterface`, whose setters such as `setStrokeWidth(view, value)` receive a concrete value on every call — the explicit one, or the default once the prop is removed. - **iOS:** your `RCTViewComponentView` subclass casts the incoming props to the generated `SignaturePadProps` in `updateProps:oldProps:` and compares fields; a prop JavaScript never set simply holds its default, so the first comparison already sees a real value. Either way, native code never needs an "is it set?" branch for a prop with a sensible default. ## Choosing defaults well - **Default to the value most screens want.** For a proof-of-delivery pad, a visible stroke width and `disabled: false`. - **Match the platform views' own defaults** when you wrap an existing view, so a prop left unset behaves the same on Android and iOS. - **Make "unset" meaningful only where it is needed.** A nullable colour, which falls back to the theme natively, is clearer than a sentinel number. - **Remember that defaults are baked in.** Changing a `WithDefault` value changes generated native code, so it needs a rebuild, not just a JavaScript reload. ## Mistakes interviewers listen for - Assuming an omitted prop arrives natively as `undefined` or "not set". - Assuming removing a prop in JavaScript leaves the native view unchanged. - Treating `WithDefault` as a runtime default that JavaScript applies. - Declaring numeric props as plain `number` and being surprised by the Codegen error.
- What does the Android view manager's setter receive when JavaScript stops passing strokeWidth?The prop arrives at the generated delegate as `null`, and the delegate calls your `setStrokeWidth(view, ...)` with the Codegen default instead: 3 with `WithDefault<Float, 3>`, or 0 without it. Your setter should therefore treat every call as the full new value and never assume null means 'leave unchanged'.
- Why does Codegen reject a plain number prop at the top level?Because it cannot choose the native type for you. `Int32`, `Float` and `Double` become different C++, Java and Objective-C types, with different ranges and precision. The spec must say which one it means, so the parser fails with a message asking for a specific numeric type.
saying these in an interview costs you the question
- An omitted component prop reaches native code as undefined, so the view keeps its last value
- WithDefault is applied in JavaScript before props are sent
- A WithDefault prop can be required as long as the default is set
- Plain number is fine for numeric props; Codegen infers Int32
- Removing a prop in JSX never triggers a native setter call