-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
Check existing issues
- I checked there isn't already an issue for the bug I encountered.
Viem Version
2.31.7
Current Behavior
When using PublicClient<Transport, TChain extends Chain>, TypeScript fails to properly enforce that transaction.to can be null, even though viem correctly declares it as Address | null.
The following code compiles without TypeScript errors when using generic chain constraints:
async function problematicGeneric<TChain extends Chain>(
client: PublicClient<Transport, TChain>
) {
const transaction = await client.getTransaction({ hash: '0x123...' })
// These should be TypeScript errors but aren't:
const unsafeAssignment: Address = transaction.to // Address | null → Address
const result = processAddress(transaction.to) // Passing null to non-null function
}This bypasses TypeScript's strict null checks and can lead to runtime errors when transaction.to is actually null (contract creation transactions).
Expected Behavior
TypeScript should show compile-time errors for:
const unsafeAssignment: Address = transaction.to- Error: Type 'Address | null' is not assignable to type 'Address'processAddress(transaction.to)- Error: Argument of type 'Address | null' is not assignable to parameter of type 'Address'
The same code with concrete types (PublicClient<Transport, Chain>) correctly shows these TypeScript errors, so the null safety should work consistently regardless of whether generics are used.
Steps To Reproduce
- Create a TypeScript project with strict null checks enabled
- Install viem ^2.31.7
- Create a generic function using
PublicClient<Transport, TChain extends Chain> - Try to assign
transaction.todirectly to anAddresstype - Run
tsc --noEmit --strict - Observe that no TypeScript errors are shown (but there should be)
Compare with the same code using PublicClient<Transport, Chain> (concrete types) which correctly shows TypeScript errors.
Link to Minimal Reproducible Example
See this TypeScript Playground
Anything else?
This may be a fundamental limitation in TypeScript's type inference system when dealing with complex generic constraints, rather than an issue that can be resolved at the viem library level.
Workarounds that work:
- Use concrete types:
PublicClient<Transport, Chain> - Remove generic entirely:
PublicClient - Explicit type assertion:
const to: Address | null = transaction.to
Impact: This affects any generic function using viem clients with chain constraints and can lead to runtime errors that are preventable with proper type checking.
Environment:
- TypeScript: 5.x
- Strict mode: enabled
- strictNullChecks: enabled