I have something I'm trying to do but I'm not quite sure how to achieve it in typescript.
I'm working with discord.js and I'm trying to make a wrapper to convert Discord.User | Discord.PartialUser (or similar T | PartialT types) to their non-partial versions.
Something like this:
interface Partial {
partial: boolean;
fetch(): Promise<any>;
}
async function departialize<T extends Partial>(thing: T) {
if(thing.partial) {
return await thing.fetch();
} else {
return thing;
}
}
While this compiles, I would like to include more type information. I.e. with this example I would like it to return Promise<Discord.User> instead of Promise<Any>.
Both Discord.User.fetch() and Discord.PartialUser.fetch() return Promise<Discord.User>, can this be deduced in the interface or return type? In C we would write something like decltype(std::declval<T>().fetch()), not sure what to do in TS.
CodePudding user response:
Here's an overloaded function which will provide a correct return type for your input, narrowing based on the inferred value of the partial property.
Notes:
Because the
Partialutility is already declared in TypeScript, I've used the type nameIncompleteto avoid a compiler error.
unknownis more type safe thanany, but feel free to replace if you really needany.
interface Incomplete<T = unknown> {
partial: boolean;
fetch (): Promise<T>;
}
function departialize <T extends Incomplete & { partial: true }>(thing: T): ReturnType<T['fetch']>;
function departialize <T extends Incomplete & { partial: false }>(thing: T): T;
function departialize <T extends Incomplete>(thing: T): T | ReturnType<T['fetch']>;
function departialize <T extends Incomplete>(thing: T): T | ReturnType<T['fetch']> {
return thing.partial ? thing.fetch() as ReturnType<T['fetch']> : thing;
}
// Usage:
declare const input1: {
partial: boolean;
fetch (): Promise<string>;
someOtherProp: number;
};
const output1 = departialize(input1); // typeof input1 | Promise<string>
declare const input2: {
partial: true;
fetch (): Promise<string>;
someOtherProp: number;
};
const output2 = departialize(input2); // Promise<string>
declare const input3: {
partial: false;
fetch (): Promise<string>;
someOtherProp: number;
};
const output3 = departialize(input3); // typeof input3
CodePudding user response:
Figured out, here's what I'm going with in case it helps anyone else:
type PotentiallyPartial = Discord.AllowedPartial | Discord.Partialize<Discord.AllowedPartial>;
async function departialize<T extends PotentiallyPartial, R extends ReturnType<T["fetch"]>>(thing: T): Promise<R> {
if(thing.partial) {
return thing.fetch();
} else {
return thing as R;
}
};
