diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md
index 9c9c8501..d7a3afec 100644
--- a/docs/rector_rules_overview.md
+++ b/docs/rector_rules_overview.md
@@ -1,4 +1,4 @@
-# 86 Rules Overview
+# 87 Rules Overview
## AbortIfRector
@@ -1378,6 +1378,25 @@ Change if report to report_if
+## RequestInputToTypedMethodRector
+
+Refactor Request input/get/data methods and array access to type-specific methods when the type is known
+
+- class: [`RectorLaravel\Rector\MethodCall\RequestInputToTypedMethodRector`](../src/Rector/MethodCall/RequestInputToTypedMethodRector.php)
+
+```diff
+-$name = $request->input('name');
+-$age = (int) $request->get('age');
+-$price = (float) $request->data('price');
+-$isActive = (bool) $request['is_active'];
++$name = $request->string('name');
++$age = $request->integer('age');
++$price = $request->float('price');
++$isActive = $request->boolean('is_active');
+```
+
+
+
## RequestStaticValidateToInjectRector
Change static `validate()` method to `$request->validate()`
diff --git a/src/Rector/MethodCall/RequestInputToTypedMethodRector.php b/src/Rector/MethodCall/RequestInputToTypedMethodRector.php
new file mode 100644
index 00000000..3246226d
--- /dev/null
+++ b/src/Rector/MethodCall/RequestInputToTypedMethodRector.php
@@ -0,0 +1,243 @@
+input('name');
+$age = (int) $request->get('age');
+$price = (float) $request->data('price');
+$isActive = (bool) $request['is_active'];
+CODE_SAMPLE,
+ <<<'CODE_SAMPLE'
+$name = $request->string('name');
+$age = $request->integer('age');
+$price = $request->float('price');
+$isActive = $request->boolean('is_active');
+CODE_SAMPLE
+ ),
+ ]
+ );
+ }
+
+ /**
+ * @return array>
+ */
+ public function getNodeTypes(): array
+ {
+ return [Cast::class, Assign::class];
+ }
+
+ /**
+ * @param Cast|Assign $node
+ */
+ public function refactor(Node $node): ?Node
+ {
+ if ($node instanceof Cast) {
+ return $this->refactorCast($node);
+ }
+
+ if ($node instanceof Assign) {
+ return $this->refactorAssign($node);
+ }
+
+ return null;
+ }
+
+ private function refactorCast(Cast $cast): ?Node
+ {
+ $expr = $cast->expr;
+
+ if ($expr instanceof MethodCall) {
+ $typedMethod = $this->getTypedMethodFromCast($cast);
+ if ($typedMethod !== null && $this->isRequestMethodCall($expr)) {
+ return $this->replaceWithTypedMethod($expr, $typedMethod);
+ }
+ }
+
+ if ($expr instanceof ArrayDimFetch) {
+ $typedMethod = $this->getTypedMethodFromCast($cast);
+ if ($typedMethod !== null && $this->isRequestArrayAccess($expr)) {
+ return $this->convertArrayAccessToTypedMethod($expr, $typedMethod);
+ }
+ }
+
+ if ($expr instanceof PropertyFetch) {
+ $typedMethod = $this->getTypedMethodFromCast($cast);
+ if ($typedMethod !== null && $this->isRequestPropertyFetch($expr)) {
+ return $this->convertPropertyFetchToTypedMethod($expr, $typedMethod);
+ }
+ }
+
+ return null;
+ }
+
+ private function refactorAssign(Assign $assign): ?Node
+ {
+ $expr = $assign->expr;
+
+ if ($expr instanceof MethodCall && $this->isRequestMethodCall($expr)) {
+ $typedMethod = $this->inferTypeFromContext($assign);
+ if ($typedMethod !== null) {
+ $assign->expr = $this->replaceWithTypedMethod($expr, $typedMethod);
+
+ return $assign;
+ }
+ }
+
+ if ($expr instanceof ArrayDimFetch && $this->isRequestArrayAccess($expr)) {
+ $typedMethod = $this->inferTypeFromContext($assign);
+ if ($typedMethod !== null) {
+ $assign->expr = $this->convertArrayAccessToTypedMethod($expr, $typedMethod);
+
+ return $assign;
+ }
+ }
+
+ if ($expr instanceof PropertyFetch && $this->isRequestPropertyFetch($expr)) {
+ $typedMethod = $this->inferTypeFromContext($assign);
+ if ($typedMethod !== null) {
+ $assign->expr = $this->convertPropertyFetchToTypedMethod($expr, $typedMethod);
+
+ return $assign;
+ }
+ }
+
+ return null;
+ }
+
+ private function isRequestMethodCall(MethodCall $methodCall): bool
+ {
+ if (! $this->isObjectType($methodCall->var, new ObjectType('Illuminate\Http\Request'))) {
+ return false;
+ }
+
+ $methodName = $this->getName($methodCall->name);
+
+ return $methodName !== null && in_array($methodName, self::GENERIC_METHODS, true);
+ }
+
+ private function isRequestArrayAccess(ArrayDimFetch $arrayDimFetch): bool
+ {
+ return $arrayDimFetch->var instanceof Variable
+ && $this->isObjectType($arrayDimFetch->var, new ObjectType('Illuminate\Http\Request'));
+ }
+
+ private function isRequestPropertyFetch(PropertyFetch $propertyFetch): bool
+ {
+ return $propertyFetch->var instanceof Variable
+ && $this->isObjectType($propertyFetch->var, new ObjectType('Illuminate\Http\Request'));
+ }
+
+ private function getTypedMethodFromCast(Cast $cast): ?string
+ {
+ return match (true) {
+ $cast instanceof String_ => 'string',
+ $cast instanceof Int_ => 'integer',
+ $cast instanceof Double => 'float',
+ $cast instanceof Bool_ => 'boolean',
+ default => null,
+ };
+ }
+
+ private function inferTypeFromContext(Assign $assign): ?string
+ {
+ if (! $assign->var instanceof Variable) {
+ return null;
+ }
+
+ $varType = $this->nodeTypeResolver->getType($assign->var);
+
+ if ($varType->isString()->yes()) {
+ return 'string';
+ }
+
+ if ($varType->isInteger()->yes()) {
+ return 'integer';
+ }
+
+ if ($varType->isFloat()->yes()) {
+ return 'float';
+ }
+
+ if ($varType->isBoolean()->yes()) {
+ return 'boolean';
+ }
+
+ $objectClassNames = $varType->getObjectClassNames();
+ if (in_array('Carbon\Carbon', $objectClassNames, true) || in_array('Illuminate\Support\Carbon', $objectClassNames, true)) {
+ return 'date';
+ }
+
+ return null;
+ }
+
+ private function replaceWithTypedMethod(MethodCall $methodCall, string $typedMethod): MethodCall
+ {
+ $methodCall->name = new Identifier($typedMethod);
+
+ return $methodCall;
+ }
+
+ private function convertArrayAccessToTypedMethod(ArrayDimFetch $arrayDimFetch, string $typedMethod): MethodCall
+ {
+ if (! $arrayDimFetch->var instanceof Variable) {
+ return new MethodCall($arrayDimFetch->var, $typedMethod);
+ }
+
+ $args = [];
+ if ($arrayDimFetch->dim instanceof Expr) {
+ $args[] = new Arg($arrayDimFetch->dim);
+ }
+
+ return new MethodCall($arrayDimFetch->var, $typedMethod, $args);
+ }
+
+ private function convertPropertyFetchToTypedMethod(PropertyFetch $propertyFetch, string $typedMethod): MethodCall
+ {
+ $propertyName = $this->getName($propertyFetch->name);
+ if ($propertyName === null) {
+ return new MethodCall($propertyFetch->var, $typedMethod);
+ }
+
+ return new MethodCall(
+ $propertyFetch->var,
+ $typedMethod,
+ [new Arg(new ScalarString($propertyName))]
+ );
+ }
+}
diff --git a/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/array_access_with_cast.php.inc b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/array_access_with_cast.php.inc
new file mode 100644
index 00000000..898b01b4
--- /dev/null
+++ b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/array_access_with_cast.php.inc
@@ -0,0 +1,37 @@
+
+-----
+string('name');
+ $age = $request->integer('age');
+ $price = $request->float('price');
+ $isActive = $request->boolean('is_active');
+ }
+}
+
+?>
diff --git a/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_boolean.php.inc b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_boolean.php.inc
new file mode 100644
index 00000000..e949e1f0
--- /dev/null
+++ b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_boolean.php.inc
@@ -0,0 +1,33 @@
+input('is_active');
+ $enabled = (bool) $request->get('enabled');
+ }
+}
+
+?>
+-----
+boolean('is_active');
+ $enabled = $request->boolean('enabled');
+ }
+}
+
+?>
diff --git a/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_float.php.inc b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_float.php.inc
new file mode 100644
index 00000000..097a764d
--- /dev/null
+++ b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_float.php.inc
@@ -0,0 +1,33 @@
+input('price');
+ $amount = (double) $request->get('amount');
+ }
+}
+
+?>
+-----
+float('price');
+ $amount = $request->float('amount');
+ }
+}
+
+?>
diff --git a/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_integer.php.inc b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_integer.php.inc
new file mode 100644
index 00000000..cda9a6bf
--- /dev/null
+++ b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_integer.php.inc
@@ -0,0 +1,35 @@
+input('age');
+ $count = (int) $request->get('count');
+ $quantity = (int) $request->data('quantity');
+ }
+}
+
+?>
+-----
+integer('age');
+ $count = $request->integer('count');
+ $quantity = $request->integer('quantity');
+ }
+}
+
+?>
diff --git a/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_string.php.inc b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_string.php.inc
new file mode 100644
index 00000000..17fbcf4e
--- /dev/null
+++ b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/cast_to_string.php.inc
@@ -0,0 +1,35 @@
+input('name');
+ $email = (string) $request->get('email');
+ $address = (string) $request->data('address');
+ }
+}
+
+?>
+-----
+string('name');
+ $email = $request->string('email');
+ $address = $request->string('address');
+ }
+}
+
+?>
diff --git a/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/property_fetch_with_cast.php.inc b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/property_fetch_with_cast.php.inc
new file mode 100644
index 00000000..10da566a
--- /dev/null
+++ b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/property_fetch_with_cast.php.inc
@@ -0,0 +1,37 @@
+name;
+ $age = (int) $request->age;
+ $price = (float) $request->price;
+ $isActive = (bool) $request->is_active;
+ }
+}
+
+?>
+-----
+string('name');
+ $age = $request->integer('age');
+ $price = $request->float('price');
+ $isActive = $request->boolean('is_active');
+ }
+}
+
+?>
diff --git a/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/skip_already_typed.php.inc b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/skip_already_typed.php.inc
new file mode 100644
index 00000000..103bbde0
--- /dev/null
+++ b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/Fixture/skip_already_typed.php.inc
@@ -0,0 +1,24 @@
+string('name');
+ $age = $request->integer('age');
+ $price = $request->float('price');
+ $isActive = $request->boolean('is_active');
+ $date = $request->date('date');
+
+ // Should not change if no cast
+ $data = $request->input('data');
+ $value = $request->get('value');
+ }
+}
+
+?>
diff --git a/tests/Rector/MethodCall/RequestInputToTypedMethodRector/RequestInputToTypedMethodRectorTest.php b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/RequestInputToTypedMethodRectorTest.php
new file mode 100644
index 00000000..fe23a685
--- /dev/null
+++ b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/RequestInputToTypedMethodRectorTest.php
@@ -0,0 +1,31 @@
+doTestFile($filePath);
+ }
+
+ public function provideConfigFilePath(): string
+ {
+ return __DIR__ . '/config/configured_rule_without_configuration.php';
+ }
+}
diff --git a/tests/Rector/MethodCall/RequestInputToTypedMethodRector/config/configured_rule_without_configuration.php b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/config/configured_rule_without_configuration.php
new file mode 100644
index 00000000..2f37a436
--- /dev/null
+++ b/tests/Rector/MethodCall/RequestInputToTypedMethodRector/config/configured_rule_without_configuration.php
@@ -0,0 +1,10 @@
+rule(RequestInputToTypedMethodRector::class);
+};