diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs
index 64677f82..101dfc54 100644
--- a/crates/backend/src/ast.rs
+++ b/crates/backend/src/ast.rs
@@ -54,7 +54,7 @@ pub enum NapiFnArgKind {
   Callback(Box<CallbackArg>),
 }
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub enum FnKind {
   Normal,
   Constructor,
@@ -84,7 +84,7 @@ pub struct NapiStruct {
   pub use_custom_finalize: bool,
 }
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub enum NapiStructKind {
   None,
   Constructor,
diff --git a/crates/backend/src/codegen/fn.rs b/crates/backend/src/codegen/fn.rs
index 4f7c1604..35e2df94 100644
--- a/crates/backend/src/codegen/fn.rs
+++ b/crates/backend/src/codegen/fn.rs
@@ -156,8 +156,63 @@ impl NapiFn {
                     }
                   }
                 } else if p.ident == "This" {
-                  if !is_in_class {
-                    bail_span!(p, "`This` is only allowed in class methods");
+                  if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
+                    args: angle_bracketed_args,
+                    ..
+                  }) = &p.arguments
+                  {
+                    if let Some(syn::GenericArgument::Type(generic_type)) =
+                      angle_bracketed_args.first()
+                    {
+                      if let syn::Type::Path(syn::TypePath {
+                        path: syn::Path { segments, .. },
+                        ..
+                      }) = generic_type
+                      {
+                        if let Some(syn::PathSegment { ident, .. }) = segments.first() {
+                          if let Some((primitive_type, _)) =
+                            crate::PRIMITIVE_TYPES.iter().find(|(p, _)| ident == *p)
+                          {
+                            bail_span!(
+                              ident,
+                              "This type must not be {} \nthis in JavaScript function must be `Object` type or `undefined`",
+                              primitive_type
+                            );
+                          }
+                          args.push(
+                            quote! {
+                              {
+                                <#ident as napi::bindgen_prelude::FromNapiValue>::from_napi_value(env, cb.this)?
+                              }
+                            },
+                          );
+                          skipped_arg_count += 1;
+                          continue;
+                        }
+                      } else if let syn::Type::Reference(syn::TypeReference {
+                        elem,
+                        mutability,
+                        ..
+                      }) = generic_type
+                      {
+                        if let syn::Type::Path(syn::TypePath {
+                          path: syn::Path { segments, .. },
+                          ..
+                        }) = elem.as_ref()
+                        {
+                          if let Some(syn::PathSegment { ident, .. }) = segments.first() {
+                            let token = if mutability.is_some() {
+                              quote! { <#ident as napi::bindgen_prelude::FromNapiMutRef>::from_napi_mut_ref(env, cb.this)? }
+                            } else {
+                              quote! { <#ident as napi::bindgen_prelude::FromNapiRef>::from_napi_ref(env, cb.this)? }
+                            };
+                            args.push(token);
+                            skipped_arg_count += 1;
+                            continue;
+                          }
+                        }
+                      }
+                    }
                   }
                   args.push(
                     quote! { <napi::bindgen_prelude::This as napi::NapiValue>::from_raw_unchecked(env, cb.this) },
diff --git a/crates/backend/src/lib.rs b/crates/backend/src/lib.rs
index 332ab69a..9ea18085 100644
--- a/crates/backend/src/lib.rs
+++ b/crates/backend/src/lib.rs
@@ -55,3 +55,40 @@ napi_ast_impl! {
  (Enum, NapiEnum),
  (Const, NapiConst),
 }
+
+pub(crate) static PRIMITIVE_TYPES: &[(&str, &str)] = &[
+  ("JsUndefined", "undefined"),
+  ("()", "undefined"),
+  ("Undefined", "undefined"),
+  ("JsNumber", "number"),
+  ("i8", "number"),
+  ("i16", "number"),
+  ("i32", "number"),
+  ("i64", "number"),
+  ("f64", "number"),
+  ("u8", "number"),
+  ("u16", "number"),
+  ("u32", "number"),
+  ("u64", "bigint"),
+  ("i64n", "bigint"),
+  ("u128", "bigint"),
+  ("i128", "bigint"),
+  ("usize", "bigint"),
+  ("isize", "bigint"),
+  ("JsBigInt", "bigint"),
+  ("BigInt", "bigint"),
+  ("JsBoolean", "boolean"),
+  ("bool", "boolean"),
+  ("JsString", "string"),
+  ("String", "string"),
+  ("str", "string"),
+  ("Latin1String", "string"),
+  ("Utf16String", "string"),
+  ("char", "string"),
+  ("Null", "null"),
+  ("JsNull", "null"),
+  ("null", "null"),
+  ("Symbol", "symbol"),
+  ("JsSymbol", "symbol"),
+  ("JsFunction", "(...args: any[]) => any"),
+];
diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs
index d0a2357c..ead99fac 100644
--- a/crates/backend/src/typegen.rs
+++ b/crates/backend/src/typegen.rs
@@ -120,35 +120,8 @@ pub trait ToTypeDef {
 
 static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
   let mut map = HashMap::default();
+  map.extend(crate::PRIMITIVE_TYPES.iter().cloned());
   map.extend([
-    ("JsUndefined", "undefined"),
-    ("()", "undefined"),
-    ("Undefined", "undefined"),
-    ("JsNumber", "number"),
-    ("i8", "number"),
-    ("i16", "number"),
-    ("i32", "number"),
-    ("i64", "number"),
-    ("f64", "number"),
-    ("u8", "number"),
-    ("u16", "number"),
-    ("u32", "number"),
-    ("u64", "bigint"),
-    ("i64n", "bigint"),
-    ("u128", "bigint"),
-    ("i128", "bigint"),
-    ("usize", "bigint"),
-    ("isize", "bigint"),
-    ("JsBigInt", "bigint"),
-    ("BigInt", "bigint"),
-    ("JsBoolean", "boolean"),
-    ("bool", "boolean"),
-    ("JsString", "string"),
-    ("String", "string"),
-    ("str", "string"),
-    ("Latin1String", "string"),
-    ("Utf16String", "string"),
-    ("char", "string"),
     ("JsObject", "object"),
     ("Object", "object"),
     ("Array", "unknown[]"),
@@ -201,14 +174,8 @@ static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
     ("Either24", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"),
     ("Either25", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"),
     ("Either26", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"),
-    ("Null", "null"),
-    ("JsNull", "null"),
-    ("null", "null"),
-    ("Symbol", "symbol"),
-    ("JsSymbol", "symbol"),
     ("external", "object"),
     ("AbortSignal", "AbortSignal"),
-    ("JsFunction", "(...args: any[]) => any"),
     ("JsGlobal", "typeof global"),
     ("External", "ExternalObject<{}>"),
     ("unknown", "unknown"),
diff --git a/crates/backend/src/typegen/fn.rs b/crates/backend/src/typegen/fn.rs
index a5541c14..b6ae0fd0 100644
--- a/crates/backend/src/typegen/fn.rs
+++ b/crates/backend/src/typegen/fn.rs
@@ -13,14 +13,18 @@ struct FnArg {
 }
 
 struct FnArgList {
+  this: Option<FnArg>,
   args: Vec<FnArg>,
   last_required: Option<usize>,
 }
 
 impl Display for FnArgList {
   fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+    if let Some(this) = &self.this {
+      write!(f, "this: {}", this.ts_type)?;
+    }
     for (i, arg) in self.args.iter().enumerate() {
-      if i != 0 {
+      if i != 0 || self.this.is_some() {
         write!(f, ", ")?;
       }
       let is_optional = arg.is_optional
@@ -39,13 +43,22 @@ impl Display for FnArgList {
 
 impl FromIterator<FnArg> for FnArgList {
   fn from_iter<T: IntoIterator<Item = FnArg>>(iter: T) -> Self {
-    let args = iter.into_iter().collect::<Vec<_>>();
+    let mut args = Vec::new();
+    let mut this = None;
+    for arg in iter.into_iter() {
+      if arg.arg != "this" {
+        args.push(arg);
+      } else {
+        this = Some(arg);
+      }
+    }
     let last_required = args
       .iter()
       .enumerate()
       .rfind(|(_, arg)| !arg.is_optional)
       .map(|(i, _)| i);
     FnArgList {
+      this,
       args,
       last_required,
     }
@@ -128,12 +141,27 @@ impl NapiFn {
             if let syn::Type::Path(path) = path.ty.as_ref() {
               if let Some(PathSegment {
                 ident,
-                arguments: PathArguments::AngleBracketed(_),
+                arguments:
+                  PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
+                    args: angle_bracketed_args,
+                    ..
+                  }),
               }) = path.path.segments.last()
               {
                 if ident == "Reference" || ident == "WeakReference" {
                   return None;
                 }
+                if ident == "This" {
+                  if let Some(syn::GenericArgument::Type(ty)) = angle_bracketed_args.first() {
+                    let (ts_type, _) = ty_to_ts_type(ty, false, false);
+                    return Some(FnArg {
+                      arg: "this".to_owned(),
+                      ts_type,
+                      is_optional: false,
+                    });
+                  }
+                  return None;
+                }
               }
             }
 
diff --git a/crates/napi/src/bindgen_runtime/js_values/class.rs b/crates/napi/src/bindgen_runtime/js_values/class.rs
index 2b700fed..9005ce33 100644
--- a/crates/napi/src/bindgen_runtime/js_values/class.rs
+++ b/crates/napi/src/bindgen_runtime/js_values/class.rs
@@ -2,9 +2,10 @@ use std::any::type_name;
 use std::ops::{Deref, DerefMut};
 use std::ptr;
 
-use crate::{bindgen_runtime::FromNapiValue, check_status, sys, JsObject, NapiRaw};
+use super::Object;
+use crate::{bindgen_runtime::FromNapiValue, check_status, sys, NapiRaw};
 
-pub type This = JsObject;
+pub type This<T = Object> = T;
 
 pub struct ClassInstance<T: 'static> {
   pub value: sys::napi_value,
diff --git a/crates/napi/src/bindgen_runtime/js_values/number.rs b/crates/napi/src/bindgen_runtime/js_values/number.rs
index 97296809..80421706 100644
--- a/crates/napi/src/bindgen_runtime/js_values/number.rs
+++ b/crates/napi/src/bindgen_runtime/js_values/number.rs
@@ -41,7 +41,7 @@ macro_rules! impl_number_conversions {
           check_status!(
             unsafe { sys::$get(env, napi_val, &mut ret) },
             "Failed to convert napi value {:?} into rust type `{}`",
-            type_of!(env, napi_val),
+            type_of!(env, napi_val)?,
             $name,
           )?;
 
diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md
index 00c6ddf5..839b73db 100644
--- a/examples/napi/__test__/typegen.spec.ts.md
+++ b/examples/napi/__test__/typegen.spec.ts.md
@@ -48,6 +48,7 @@ Generated by [AVA](https://avajs.dev).
     }␊
     export function createObjectWithClassField(): ObjectFieldClassInstance␊
     export function receiveObjectWithClassField(object: ObjectFieldClassInstance): Bird␊
+    export function plusOne(this: Width): number␊
     export function dateToNumber(input: Date): number␊
     export function chronoDateToMillis(input: Date): number␊
     export function chronoDateAdd1Minute(input: Date): Date␊
@@ -298,6 +299,10 @@ Generated by [AVA](https://avajs.dev).
     export class CustomFinalize {␊
       constructor(width: number, height: number)␊
     }␊
+    export class Width {␊
+      value: number␊
+      constructor(value: number)␊
+    }␊
     export class ClassWithFactory {␊
       name: string␊
       static withName(name: string): ClassWithFactory␊
diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap
index 17f9c8a7..4b49767a 100644
Binary files a/examples/napi/__test__/typegen.spec.ts.snap and b/examples/napi/__test__/typegen.spec.ts.snap differ
diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts
index 999a77ac..2b884642 100644
--- a/examples/napi/__test__/values.spec.ts
+++ b/examples/napi/__test__/values.spec.ts
@@ -108,6 +108,8 @@ import {
   getNumArr,
   getNestedNumArr,
   CustomFinalize,
+  plusOne,
+  Width,
 } from '../'
 
 test('export const', (t) => {
@@ -161,7 +163,7 @@ test('enum', (t) => {
   t.is(enumToI32(CustomNumEnum.Eight), 8)
 })
 
-test('class', (t) => {
+test.only('class', (t) => {
   const dog = new Animal(Kind.Dog, '旺财')
 
   t.is(dog.name, '旺财')
@@ -192,6 +194,13 @@ test('class', (t) => {
   const turtle = NinjaTurtle.newRaph()
   t.is(turtle.returnThis(), turtle)
   t.is(NinjaTurtle.isInstanceOf(turtle), true)
+  // Inject this to function
+  const width = new Width(1)
+  t.is(plusOne.call(width), 2)
+  t.throws(() => {
+    // @ts-expect-error
+    plusOne.call('')
+  })
 })
 
 test('class factory', (t) => {
diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts
index 0ea1ca8e..970ce77a 100644
--- a/examples/napi/index.d.ts
+++ b/examples/napi/index.d.ts
@@ -38,6 +38,7 @@ export interface ObjectFieldClassInstance {
 }
 export function createObjectWithClassField(): ObjectFieldClassInstance
 export function receiveObjectWithClassField(object: ObjectFieldClassInstance): Bird
+export function plusOne(this: Width): number
 export function dateToNumber(input: Date): number
 export function chronoDateToMillis(input: Date): number
 export function chronoDateAdd1Minute(input: Date): Date
@@ -288,6 +289,10 @@ export class NotWritableClass {
 export class CustomFinalize {
   constructor(width: number, height: number)
 }
+export class Width {
+  value: number
+  constructor(value: number)
+}
 export class ClassWithFactory {
   name: string
   static withName(name: string): ClassWithFactory
diff --git a/examples/napi/src/class.rs b/examples/napi/src/class.rs
index b0c3a545..72c3a5ff 100644
--- a/examples/napi/src/class.rs
+++ b/examples/napi/src/class.rs
@@ -395,3 +395,13 @@ impl ObjectFinalize for CustomFinalize {
     Ok(())
   }
 }
+
+#[napi(constructor)]
+pub struct Width {
+  pub value: i32,
+}
+
+#[napi]
+pub fn plus_one(this: This<&Width>) -> i32 {
+  this.value + 1
+}
diff --git a/examples/napi/src/lib.rs b/examples/napi/src/lib.rs
index 189f1eef..1825406c 100644
--- a/examples/napi/src/lib.rs
+++ b/examples/napi/src/lib.rs
@@ -1,5 +1,6 @@
 #![allow(dead_code)]
 #![allow(unreachable_code)]
+#![allow(clippy::blacklisted_name)]
 
 #[macro_use]
 extern crate napi_derive;