diff --git a/src/pymatlib/core/typedefs.py b/src/pymatlib/core/typedefs.py
index 7201a978cf698bd014e1bff742727e29fcc336cc..f6b69cd4a2cbe01d72c12489f43d0a891f4dfabd 100644
--- a/src/pymatlib/core/typedefs.py
+++ b/src/pymatlib/core/typedefs.py
@@ -62,6 +62,18 @@ class MaterialProperty:
     expr: sp.Expr
     assignments: List[Assignment] = field(default_factory=list)
 
+    def __post_init__(self):
+        """Validate assignments after initialization."""
+        if any(assignment is None for assignment in self.assignments):
+            raise ValueError("None assignments are not allowed")
+
+        # Validate each assignment
+        for assignment in self.assignments:
+            if not isinstance(assignment, Assignment):
+                raise ValueError(f"Invalid assignment type: {type(assignment)}")
+            if assignment.lhs is None or assignment.rhs is None or assignment.lhs_type is None:
+                raise ValueError("Assignment fields cannot be None")
+
     def evalf(self, symbol: sp.Symbol, temperature: Union[float, ArrayTypes]) -> Union[float, np.ndarray]:
         """
         Evaluates the material property at specific temperature values.
@@ -72,18 +84,44 @@ class MaterialProperty:
 
         Returns:
             Union[float, np.ndarray]: The evaluated property value(s) at the given temperature(s).
+
+        Raises:
+            TypeError: If:
+                - symbol is not found in expression or assignments
+                - temperature contains non-numeric values
+                - invalid type for temperature
         """
+        # Get all symbols from expression and assignments
+        expr_symbols = self.expr.free_symbols
+        assignment_symbols = set().union(*(
+            assignment.rhs.free_symbols
+            for assignment in self.assignments
+            if isinstance(assignment.rhs, sp.Expr)
+        ))
+        all_symbols = expr_symbols.union(assignment_symbols)
+
+        # If we have symbols but the provided one isn't among them, raise TypeError
+        if all_symbols and symbol not in all_symbols:
+            raise TypeError(f"Symbol {symbol} not found in expression or assignments")
+
         # If the expression has no symbolic variables, return it as a constant float
         if not self.expr.free_symbols:
             return float(self.expr)
 
+        # Handle array inputs
         # If temperature is a numpy array, list, or tuple (ArrayTypes), evaluate the property for each temperature
         if isinstance(temperature, get_args(ArrayTypes)):
             return np.array([self.evalf(symbol, t) for t in temperature])
 
         # Convert any numpy scalar to Python float
-        elif isinstance(temperature, np.generic):
+        if isinstance(temperature, np.floating):
+            temperature = float(temperature)
+
+        # Convert numeric types to float
+        try:
             temperature = float(temperature)
+        except (TypeError, ValueError):
+            raise TypeError(f"Temperature must be numeric, got {type(temperature)}")
 
         # Prepare substitutions for symbolic assignments
         substitutions = [(symbol, temperature)]
@@ -98,7 +136,6 @@ class MaterialProperty:
 
         # Evaluate the material property with the substitutions
         result = sp.N(self.expr.subs(substitutions))
-        # return float(result)
         # Try to convert the result to float if possible
         try:
             return float(result)
diff --git a/tests/test_typedefs.py b/tests/test_typedefs.py
new file mode 100644
index 0000000000000000000000000000000000000000..dfbbb318f312995c0bb4a414286915a4f6073729
--- /dev/null
+++ b/tests/test_typedefs.py
@@ -0,0 +1,108 @@
+import pytest
+import numpy as np
+import sympy as sp
+from pymatlib.core.typedefs import Assignment, MaterialProperty, ArrayTypes, PropertyTypes
+
+def test_assignment():
+    """Test Assignment dataclass functionality."""
+    # Test basic assignment
+    x = sp.Symbol('x')
+    assignment = Assignment(x, 100, 'double')
+    assert assignment.lhs == x
+    assert assignment.rhs == 100
+    assert assignment.lhs_type == 'double'
+
+    # Test with tuple
+    v = sp.IndexedBase('v')
+    assignment = Assignment(v, (1, 2, 3), 'double[]')
+    assert assignment.lhs == v
+    assert assignment.rhs == (1, 2, 3)
+    assert assignment.lhs_type == 'double[]'
+
+def test_material_property_constant():
+    """Test MaterialProperty with constant values."""
+    # Test constant property
+    mp = MaterialProperty(sp.Float(405.))
+    assert mp.evalf(sp.Symbol('T'), 100.) == 405.0
+
+    # Test with assignments
+    mp.assignments.append(Assignment(sp.Symbol('A'), (100, 200), 'int'))
+    assert isinstance(mp.assignments, list)
+    assert len(mp.assignments) == 1
+
+def test_material_property_temperature_dependent():
+    """Test MaterialProperty with temperature-dependent expressions."""
+    T = sp.Symbol('T')
+
+    # Test linear dependency
+    mp = MaterialProperty(T * 100.)
+    assert mp.evalf(T, 2.0) == 200.0
+
+    # Test polynomial
+    mp = MaterialProperty(T**2 + T + 1)
+    assert mp.evalf(T, 2.0) == 7.0
+
+def test_material_property_indexed():
+    """Test MaterialProperty with indexed base expressions."""
+    T = sp.Symbol('T')
+    v = sp.IndexedBase('v')
+    i = sp.Symbol('i', integer=True)
+
+    mp = MaterialProperty(v[i])
+    mp.assignments.extend([
+        Assignment(v, (3, 6, 9), 'float'),
+        Assignment(i, T / 100, 'int')
+    ])
+
+    assert mp.evalf(T, 97) == 3  # i=0
+    assert mp.evalf(T, 150) == 6  # i=1
+
+def test_material_property_errors():
+    """Test error handling in MaterialProperty."""
+    T = sp.Symbol('T')
+    X = sp.Symbol('X')  # Different symbol
+
+    # Test evaluation with wrong symbol
+    mp = MaterialProperty(X * 100)
+    with pytest.raises(TypeError, match="Symbol T not found in expression or assignments"):
+        mp.evalf(T, 100.0)
+
+    # Test invalid assignments
+    with pytest.raises(ValueError, match="None assignments are not allowed"):
+        MaterialProperty(T * 100, assignments=[None])
+
+def test_material_property_array_evaluation():
+    """Test MaterialProperty evaluation with arrays."""
+    T = sp.Symbol('T')
+    mp = MaterialProperty(T * 100)
+
+    # Test with numpy array
+    temps = np.array([1.0, 2.0, 3.0])
+    result = mp.evalf(T, temps)
+    assert isinstance(result, np.ndarray)
+    assert np.allclose(result, temps * 100.0)
+
+    # Test with invalid array values
+    with pytest.raises(TypeError):
+        mp.evalf(T, np.array(['a', 'b', 'c']))
+
+def test_material_property_piecewise():
+    """Test MaterialProperty with piecewise functions."""
+    T = sp.Symbol('T')
+    mp = MaterialProperty(sp.Piecewise(
+        (100, T < 0),
+        (200, T >= 100),
+        (T, True)
+    ))
+
+    assert mp.evalf(T, -10) == 100
+    assert mp.evalf(T, 50) == 50
+    assert mp.evalf(T, 150) == 200
+
+def test_material_property_numpy_types():
+    """Test MaterialProperty with numpy numeric types."""
+    T = sp.Symbol('T')
+    mp = MaterialProperty(T * 100)
+
+    assert mp.evalf(T, np.float32(1.0)) == 100.0
+    assert mp.evalf(T, np.float64(1.0)) == 100.0