For a detailed example, visit the TS playground here.
I have defined two fundamental types for my application model that interacts with raw data: Accessor
and
IndexedAccessor<A extends Accessor>
. Both of these types have a read()
function that can output specific primitive types (currently limited to number
and string
). Due to this characteristic, they form a discriminated union instead of being subclasses. I am attempting to write code to map model objects (which are aggregations of accessors) to DTO objects (objects with the same properties but containing raw values from accessors).
export type AccessedType<A> = A extends IndexedAccessor<infer T> ? ReturnType<T["read"]> :
A extends Accessor ? ReturnType<A["read"]> : never;
export function mapToAccessed<A extends Accessor, I extends A | IndexedAccessor<A>>(a: I): AccessedType<I> {
return a.read();
}
Upon compiling in Typescript, the following error is generated:
Type 'string | number | ReturnType<A["read"]>' is not assignable to type 'AccessedType<I>'. Type 'string' is not assignable to type 'AccessedType<I>'.ts(2322)
I have tried incorporating square brackets in the conditional segments of AccessedType
, as well as changing the return type of mapToAccessed
to
ReturnType<I["read"]>
, but neither approach resolved the issue.
Could anyone demonstrate the proper formulation to achieve such a generic static function that takes an accessor of any type and returns the corresponding type? Ideally, I would like to avoid direct dependency on the set of accessors, meaning I prefer not to employ if statements or switch cases for something already conceptually typed.
Conversely, could it be speculated that there is a deficiency in the type system here? Is there potential for TypeScript to become more intelligent in this particular scenario? If not, where might my logical error lie?