简体   繁体   English

具有条件可选键的对象

[英]Object with conditionally optional keys

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 eg getColors(url, { dominant: true}) then it is not optional in Result .我怎么能说如果dominant被作为true传递给配置对象,例如getColors(url, { dominant: true})那么它在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'
};

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} : {}) .核心是让ConfiggetColors通用,并在返回类型中附加条件行为: 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.我们在这里做的是 - 如果在配置中dominant为真,我们与我们的类型对象相交具有dominant需要,如果dominant为假,我们与{}相交,这是中性元素,所以我们得到Result

Playground 操场

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;
};

Playground Link 游乐场链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM