To build off of the question found here: Generic and Non-Generic Version of Type
The question asks: "how to have a generic and non-generic version of a typescript type" like
export class ServiceResponse {}
export class ServiceResponse<T> extends ServiceResponse {}
The provided answer is use one class such as: export class ServiceResponse<T = void> {}
.
But something is missing from the answer, and that is "how do you define a void property?" . Presumably the ServiceResponse
class will have a property such as result: T
. How then do you define a non-generic object?
const resp: ServiceResponse {
result: __ // <------ result MUST be defined, but cannot be void, so what can it be?
}
I understand I can make result
an optional (result?
) or union (T | null
) type, but then I do not see the point of using <T = void>
, because I will need to falsy-check my result
every time I use it.
My ideal answer is one that lets me create a non-generic ServiceResponse
where I do not (and cannot) define a result
, and create a generic ServiceResponse<TThing>
where I MUST define result
.
So this is 2 questions:
EDIT: more info for @jcalz. doesn't work, but is minimum code. One question: how to make this work WITHOUT defining result as optional?
export interface ServiceResult<T = void> {
result: T;
}
const genericResult: ServiceResult<string> = { result: "rad" }
const nonGenericResult: ServiceResult = { result: void } /**** doesn't work ****/
function test(x: ServiceResult): void {console.log(x)}
test(genericResult); //**** doesn't work
test(nonGenericResult);
// jose ramirez's answer gets a little closer, but still not what I'm looking for because I still have to assign {} to result.
export interface ServiceResult2<T = {}> {
result: T;
}
const genericResult2: ServiceResult2<string> = { result: "rad" }
const nonGenericResult2: ServiceResult2 = { result: {} /* works but sucks */ }
function test2(x: ServiceResult2): void { console.log(x) }
test2(genericResult2);
test2(nonGenericResult2);
Posting my own answer because people are already voting to close, and that's just not useful.
The answer is: it doesn't appear possible. I can either make result optional:
export interface ServiceResult<T> { result? T; }
... but that's not what I want, because I want the generic version to be guaranteed to have a T and the non-generic to never have a T.
The other option is to give the generic and non-generic classes different names, and inherit one from the other.
export interface ServiceResult1 {};
export interface ServiceResult2<T> extends ServiceResult1 { result: T };
Neither is optimal, so that answers both my questions.