diff --git a/api/next/62121.txt b/api/next/62121.txt
new file mode 100644
index 00000000000000..bb220a619aaeda
--- /dev/null
+++ b/api/next/62121.txt
@@ -0,0 +1 @@
+pkg reflect, func TypeAssert[$0 interface{}](Value) ($0, bool) #62121
diff --git a/doc/next/6-stdlib/99-minor/reflect/62121.md b/doc/next/6-stdlib/99-minor/reflect/62121.md
new file mode 100644
index 00000000000000..4945891c6ebd1a
--- /dev/null
+++ b/doc/next/6-stdlib/99-minor/reflect/62121.md
@@ -0,0 +1,2 @@
+The new [TypeAssert] function permits converting a [Value] directly to a Go type.
+This is like using a type assertion on the result of [Value.Interface].
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 3d1e410dac6323..675fa242b45abb 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -8681,3 +8681,126 @@ func TestMapOfKeyPanic(t *testing.T) {
 	var slice []int
 	m.MapIndex(ValueOf(slice))
 }
+
+func testTypeAssert[T comparable](t *testing.T, val T) {
+	t.Helper()
+	v, ok := TypeAssert[T](ValueOf(val))
+	if v != val || !ok {
+		t.Errorf("TypeAssert[%T](%v) = (%v, %v); want = (%v, true)", *new(T), val, v, ok, val)
+	}
+}
+
+func testTypeAssertDifferentType[T, T2 comparable](t *testing.T, val T2) {
+	t.Helper()
+	if v, ok := TypeAssert[T](ValueOf(val)); ok {
+		t.Errorf("TypeAssert[%T](%v) = (%v, %v); want = (%v, false)", *new(T), val, v, ok, *new(T))
+	}
+}
+
+func newPtr[T any](t T) *T {
+	return &t
+}
+
+func TestTypeAssertConcreteTypes(t *testing.T) {
+	testTypeAssert(t, int(1111))
+	testTypeAssert(t, int(111111111))
+	testTypeAssert(t, int(-111111111))
+	testTypeAssert(t, int32(111111111))
+	testTypeAssert(t, int32(-111111111))
+	testTypeAssert(t, uint32(111111111))
+	testTypeAssert(t, [2]int{111111111, 22222222})
+	testTypeAssert(t, [2]int{-111111111, -22222222})
+	testTypeAssert(t, newPtr(1111))
+	testTypeAssert(t, newPtr(111111111))
+	testTypeAssert(t, newPtr(-111111111))
+	testTypeAssert(t, newPtr([2]int{-111111111, -22222222}))
+	testTypeAssert(t, [2]*int{newPtr(-111111111), newPtr(-22222222)})
+	testTypeAssert(t, newPtr(time.Now()))
+
+	testTypeAssertDifferentType[uint](t, int(111111111))
+	testTypeAssertDifferentType[uint](t, int(-111111111))
+}
+
+func TestTypeAssertInterfaceTypes(t *testing.T) {
+	v, ok := TypeAssert[any](ValueOf(1))
+	if v != any(1) || !ok {
+		t.Errorf("TypeAssert[any](1) = (%v, %v); want = (1, true)", v, ok)
+	}
+
+	v, ok = TypeAssert[fmt.Stringer](ValueOf(1))
+	if v != nil || ok {
+		t.Errorf("TypeAssert[fmt.Stringer](1) = (%v, %v); want = (1, false)", v, ok)
+	}
+
+	v, ok = TypeAssert[any](ValueOf(testTypeWithMethod{"test"}))
+	if v != any(testTypeWithMethod{"test"}) || !ok {
+		t.Errorf(`TypeAssert[any](testTypeWithMethod{"test"}) = (%v, %v); want = (testTypeWithMethod{"test"}, true)`, v, ok)
+	}
+
+	v, ok = TypeAssert[fmt.Stringer](ValueOf(testTypeWithMethod{"test"}))
+	if v != fmt.Stringer(testTypeWithMethod{"test"}) || !ok {
+		t.Errorf(`TypeAssert[fmt.Stringer](testTypeWithMethod{"test"}) = (%v, %v); want = (testTypeWithMethod{"test"}, true)`, v, ok)
+	}
+
+	val := &testTypeWithMethod{"test"}
+	v, ok = TypeAssert[fmt.Stringer](ValueOf(val))
+	if v != fmt.Stringer(val) || !ok {
+		t.Errorf(`TypeAssert[fmt.Stringer](&testTypeWithMethod{"test"}) = (%v, %v); want = (&testTypeWithMethod{"test"}, true)`, v, ok)
+	}
+
+	if v, ok := TypeAssert[int](ValueOf(newPtr(any(1))).Elem()); v != 1 || !ok {
+		t.Errorf(`TypeAssert[int](ValueOf(newPtr(any(1))).Elem()) = (%v, %v); want = (1, true)`, v, ok)
+	}
+
+	if v, ok := TypeAssert[testTypeWithMethod](ValueOf(newPtr(fmt.Stringer(testTypeWithMethod{"test"}))).Elem()); v.val != "test" || !ok {
+		t.Errorf(`TypeAssert[testTypeWithMethod](newPtr(fmt.Stringer(testTypeWithMethod{"test"}))) = (%v, %v); want = (testTypeWithMethod{"test"}, true)`, v, ok)
+	}
+}
+
+type testTypeWithMethod struct {
+	val string
+}
+
+func (v testTypeWithMethod) String() string { return v.val }
+
+func TestTypeAssertMethod(t *testing.T) {
+	method := ValueOf(&testTypeWithMethod{val: "test value"}).MethodByName("String")
+	f, ok := TypeAssert[func() string](method)
+	if !ok {
+		t.Fatalf(`TypeAssert[func() string](method) = (,false); want = (,true)`)
+	}
+
+	out := f()
+	if out != "test value" {
+		t.Fatalf(`TypeAssert[func() string](method)() = %q; want "test value"`, out)
+	}
+}
+
+func TestTypeAssertZeroValPanic(t *testing.T) {
+	defer func() { recover() }()
+	TypeAssert[int](Value{})
+	t.Fatalf("TypeAssert did not panic")
+}
+
+func TestTypeAssertReadOnlyPanic(t *testing.T) {
+	defer func() { recover() }()
+	TypeAssert[int](ValueOf(&testTypeWithMethod{}).FieldByName("val"))
+	t.Fatalf("TypeAssert did not panic")
+}
+
+func TestTypeAssertAllocs(t *testing.T) {
+	val := ValueOf(new(time.Time)).Elem()
+	allocs := testing.AllocsPerRun(100, func() {
+		TypeAssert[time.Time](val)
+	})
+	if allocs != 0 {
+		t.Errorf("unexpected amount of allocations = %v; want = 0", allocs)
+	}
+}
+
+func BenchmarkTypeAssertTime(b *testing.B) {
+	val := ValueOf(time.Now())
+	for b.Loop() {
+		TypeAssert[time.Time](val)
+	}
+}
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 6e062a56d1c7ac..7d30d2ae3df997 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -1513,6 +1513,58 @@ func valueInterface(v Value, safe bool) any {
 	return packEface(v)
 }
 
