Let us say I want to write a function that can accept a single argument which can be either of nullable or non-nullable type. If the argument is non-nullable, then the return type should also be non-nullable. Similarly, if the argument is of nullable type, so too should be the return type.
Below is my attempt at implementing such function:
type TransformKey = 'one' | 'two' | 'three'
function transform<T extends TransformKey | null>(key: T): T extends TransformKey ? string : string | null {
if (key === null)
return null as any
else
return key.toUpperCase() as any
}
The function signature appears to be correct, since it achieves the desired behavior on call-site, for example:
const neverNullArg = 'two'
const neverNullResult: string = transform(neverNullArg)
const maybeNullArg: TransformKey | null = 'three'
const maybeNullResult: string | null = transform(maybeNullArg)
i.e. the return type is indeed determined by the argument type in a correct manner.
However, my issue lies with the function implementation. Without casting the return value to any
, both return statements result in TS2322 error: Type 'null'/'string' is not assignable to type 'T extends TransformKey ? string : string | null'
. So I was wondering how could the function be implemented in a way that satisfies the signature without defeating the typing system using as any
casts or // @ts-ignore
You can create overloads for your function:
type TransformKey = 'one' | 'two' | 'three'
function transform(key: TransformKey): string;
function transform(key: TransformKey | null): string | null;
function transform(key: any): string | null {
if (key === null)
return null;
else
return key.toUpperCase();
}
const neverNullArg = 'two'
const neverNullResult: string = transform(neverNullArg)
const maybeNullArg: TransformKey | null = 'three'
const maybeNullResult: string | null = transform(maybeNullArg)
See also: Writing Good Overloads
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments