Reputation: 1459
function getColors(
url: string,
config: Config
): Promise<Result>;
}
type Config = {
dominant?: boolean;
average?: boolean;
};
type Result = {
dominant?: string;
average?: string;
};
How can I say if dominant
was passed as true
to the config object e.g. getColors(url, {
dominant: true})
then it is not optional in Result
.
async () => {
let example : string;
const colors = await getColors(url, {dominant: true});
example = colors.dominant;
// ^^^^^^ Type 'string | undefined' is not assignable to type 'string'.
// Type 'undefined' is not assignable to type 'string'
};
Upvotes: 3
Views: 482
Reputation: 20162
We can do that by conditional types. Consider:
type Config = {
dominant?: boolean;
average?: boolean;
};
type Result = {
dominant?: string;
average?: string;
};
declare function getColors<C extends Config>(
url: string,
config: C
): Promise<Result & (C['dominant'] extends true ? {dominant: string} : {})>;
async function f() {
const colors = await getColors('url', { dominant: true })
colors.dominant // is non-optional string
}
The core thing is to have Config
as generic in getColors
and append conditional behavior in the return type: Result & (C['dominant'] extends true ? {dominant: string} : {})
. What we do here is - if dominant
is true in config, we intersect with our type object having dominant
required, if dominant
is false we intersect with {}
which is neutral element, so we get Result
back.
Upvotes: 4
Reputation: 51162
You can provide two signatures by overloading the function:
interface Config { average?: boolean, dominant?: boolean }
interface ConfigDominant extends Config { dominant: true }
interface Result { average?: string, dominant?: string }
interface ResultDominant extends Result { dominant: string }
// more specific signature must go first
function getColors(url: string, config: ConfigDominant): Promise<ResultDominant>;
// less specific signature
function getColors(url: string, config: Config): Promise<Result>;
// implementation
function getColors(url: string, config: Config): Promise<Result> {
throw new Error('not implemented');
}
async (url: string) => {
const colors = await getColors(url, {dominant: true});
// no error here
let example: string = colors.dominant;
};
Upvotes: 2