+// TypeAssert is semantically equivalent to:
+//
+//	v2, ok := v.Interface().(T)
+func TypeAssert[T any](v Value) (T, bool) {
+	if v.flag == 0 {
+		panic(&ValueError{"reflect.TypeAssert", Invalid})
+	}
+	if v.flag&flagRO != 0 {
+		// Do not allow access to unexported values via Interface,
+		// because they might be pointers that should not be
+		// writable or methods or function that should not be callable.
+		panic("reflect.TypeAssert: cannot return value obtained from unexported field or method")
+	}
+
+	if v.flag&flagMethod != 0 {
+		v = makeMethodValue("TypeAssert", v)
+	}
+
+	if abi.TypeFor[T]() != v.typ() {
+		// TypeAssert[T] should work the same way as v.Interface().(T), thus we need
+		// to handle following case properly: TypeAssert[any](ValueOf(1)).
+		// Note that we will not hit here is such case: TypeAssert[any](ValueOf(new(any)).Elem()).
+		if abi.TypeFor[T]().Kind() == abi.Interface {
+			v, ok := packEface(v).(T)
+			return v, ok
+		}
+
+		// Special case: match the element inside the interface.
+		// TypeAssert[int](ValueOf(newPtr(any(0))).Elem()
+		if v.kind() == Interface {
+			// Empty interface has one layout, all interfaces with
+			// methods have a second layout.
+			if v.NumMethod() == 0 {
+				v, ok := (*(*any)(v.ptr)).(T)
+				return v, ok
+			}
+			v, ok := any(*(*interface {
+				M()
+			})(v.ptr)).(T)
+			return v, ok
+		}
+
+		var zero T
+		return zero, false
+	}
+
+	if v.flag&flagIndir == 0 {
+		return *(*T)(unsafe.Pointer(&v.ptr)), true
+	}
+	return *(*T)(v.ptr), true
+}
+
 // InterfaceData returns a pair of unspecified uintptr values.
 // It panics if v's Kind is not Interface.
 //