#Return type based on input.
26 messages · Page 1 of 1 (latest)
Preview:```ts
type Return<T, A, B, C> = [A, B, C] extends [
string,
string,
string
]
? T
: T[]
declare function test<
T,
A = unknown,
B = unknown,
C = unknown
(data: {a: A; b: B; c: C}): Return<T, A, B, C>
// if all 3 properties are string, return T, if not T[]
const variable = test<number>({a: "", b: "", c: ""})
...```
You cannot specify one generic type parameter while inferring the others, you have to either all specify or all infer.
But even putting that aside, I don't see how you can implement such a function, it's impossible to know what T is so there's no way for the function to return a T.
i've already implemented it just this wasn't working, didnt know that you cant do half half tbh
I don't see how it's possible to implement it.
i mean not naturally, i had to do as Type but why wouldn't it be
Let's pretend the partial inference issue does not exist, the following code:
const foo = test<number>({ a: '', b: '', c: '' })
const bar = test<string>({ a: '', b: '', c: '' })
Compiles to:
const foo = test({ a: '', b: '', c: '' })
const bar = test({ a: '', b: '', c: '' })
They are literally the same code, yet somehow foo should be number but bar has to be a string.
If T was somewhere in the arguments or somehow captured, it would be possible.
When you use a type parameter in the function, it should generally be inferrable from the arguments.
For example, this is a misuse of generics:
function getMeA<T>(): T {
/* magic */
}
because getMeA<string>() and getMeA<number>() compile to the same code at runtime, there's so way to implement this function safely (other than always throwing); this is just a type cast in disguise. Instead of using a generic here, you should return unknown, and cast at the call site if necessary, to be clear it's an unsafe operation:
-function getMeA<T>(): T {
+function getMeA(): unknown {
/* magic */
}
-getMeA<number>()
+getMeA() as number
One exception to this rule is if you're returning a possibly-empty container of T. For example, these are all perfectly safe, even though the generic can't be inferred from the parameters:
function emptyArray<T>(): Array<T> {
return []
}
function useRef<T>(): { current?: T } {
return {}
}
A few API does that and it's actually unsafe, but it is convenient.
well yeah im pretty much aware that its unsafe but it is what it is
in this specific usecase i dont prefer using as type when calling function everywhere
Cool, I wasn't sure if you were aware because it's just impossible to implement. I suppose I should've said "impossible to implement safely/correctly."
its easiest to just type it as unknown, but this is just for convenience so yeah, thanks tho
but now funny thing is that i can't know if a,b,c are or will be undefined or string xD
there goes my convenience out of the window
I mean, your safety is already out of the window anyways by using a generic as type cast.
well yeah but now its impossible to make it work
So you might as well use overload rather than generic to do what you want.
yeah
This would work:
declare function test<T>(data: { a: string, b: string, c: string }): T
declare function test<T>(data: { a: unknown, b: unknown, c: unknown }): T[]