The compiler is not catching this case because of the middleman that is the generic alias type (which is probably an easy fix, though a bit arbitrary). This works: import strutils template typeOrSeqType(U: type): type = U or seq[U] proc f[T](x: typeOrSeqType(proc(y: string): T)) = discard let p = proc(y: string): int {.closure.} = parseInt(y) f(p) Run
Otherwise though, in these cases where it's hard for the compiler to understand, it's possible to write small macros, usually templates are enough but this is one of the cases where the AST substitution is bottom-up and it's uglier. import macros, strutils type TypeOrSeqType[U] {.used.} = U | seq[U] # this definition does not change anything, TypeOrSeqType just needs to be defined to compile macro expandTypeOrSeqType(pr) = proc process(n: NimNode): NimNode = result = n for i in 1 ..< n[3].len: let paramType = n[3][i][^2] if paramType.kind == nnkBracketExpr and paramType[0].eqIdent("TypeOrSeqType"): let (a, b) = (copy(n), copy(n)) a[3][i][^2] = paramType[1] b[3][i][^2] = newTree(nnkBracketExpr, ident"seq", paramType[1]) return newStmtList(process(a), process(b)) result = process(pr) proc f[T](x: TypeOrSeqType[proc(y: string): T]) {.expandTypeOrSeqType.} = discard let p = proc(y: string): int = parseInt(y) f(p) proc foo(a: TypeOrSeqType[int], b: TypeOrSeqType[string]) {.expandTypeOrSeqType.} = discard foo(3, "abc") foo(@[3], "abc") foo(3, @["abc"]) foo(@[3], @["abc"]) Run